summaryrefslogtreecommitdiffstats
path: root/src/lib/gssapi/krb5/add_cred.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/gssapi/krb5/add_cred.c')
-rw-r--r--src/lib/gssapi/krb5/add_cred.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/lib/gssapi/krb5/add_cred.c b/src/lib/gssapi/krb5/add_cred.c
new file mode 100644
index 000000000..2a6fdb47b
--- /dev/null
+++ b/src/lib/gssapi/krb5/add_cred.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "gssapiP_krb5.h"
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * $Id$
+ */
+
+/* V2 interface */
+OM_uint32
+krb5_gss_add_cred(minor_status, input_cred_handle,
+ desired_name, desired_mech, cred_usage,
+ initiator_time_req, acceptor_time_req,
+ output_cred_handle, actual_mechs,
+ initiator_time_rec, acceptor_time_rec)
+ OM_uint32 *minor_status;
+ gss_cred_id_t input_cred_handle;
+ gss_name_t desired_name;
+ gss_OID desired_mech;
+ gss_cred_usage_t cred_usage;
+ OM_uint32 initiator_time_req;
+ OM_uint32 acceptor_time_req;
+ gss_cred_id_t *output_cred_handle;
+ gss_OID_set *actual_mechs;
+ OM_uint32 *initiator_time_rec;
+ OM_uint32 *acceptor_time_rec;
+{
+ krb5_context context;
+ OM_uint32 major_status, lifetime;
+ krb5_gss_cred_id_t cred;
+ krb5_error_code code;
+
+ /* this is pretty simple, since there's not really any difference
+ between the underlying mechanisms. The main hair is in copying
+ a mechanism if requested. */
+
+ /* check if the desired_mech is bogus */
+
+ if (!g_OID_equal(desired_mech, gss_mech_krb5_v2) &&
+ !g_OID_equal(desired_mech, gss_mech_krb5) &&
+ !g_OID_equal(desired_mech, gss_mech_krb5_old)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_MECH);
+ }
+
+ /* check if the desired_mech is bogus */
+
+ if ((cred_usage != GSS_C_INITIATE) &&
+ (cred_usage != GSS_C_ACCEPT) &&
+ (cred_usage != GSS_C_BOTH)) {
+ *minor_status = (OM_uint32) G_BAD_USAGE;
+ return(GSS_S_FAILURE);
+ }
+
+ /* since the default credential includes all the mechanisms,
+ return an error for that case. */
+
+ /*SUPPRESS 29*/
+ if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
+ *minor_status = 0;
+ return(GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ /* verify the credential */
+ if (GSS_ERROR(major_status =
+ krb5_gss_validate_cred(minor_status, input_cred_handle)))
+ return(major_status);
+
+ cred = (krb5_gss_cred_id_t) input_cred_handle;
+
+ /* check if the cred_usage is equal or "less" than the passed-in cred
+ if copying */
+
+ if (!((cred->usage == cred_usage) ||
+ ((cred->usage == GSS_C_BOTH) &&
+ (output_cred_handle != NULL)))) {
+ *minor_status = (OM_uint32) G_BAD_USAGE;
+ return(GSS_S_FAILURE);
+ }
+
+ /* check that desired_mech isn't already in the credential */
+
+ if ((g_OID_equal(desired_mech, gss_mech_krb5_old) && cred->prerfc_mech) ||
+ (g_OID_equal(desired_mech, gss_mech_krb5) && cred->rfc_mech) ||
+ (g_OID_equal(desired_mech, gss_mech_krb5_v2) && cred->rfcv2_mech)) {
+ *minor_status = 0;
+ return(GSS_S_DUPLICATE_ELEMENT);
+ }
+
+ if (GSS_ERROR(kg_get_context(minor_status, &context)))
+ return(GSS_S_FAILURE);
+
+ /* verify the desired_name */
+
+ /*SUPPRESS 29*/
+ if ((desired_name != (gss_name_t) NULL) &&
+ (! kg_validate_name(desired_name))) {
+ *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+ return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
+ }
+
+ /* make sure the desired_name is the same as the existing one */
+
+ if (desired_name &&
+ !krb5_principal_compare(context, (krb5_principal) desired_name,
+ cred->princ)) {
+ *minor_status = 0;
+ return(GSS_S_BAD_NAME);
+ }
+
+ /* copy the cred if necessary */
+
+ if (output_cred_handle) {
+ /* make a copy */
+ krb5_gss_cred_id_t new_cred;
+ char *kttype, ktboth[1024];
+ char *cctype, *ccname, ccboth[1024];
+
+ if ((new_cred =
+ (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))
+ == NULL) {
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+ memset(new_cred, 0, sizeof(krb5_gss_cred_id_rec));
+
+ new_cred->usage = cred_usage;
+ new_cred->prerfc_mech = cred->prerfc_mech;
+ new_cred->rfc_mech = cred->rfc_mech;
+ new_cred->rfcv2_mech = cred->rfcv2_mech;
+ new_cred->tgt_expire = cred->tgt_expire;
+
+ if (code = krb5_copy_principal(context, cred->princ,
+ &new_cred->princ)) {
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ if (cred->keytab) {
+ kttype = krb5_kt_get_type(context, cred->keytab);
+ if ((strlen(kttype)+2) > sizeof(ktboth)) {
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ strcpy(ktboth, kttype);
+ strcat(ktboth, ":");
+
+ if (code = krb5_kt_get_name(context, cred->keytab,
+ ktboth+strlen(ktboth),
+ sizeof(ktboth)-strlen(ktboth))) {
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+
+ if (code = krb5_kt_resolve(context, ktboth, &new_cred->keytab)) {
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ new_cred->keytab = NULL;
+ }
+
+ if (cred->rcache) {
+ /* Open the replay cache for this principal. */
+ if ((code = krb5_get_server_rcache(context,
+ krb5_princ_component(context, cred->princ, 0),
+ &new_cred->rcache))) {
+ if (new_cred->keytab)
+ krb5_kt_close(context, new_cred->keytab);
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ new_cred->rcache = NULL;
+ }
+
+ if (cred->ccache) {
+ cctype = krb5_cc_get_type(context, cred->ccache);
+ ccname = krb5_cc_get_name(context, cred->ccache);
+
+ if ((strlen(cctype)+strlen(ccname)+2) > sizeof(ccboth)) {
+ if (new_cred->rcache)
+ krb5_rc_close(context, new_cred->rcache);
+ if (new_cred->keytab)
+ krb5_kt_close(context, new_cred->keytab);
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = ENOMEM;
+ return(GSS_S_FAILURE);
+ }
+
+ strcpy(ccboth, cctype);
+ strcat(ccboth, ":");
+ strcat(ccboth, ccname);
+
+ if (code = krb5_cc_resolve(context, ccboth, &new_cred->ccache)) {
+ if (new_cred->rcache)
+ krb5_rc_close(context, new_cred->rcache);
+ if (new_cred->keytab)
+ krb5_kt_close(context, new_cred->keytab);
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = code;
+ return(GSS_S_FAILURE);
+ }
+ } else {
+ new_cred->ccache = NULL;
+ }
+
+ /* intern the credential handle */
+
+ if (! kg_save_cred_id((gss_cred_id_t) new_cred)) {
+ if (new_cred->ccache)
+ krb5_cc_close(context, new_cred->ccache);
+ if (new_cred->rcache)
+ krb5_rc_close(context, new_cred->rcache);
+ if (new_cred->keytab)
+ krb5_kt_close(context, new_cred->keytab);
+ krb5_free_principal(context, new_cred->princ);
+ free(new_cred);
+
+ *minor_status = (OM_uint32) G_VALIDATE_FAILED;
+ return(GSS_S_FAILURE);
+ }
+
+ /* modify new_cred */
+
+ cred = new_cred;
+ }
+
+ /* set the flag for the new mechanism */
+
+ if (g_OID_equal(desired_mech, gss_mech_krb5_old))
+ cred->prerfc_mech = 1;
+ else if (g_OID_equal(desired_mech, gss_mech_krb5))
+ cred->rfc_mech = 1;
+ else if (g_OID_equal(desired_mech, gss_mech_krb5_v2))
+ cred->rfcv2_mech = 1;
+
+ /* set the outputs */
+
+ if (GSS_ERROR(major_status = krb5_gss_inquire_cred(minor_status, cred,
+ NULL, &lifetime,
+ NULL, actual_mechs))) {
+ OM_uint32 dummy;
+
+ if (output_cred_handle)
+ (void) krb5_gss_release_cred(&dummy, (gss_cred_id_t *) &cred);
+
+ return(major_status);
+ }
+
+ if (initiator_time_rec)
+ *initiator_time_rec = lifetime;
+ if (acceptor_time_rec)
+ *acceptor_time_rec = lifetime;
+
+ if (output_cred_handle)
+ *output_cred_handle = cred;
+
+ *minor_status = 0;
+ return(GSS_S_COMPLETE);
+}