OM_uint32 gss_indicate_mechs (OM_uint32 * minor_status, gss_OID_set * mech_set ) { OM_uint32 ret; ret = gss_create_empty_oid_set(minor_status, mech_set); if (ret) return ret; ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, mech_set); if (ret) { gss_release_oid_set(NULL, mech_set); return ret; } ret = gss_add_oid_set_member(minor_status, GSS_SPNEGO_MECHANISM, mech_set); if (ret) { gss_release_oid_set(NULL, mech_set); return ret; } *minor_status = 0; return GSS_S_COMPLETE; }
static OM_uint32 spnego_supported_mechs(OM_uint32 *minor_status, gss_OID_set *mechs) { OM_uint32 ret, junk; gss_OID_set m; size_t i; ret = gss_indicate_mechs(minor_status, &m); if (ret != GSS_S_COMPLETE) return ret; ret = gss_create_empty_oid_set(minor_status, mechs); if (ret != GSS_S_COMPLETE) { gss_release_oid_set(&junk, &m); return ret; } for (i = 0; i < m->count; i++) { if (gss_oid_equal(&m->elements[i], GSS_SPNEGO_MECHANISM)) continue; ret = gss_add_oid_set_member(minor_status, &m->elements[i], mechs); if (ret) { gss_release_oid_set(&junk, &m); gss_release_oid_set(&junk, mechs); return ret; } } gss_release_oid_set(&junk, &m); return ret; }
OM_uint32 _gsskrb5_inquire_names_for_mech ( OM_uint32 * minor_status, const gss_OID mechanism, gss_OID_set * name_types ) { OM_uint32 ret; int i; *minor_status = 0; if (gss_oid_equal(mechanism, GSS_KRB5_MECHANISM) == 0 && gss_oid_equal(mechanism, GSS_C_NULL_OID) == 0) { *name_types = GSS_C_NO_OID_SET; return GSS_S_BAD_MECH; } ret = gss_create_empty_oid_set(minor_status, name_types); if (ret != GSS_S_COMPLETE) return ret; for (i = 0; name_list[i] != NULL; i++) { ret = gss_add_oid_set_member(minor_status, *(name_list[i]), name_types); if (ret != GSS_S_COMPLETE) break; } if (ret != GSS_S_COMPLETE) gss_release_oid_set(NULL, name_types); return GSS_S_COMPLETE; }
OM_uint32 ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) { gss_buffer_desc gssbuf; gss_name_t gssname; OM_uint32 status; gss_OID_set oidset; gssbuf.value = (void *) name; gssbuf.length = strlen(gssbuf.value); gss_create_empty_oid_set(&status, &oidset); gss_add_oid_set_member(&status, ctx->oid, &oidset); ctx->major = gss_import_name(&ctx->minor, &gssbuf, GSS_C_NT_USER_NAME, &gssname); if (!ctx->major) ctx->major = gss_acquire_cred(&ctx->minor, gssname, 0, oidset, GSS_C_INITIATE, &ctx->client_creds, NULL, NULL); gss_release_name(&status, &gssname); gss_release_oid_set(&status, &oidset); if (ctx->major) ssh_gssapi_error(ctx); return(ctx->major); }
/* Unprivileged */ void ssh_gssapi_supported_oids(gss_OID_set *oidset) { int i = 0; OM_uint32 min_status; int present; gss_OID_set supported; gss_create_empty_oid_set(&min_status, oidset); if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) return; while (supported_mechs[i]->name != NULL) { if (GSS_ERROR(gss_test_oid_set_member(&min_status, &supported_mechs[i]->oid, supported, &present))) present = 0; if (present) gss_add_oid_set_member(&min_status, &supported_mechs[i]->oid, oidset); i++; } gss_release_oid_set(&min_status, &supported); }
/* Privileged (called from ssh_gssapi_server_ctx) */ static OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx) { OM_uint32 status; char lname[NI_MAXHOST]; gss_OID_set oidset; gss_create_empty_oid_set(&status, &oidset); gss_add_oid_set_member(&status, ctx->oid, &oidset); if (gethostname(lname, sizeof(lname))) { gss_release_oid_set(&status, &oidset); return (-1); } if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { gss_release_oid_set(&status, &oidset); return (ctx->major); } if ((ctx->major = gss_acquire_cred(&ctx->minor, ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) ssh_gssapi_error(ctx); gss_release_oid_set(&status, &oidset); return (ctx->major); }
/* Privileged (called from ssh_gssapi_server_ctx) */ static OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx) { OM_uint32 status; char lname[NI_MAXHOST]; gss_OID_set oidset; if (options.gss_strict_acceptor) { gss_create_empty_oid_set(&status, &oidset); gss_add_oid_set_member(&status, ctx->oid, &oidset); if (gethostname(lname, MAXHOSTNAMELEN)) { gss_release_oid_set(&status, &oidset); return (-1); } if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) { gss_release_oid_set(&status, &oidset); return (ctx->major); } if ((ctx->major = gss_acquire_cred(&ctx->minor, ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) ssh_gssapi_error(ctx); gss_release_oid_set(&status, &oidset); return (ctx->major); } else { ctx->name = GSS_C_NO_NAME; ctx->creds = GSS_C_NO_CREDENTIAL; } return GSS_S_COMPLETE; }
/** * Passes back the mech set of available mechs. * We only have one for now. * * @param minor_status * @param mech_set * * @return */ OM_uint32 GSS_CALLCONV gss_indicate_mechs( OM_uint32 * minor_status, gss_OID_set * mech_set) { OM_uint32 major_status = GSS_S_COMPLETE; OM_uint32 local_minor_status; gss_OID_set_desc * set; static char * _function_name_ = "gss_indicate_mechs"; GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER; if (minor_status == NULL || mech_set == NULL) { major_status = GSS_S_FAILURE; if (minor_status != NULL) { GLOBUS_GSI_GSSAPI_OPENSSL_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid parameter"))); } goto exit; } *minor_status = (OM_uint32) GLOBUS_SUCCESS; major_status = gss_create_empty_oid_set(&local_minor_status, &set); if (GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_MECH); goto exit; } major_status = gss_add_oid_set_member( &local_minor_status, (const gss_OID) gss_mech_globus_gssapi_openssl, &set); if (GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_OID); gss_release_oid_set(&local_minor_status, &set); goto exit; } *mech_set = set; exit: GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT; return major_status; }
OM_uint32 GSSAPI_CALLCONV _gss_ntlm_inquire_cred (OM_uint32 * minor_status, const gss_cred_id_t cred_handle, gss_name_t * name, OM_uint32 * lifetime, gss_cred_usage_t * cred_usage, gss_OID_set * mechanisms ) { OM_uint32 ret, junk; *minor_status = 0; if (cred_handle == NULL) return GSS_S_NO_CRED; if (name) { ntlm_name n = calloc(1, sizeof(*n)); ntlm_cred c = (ntlm_cred)cred_handle; if (n) { n->user = strdup(c->username); n->domain = strdup(c->domain); } if (n == NULL || n->user == NULL || n->domain == NULL) { if (n) free(n->user); *minor_status = ENOMEM; return GSS_S_FAILURE; } *name = (gss_name_t)n; } if (lifetime) *lifetime = GSS_C_INDEFINITE; if (cred_usage) *cred_usage = 0; if (mechanisms) *mechanisms = GSS_C_NO_OID_SET; if (cred_handle == GSS_C_NO_CREDENTIAL) return GSS_S_NO_CRED; if (mechanisms) { ret = gss_create_empty_oid_set(minor_status, mechanisms); if (ret) goto out; ret = gss_add_oid_set_member(minor_status, GSS_NTLM_MECHANISM, mechanisms); if (ret) goto out; } return GSS_S_COMPLETE; out: gss_release_oid_set(&junk, mechanisms); return ret; }
OM_uint32 GSSAPI_CALLCONV _gss_ntlm_inquire_names_for_mech ( OM_uint32 * minor_status, const gss_OID mechanism, gss_OID_set * name_types ) { OM_uint32 ret; ret = gss_create_empty_oid_set(minor_status, name_types); if (ret != GSS_S_COMPLETE) return ret; *minor_status = 0; return GSS_S_COMPLETE; }
static OM_uint32 acceptor_approved(void *userptr, gss_name_t target_name, const gss_cred_id_t cred_handle, gss_OID mech) { OM_uint32 junk, ret; gss_OID_set oidset; if (cred_handle) { int present = 0; ret = gss_inquire_cred(&junk, cred_handle, NULL, NULL, NULL, &oidset); if (ret != GSS_S_COMPLETE) return ret; ret = gss_test_oid_set_member(&junk, mech, oidset, &present); gss_release_oid_set(&junk, &oidset); if (ret != GSS_S_COMPLETE || present == 0) return GSS_S_FAILURE; } else { gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; if (target_name == GSS_C_NO_NAME) return GSS_S_COMPLETE; gss_create_empty_oid_set(&junk, &oidset); gss_add_oid_set_member(&junk, mech, &oidset); ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset, GSS_C_ACCEPT, &cred, NULL, NULL); gss_release_oid_set(&junk, &oidset); if (ret != GSS_S_COMPLETE) return ret; gss_release_cred(&junk, &cred); } return GSS_S_COMPLETE; }
gss_OID_set mag_filter_unwanted_mechs(gss_OID_set src) { gss_const_OID unwanted_mechs[] = { &gss_mech_spnego, gss_mech_krb5_old, gss_mech_krb5_wrong, gss_mech_iakerb, GSS_C_NO_OID }; gss_OID_set dst; uint32_t maj, min; int present = 0; if (src == GSS_C_NO_OID_SET) return GSS_C_NO_OID_SET; for (int i = 0; unwanted_mechs[i] != GSS_C_NO_OID; i++) { maj = gss_test_oid_set_member(&min, discard_const(unwanted_mechs[i]), src, &present); if (present) break; } if (present) { maj = gss_create_empty_oid_set(&min, &dst); if (maj != GSS_S_COMPLETE) { return GSS_C_NO_OID_SET; } for (int i = 0; i < src->count; i++) { present = 0; for (int j = 0; unwanted_mechs[j] != GSS_C_NO_OID; j++) { if (gss_oid_equal(&src->elements[i], unwanted_mechs[j])) { present = 1; break; } } if (present) continue; maj = gss_add_oid_set_member(&min, &src->elements[i], &dst); if (maj != GSS_S_COMPLETE) { gss_release_oid_set(&min, &dst); return GSS_C_NO_OID_SET; } } return dst; } return src; }
GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL gss_inquire_names_for_mech(OM_uint32 *minor_status, const gss_OID mechanism, gss_OID_set *name_types) { OM_uint32 major_status; gssapi_mech_interface m = __gss_get_mechanism(mechanism); *minor_status = 0; *name_types = GSS_C_NO_OID_SET; if (!m) return (GSS_S_BAD_MECH); /* * If the implementation can do it, ask it for a list of * names, otherwise fake it. */ if (m->gm_inquire_names_for_mech) { return (m->gm_inquire_names_for_mech(minor_status, mechanism, name_types)); } else { major_status = gss_create_empty_oid_set(minor_status, name_types); if (major_status) return (major_status); major_status = gss_add_oid_set_member(minor_status, GSS_C_NT_HOSTBASED_SERVICE, name_types); if (major_status) { OM_uint32 junk; gss_release_oid_set(&junk, name_types); return (major_status); } major_status = gss_add_oid_set_member(minor_status, GSS_C_NT_USER_NAME, name_types); if (major_status) { OM_uint32 junk; gss_release_oid_set(&junk, name_types); return (major_status); } } return (GSS_S_COMPLETE); }
OM_uint32 gssEapIndicateMechs(OM_uint32 *minor, gss_OID_set *mechs) { OM_uint32 major; major = gss_create_empty_oid_set(minor, mechs); if (GSS_ERROR(major)) { return major; } major = gss_add_oid_set_member(minor, GSS_SAMLEC_MECHANISM, mechs); if (GSS_ERROR(major)) { return major; } *minor = 0; return major; }
OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_names_for_mech ( OM_uint32 * minor_status, const gss_OID mechanism, gss_OID_set * name_types ) { gss_OID_set mechs, names, n; OM_uint32 ret, junk; size_t i, j; *name_types = NULL; ret = spnego_supported_mechs(minor_status, &mechs); if (ret != GSS_S_COMPLETE) return ret; ret = gss_create_empty_oid_set(minor_status, &names); if (ret != GSS_S_COMPLETE) goto out; for (i = 0; i < mechs->count; i++) { ret = gss_inquire_names_for_mech(minor_status, &mechs->elements[i], &n); if (ret) continue; for (j = 0; j < n->count; j++) gss_add_oid_set_member(minor_status, &n->elements[j], &names); gss_release_oid_set(&junk, &n); } ret = GSS_S_COMPLETE; *name_types = names; out: gss_release_oid_set(&junk, &mechs); return ret; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_indicate_mechs (OM_uint32 * minor_status, gss_OID_set * mech_set ) { OM_uint32 ret, junk; ret = gss_create_empty_oid_set(minor_status, mech_set); if (ret) return ret; ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, mech_set); if (ret) { gss_release_oid_set(&junk, mech_set); return ret; } *minor_status = 0; return GSS_S_COMPLETE; }
OM_uint32 _gsskrb5_inquire_mechs_for_name ( OM_uint32 * minor_status, const gss_name_t input_name, gss_OID_set * mech_types ) { OM_uint32 ret; ret = gss_create_empty_oid_set(minor_status, mech_types); if (ret) return ret; ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, mech_types); if (ret) gss_release_oid_set(NULL, mech_types); return ret; }
OM_uint32 GSSAPI_CALLCONV _gss_spnego_inquire_mechs_for_name ( OM_uint32 * minor_status, gss_const_name_t input_name, gss_OID_set * mech_types ) { OM_uint32 ret, junk; ret = gss_create_empty_oid_set(minor_status, mech_types); if (ret) return ret; ret = gss_add_oid_set_member(minor_status, GSS_SPNEGO_MECHANISM, mech_types); if (ret) gss_release_oid_set(&junk, mech_types); return ret; }
OM_uint32 GSSAPI_CALLCONV gss_inquire_names_for_mech(OM_uint32 *minor, gss_OID mechanism, gss_OID_set *ret_name_types) { OM_uint32 major, tmpMinor; gss_OID nameTypes[] = { GSS_C_NT_USER_NAME, GSS_C_NT_HOSTBASED_SERVICE, #ifdef MECH_EAP GSS_C_NT_EXPORT_NAME, #ifdef HAVE_GSS_C_NT_COMPOSITE_EXPORT GSS_C_NT_COMPOSITE_EXPORT, #endif GSS_EAP_NT_EAP_NAME, GSS_C_NT_ANONYMOUS, #endif }; size_t i; if (!gssEapIsMechanismOid(mechanism)) { *minor = GSSEAP_WRONG_MECH; return GSS_S_BAD_MECH; } major = gss_create_empty_oid_set(minor, ret_name_types); if (GSS_ERROR(major)) goto cleanup; for (i = 0; i < sizeof(nameTypes)/sizeof(nameTypes[0]); i++) { major = gss_add_oid_set_member(minor, nameTypes[i], ret_name_types); if (GSS_ERROR(major)) goto cleanup; } cleanup: if (GSS_ERROR(major)) gss_release_oid_set(&tmpMinor, ret_name_types); return major; }
OM_uint32 _netlogon_inquire_names_for_mech ( OM_uint32 * minor_status, const gss_OID mechanism, gss_OID_set * name_types ) { OM_uint32 ret, tmp; ret = gss_create_empty_oid_set(minor_status, name_types); if (ret != GSS_S_COMPLETE) return ret; ret = gss_add_oid_set_member(minor_status, GSS_NETLOGON_NT_NETBIOS_DNS_NAME, name_types); if (ret != GSS_S_COMPLETE) { gss_release_oid_set(&tmp, name_types); return ret; } *minor_status = 0; return GSS_S_COMPLETE; }
static OM_uint32 acceptor_approved(gss_name_t target_name, gss_OID mech) { gss_cred_id_t cred = GSS_C_NO_CREDENTIAL; gss_OID_set oidset; OM_uint32 junk, ret; if (target_name == GSS_C_NO_NAME) return GSS_S_COMPLETE; gss_create_empty_oid_set(&junk, &oidset); gss_add_oid_set_member(&junk, mech, &oidset); ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset, GSS_C_ACCEPT, &cred, NULL, NULL); gss_release_oid_set(&junk, &oidset); if (ret != GSS_S_COMPLETE) return ret; gss_release_cred(&junk, &cred); return GSS_S_COMPLETE; }
OM_uint32 gss_acquire_cred(OM_uint32 *minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *time_rec) { OM_uint32 major_status; gss_OID_set mechs = desired_mechs; gss_OID_set_desc set; struct _gss_name *name = (struct _gss_name *) desired_name; gssapi_mech_interface m; struct _gss_cred *cred; struct _gss_mechanism_cred *mc; OM_uint32 min_time, cred_time; int i; _gss_load_mech(); /* * First make sure that at least one of the requested * mechanisms is one that we support. */ if (mechs) { for (i = 0; i < mechs->count; i++) { int t; gss_test_oid_set_member(minor_status, &mechs->elements[i], _gss_mech_oids, &t); if (t) break; } if (i == mechs->count) { *output_cred_handle = 0; *minor_status = 0; return (GSS_S_BAD_MECH); } } if (actual_mechs) { major_status = gss_create_empty_oid_set(minor_status, actual_mechs); if (major_status) return (major_status); } cred = malloc(sizeof(struct _gss_cred)); if (!cred) { if (actual_mechs) gss_release_oid_set(minor_status, actual_mechs); *minor_status = ENOMEM; return (GSS_S_FAILURE); } cred->gc_usage = cred_usage; SLIST_INIT(&cred->gc_mc); if (mechs == GSS_C_NO_OID_SET) mechs = _gss_mech_oids; set.count = 1; min_time = GSS_C_INDEFINITE; for (i = 0; i < mechs->count; i++) { struct _gss_mechanism_name *mn = NULL; m = __gss_get_mechanism(&mechs->elements[i]); if (!m) continue; if (desired_name != GSS_C_NO_NAME) { mn = _gss_find_mn(name, &mechs->elements[i]); if (!mn) continue; } mc = malloc(sizeof(struct _gss_mechanism_cred)); if (!mc) { continue; } SLIST_INIT(&cred->gc_mc); mc->gmc_mech = m; mc->gmc_mech_oid = &m->gm_mech_oid; /* * XXX Probably need to do something with actual_mechs. */ set.elements = &mechs->elements[i]; major_status = m->gm_acquire_cred(minor_status, (desired_name != GSS_C_NO_NAME ? mn->gmn_name : GSS_C_NO_NAME), time_req, &set, cred_usage, &mc->gmc_cred, NULL, &cred_time); if (major_status) { free(mc); continue; } if (cred_time < min_time) min_time = cred_time; if (actual_mechs) { major_status = gss_add_oid_set_member(minor_status, mc->gmc_mech_oid, actual_mechs); if (major_status) { m->gm_release_cred(minor_status, &mc->gmc_cred); free(mc); continue; } } SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link); } /* * If we didn't manage to create a single credential, return * an error. */ if (!SLIST_FIRST(&cred->gc_mc)) { free(cred); if (actual_mechs) gss_release_oid_set(minor_status, actual_mechs); *output_cred_handle = 0; *minor_status = 0; return (GSS_S_NO_CRED); } if (time_rec) *time_rec = min_time; *output_cred_handle = (gss_cred_id_t) cred; *minor_status = 0; return (GSS_S_COMPLETE); }
int main(int argc, char **argv) { gss_OID_set oidset = GSS_C_NULL_OID_SET; gss_OID mechoid = GSS_C_NO_OID; OM_uint32 maj_stat, min_stat; gss_cred_id_t cred; gss_name_t target = GSS_C_NO_NAME; int i, optidx = 0; gss_cred_usage_t cred_usage = GSS_C_BOTH; gss_OID type = GSS_C_NT_HOSTBASED_SERVICE; gss_key_value_set_desc store, *storep = GSS_C_NO_CRED_STORE; gss_key_value_element_desc elements[2]; store.count = 0; store.elements = elements; setprogname(argv[0]); if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if(version_flag){ print_version(NULL); exit(0); } argc -= optidx; argv += optidx; if (argc != 0) usage(1); if (acquire_type) { if (strcasecmp(acquire_type, "both") == 0) cred_usage = GSS_C_BOTH; else if (strcasecmp(acquire_type, "accept") == 0) cred_usage = GSS_C_ACCEPT; else if (strcasecmp(acquire_type, "initiate") == 0) cred_usage = GSS_C_INITIATE; else errx(1, "unknown type %s", acquire_type); } if (name_type) { if (strcasecmp("hostbased-service", name_type) == 0) type = GSS_C_NT_HOSTBASED_SERVICE; else if (strcasecmp("user-name", name_type) == 0) type = GSS_C_NT_USER_NAME; else errx(1, "unknown name type %s", name_type); } if (ccache) { store.elements[store.count].key = "ccache"; store.elements[store.count].value = ccache; store.count++; } if (client_keytab) { store.elements[store.count].key = "client_keytab"; store.elements[store.count].value = client_keytab; store.count++; } if (store.count) storep = &store; if (kerberos_flag) { mechoid = GSS_KRB5_MECHANISM; maj_stat = gss_create_empty_oid_set(&min_stat, &oidset); if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_create_empty_oid_set: %s", gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); maj_stat = gss_add_oid_set_member(&min_stat, GSS_KRB5_MECHANISM, &oidset); if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_add_oid_set_member: %s", gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); } if (target_name) { gss_buffer_desc name; name.value = target_name; name.length = strlen(target_name); maj_stat = gss_import_name(&min_stat, &name, GSS_C_NT_HOSTBASED_SERVICE, &target); if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_import_name: %s", gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); } for (i = 0; i < num_loops; i++) { cred = acquire_cred_service(acquire_name, type, oidset, cred_usage, storep); if (enctype) { int32_t enctypelist = enctype; maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, cred, 1, &enctypelist); if (maj_stat) errx(1, "gss_krb5_set_allowable_enctypes: %s", gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); } if (target) { gss_ctx_id_t context = GSS_C_NO_CONTEXT; gss_buffer_desc out; out.length = 0; out.value = NULL; maj_stat = gss_init_sec_context(&min_stat, cred, &context, target, mechoid, GSS_C_MUTUAL_FLAG, 0, NULL, GSS_C_NO_BUFFER, NULL, &out, NULL, NULL); if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) errx(1, "init_sec_context failed: %s", gssapi_err(maj_stat, min_stat, GSS_C_NO_OID)); gss_release_buffer(&min_stat, &out); gss_delete_sec_context(&min_stat, &context, NULL); } gss_release_cred(&min_stat, &cred); } return 0; }
/** * @brief Set Security Context Option * @ingroup globus_gsi_gssapi_extensions * @details * GSSAPI routine to initiate the sending of a security context * See: <draft-ietf-cat-gssv2-cbind-04.txt> * * @param minor_status * @param context_handle * @param option * @param value * * @return */ OM_uint32 GSS_CALLCONV gss_set_sec_context_option( OM_uint32 * minor_status, gss_ctx_id_t * context_handle, const gss_OID option, const gss_buffer_t value) { gss_ctx_id_desc * context = NULL; OM_uint32 major_status = GSS_S_COMPLETE; OM_uint32 local_minor_status; globus_result_t local_result = GLOBUS_SUCCESS; int index; GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER; if(minor_status == NULL) { major_status = GSS_S_FAILURE; goto exit; } *minor_status = (OM_uint32) GLOBUS_SUCCESS; if(context_handle == NULL) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid context_handle passed to function - cannot be NULL"))); major_status = GSS_S_FAILURE; goto exit; } context = *context_handle; if(option == GSS_C_NO_OID) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid option passed to function with value: GSS_C_NO_OID"))); major_status = GSS_S_FAILURE; goto exit; } if (*context_handle == GSS_C_NO_CONTEXT) { /* for now just malloc and zero the context */ context = (gss_ctx_id_desc *) malloc(sizeof(gss_ctx_id_desc)); if (context == NULL) { GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status); major_status = GSS_S_FAILURE; goto exit; } *context_handle = context; memset(context, 0, sizeof(gss_ctx_id_desc)); context->ctx_flags = 0; major_status = gss_create_empty_oid_set( &local_minor_status, (gss_OID_set *) &context->extension_oids); /* initialize the callback_data in the context. This needs * to be done so the verify_callback func can be set later. */ local_result = globus_gsi_callback_data_init( &context->callback_data); if(local_result != GLOBUS_SUCCESS) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT, (_GGSL("The callback data in the context " "could not be initialized."))); major_status = GSS_S_FAILURE; goto exit; } } else if(context->ctx_flags & GSS_I_CTX_INITIALIZED) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT, (_GGSL("The context has already been initialized! %s should be " "called on a context before initialization"), __func__)); major_status = GSS_S_FAILURE; goto exit; } if(g_OID_equal(option, GSS_DISALLOW_ENCRYPTION)) { context->ctx_flags |= GSS_I_DISALLOW_ENCRYPTION; } else if(g_OID_equal(option, GSS_PROTECTION_FAIL_ON_CONTEXT_EXPIRATION)) { context->ctx_flags |= GSS_I_PROTECTION_FAIL_ON_CONTEXT_EXPIRATION; } else if(g_OID_equal(option, GSS_APPLICATION_WILL_HANDLE_EXTENSIONS)) { if(value == GSS_C_NO_BUFFER) { GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid buffer passed to function"))); major_status = GSS_S_FAILURE; goto exit; } for(index = 0; index < ((gss_OID_set_desc *) value->value)->count; index++) { major_status = gss_add_oid_set_member( &local_minor_status, (gss_OID) &((gss_OID_set_desc *) value->value)->elements[index], (gss_OID_set *) &context->extension_oids); if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_OID); goto exit; } } local_result = globus_gsi_callback_set_extension_cb( context->callback_data, globus_i_gsi_gss_verify_extensions_callback); if(local_result != GLOBUS_SUCCESS) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_result, GLOBUS_GSI_GSSAPI_ERROR_WITH_CALLBACK_DATA); major_status = GSS_S_FAILURE; goto exit; } /* if the extension_oids are set, * then we set them in the callback data */ local_result = globus_gsi_callback_set_extension_oids( context->callback_data, (void *) context->extension_oids); if(local_result != GLOBUS_SUCCESS) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_result, GLOBUS_GSI_GSSAPI_ERROR_WITH_CALLBACK_DATA); major_status = GSS_S_FAILURE; goto exit; } context->ctx_flags |= GSS_I_APPLICATION_WILL_HANDLE_EXTENSIONS; } else { /* unknown option */ GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_UNKNOWN_OPTION, (NULL)); major_status = GSS_S_FAILURE; goto exit; } *context_handle = context; exit: GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT; return major_status; }
int main(int argc, char **argv) { int i, s, done, print_body, gssapi_done, gssapi_started, optidx = 0; const char *host, *page; struct http_req req; char *headers[99]; /* XXX */ int num_headers; krb5_storage *sp; gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT; gss_name_t server = GSS_C_NO_NAME; gss_OID mech_oid, cred_mech_oid; OM_uint32 flags; OM_uint32 maj_stat, min_stat; setprogname(argv[0]); if(getarg(http_args, num_http_args, argc, argv, &optidx)) usage(1); if (help_flag) usage (0); if(version_flag) { print_version(NULL); exit(0); } argc -= optidx; argv += optidx; mech_oid = select_mech(mech); if (cred_mech_str) cred_mech_oid = select_mech(cred_mech_str); else cred_mech_oid = mech_oid; if (argc != 1 && argc != 2) errx(1, "usage: %s host [page]", getprogname()); host = argv[0]; if (argc == 2) page = argv[1]; else page = "/"; flags = 0; if (delegate_flag) flags |= GSS_C_DELEG_FLAG; if (policy_flag) flags |= GSS_C_DELEG_POLICY_FLAG; if (mutual_flag) flags |= GSS_C_MUTUAL_FLAG; done = 0; num_headers = 0; gssapi_done = 0; gssapi_started = 0; if (client_str) { gss_buffer_desc name_buffer; gss_name_t name; gss_OID_set mechset = GSS_C_NO_OID_SET; name_buffer.value = client_str; name_buffer.length = strlen(client_str); maj_stat = gss_import_name(&min_stat, &name_buffer, GSS_C_NT_USER_NAME, &name); if (maj_stat) errx(1, "failed to import name"); if (cred_mech_oid) { gss_create_empty_oid_set(&min_stat, &mechset); gss_add_oid_set_member(&min_stat, cred_mech_oid, &mechset); } maj_stat = gss_acquire_cred(&min_stat, name, GSS_C_INDEFINITE, mechset, GSS_C_INITIATE, &client_cred, NULL, NULL); gss_release_name(&min_stat, &name); gss_release_oid_set(&min_stat, &mechset); if (maj_stat) errx(1, "failed to find cred of name %s", client_str); } { gss_buffer_desc name_token; char *name; asprintf(&name, "%s@%s", gss_service, host); name_token.length = strlen(name); name_token.value = name; maj_stat = gss_import_name(&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, &server); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_inport_name: %s", name); free(name); } s = do_connect(host, port_str); if (s < 0) errx(1, "connection failed"); sp = krb5_storage_from_fd(s); if (sp == NULL) errx(1, "krb5_storage_from_fd"); do { print_body = 0; http_query(sp, host, page, headers, num_headers, &req); for (i = 0 ; i < num_headers; i++) free(headers[i]); num_headers = 0; if (strstr(req.response, " 200 ") != NULL) { print_body = 1; done = 1; } else if (strstr(req.response, " 401 ") != NULL) { if (http_find_header(&req, "WWW-Authenticate:") == NULL) errx(1, "Got %s but missed `WWW-Authenticate'", req.response); } if (!gssapi_done) { const char *h = http_find_header(&req, "WWW-Authenticate:"); if (h == NULL) errx(1, "Got %s but missed `WWW-Authenticate'", req.response); if (strncasecmp(h, "Negotiate", 9) == 0) { gss_buffer_desc input_token, output_token; if (verbose_flag) printf("Negotiate found\n"); i = 9; while(h[i] && isspace((unsigned char)h[i])) i++; if (h[i] != '\0') { size_t len = strlen(&h[i]); int slen; if (len == 0) errx(1, "invalid Negotiate token"); input_token.value = emalloc(len); slen = base64_decode(&h[i], input_token.value); if (slen < 0) errx(1, "invalid base64 Negotiate token %s", &h[i]); input_token.length = slen; } else { if (gssapi_started) errx(1, "Negotiate already started"); gssapi_started = 1; input_token.length = 0; input_token.value = NULL; } if (strstr(req.response, " 200 ") != NULL) sleep(1); maj_stat = gss_init_sec_context(&min_stat, client_cred, &context_hdl, server, mech_oid, flags, 0, GSS_C_NO_CHANNEL_BINDINGS, &input_token, NULL, &output_token, NULL, NULL); if (maj_stat == GSS_S_CONTINUE_NEEDED) { } else if (maj_stat == GSS_S_COMPLETE) { gss_name_t targ_name, src_name; gss_buffer_desc name_buffer; gss_OID mech_type; gssapi_done = 1; maj_stat = gss_inquire_context(&min_stat, context_hdl, &src_name, &targ_name, NULL, &mech_type, NULL, NULL, NULL); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_inquire_context"); printf("Negotiate done: %s\n", mech); maj_stat = gss_display_name(&min_stat, src_name, &name_buffer, NULL); if (GSS_ERROR(maj_stat)) gss_print_errors(min_stat); else printf("Source: %.*s\n", (int)name_buffer.length, (char *)name_buffer.value); gss_release_buffer(&min_stat, &name_buffer); maj_stat = gss_display_name(&min_stat, targ_name, &name_buffer, NULL); if (GSS_ERROR(maj_stat)) gss_print_errors(min_stat); else printf("Target: %.*s\n", (int)name_buffer.length, (char *)name_buffer.value); gss_release_name(&min_stat, &targ_name); gss_release_buffer(&min_stat, &name_buffer); } else { gss_err (1, min_stat, "gss_init_sec_context"); } if (output_token.length) { char *neg_token; base64_encode(output_token.value, (int)output_token.length, &neg_token); asprintf(&headers[0], "Authorization: Negotiate %s", neg_token); num_headers = 1; free(neg_token); gss_release_buffer(&min_stat, &output_token); } if (input_token.length) free(input_token.value); } else done = 1; } else done = 1; if (print_body || verbose_flag) printf("%.*s\n", (int)req.body_size, (char *)req.body); http_req_free(&req); } while (!done); if (gssapi_done == 0) errx(1, "gssapi not done but http dance done"); krb5_storage_free(sp); close(s); return 0; }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext (OM_uint32 * minor_status, gss_const_name_t desired_name, gss_const_OID credential_type, const void *credential_data, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle ) { krb5_context context; gsskrb5_cred handle; OM_uint32 ret; cred_usage &= GSS_C_OPTION_MASK; if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } GSSAPI_KRB5_INIT(&context); *output_cred_handle = NULL; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } HEIMDAL_MUTEX_init(&handle->cred_id_mutex); if (desired_name != GSS_C_NO_NAME) { ret = _gsskrb5_canon_name(minor_status, context, 1, NULL, desired_name, &handle->principal); if (ret) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); return ret; } } if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { ret = acquire_initiator_cred(minor_status, context, credential_type, credential_data, desired_name, time_req, desired_mech, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { ret = acquire_acceptor_cred(minor_status, context, credential_type, credential_data, desired_name, time_req, desired_mech, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret != GSS_S_COMPLETE) { if (handle->mechanisms != NULL) gss_release_oid_set(NULL, &handle->mechanisms); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } handle->usage = cred_usage; *minor_status = 0; *output_cred_handle = (gss_cred_id_t)handle; return (GSS_S_COMPLETE); }
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext (OM_uint32 * minor_status, gss_const_name_t desired_name, gss_const_OID credential_type, const void *credential_data, OM_uint32 time_req, gss_const_OID desired_mech, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle ) { krb5_context context; gsskrb5_cred handle; OM_uint32 ret; cred_usage &= GSS_C_OPTION_MASK; if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } GSSAPI_KRB5_INIT(&context); *output_cred_handle = GSS_C_NO_CREDENTIAL; handle = calloc(1, sizeof(*handle)); if (handle == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } HEIMDAL_MUTEX_init(&handle->cred_id_mutex); if (desired_name != GSS_C_NO_NAME) { ret = _gsskrb5_canon_name(minor_status, context, desired_name, &handle->principal); if (ret) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); return ret; } } if (credential_type != GSS_C_NO_OID && gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) { /* Acquire a cred with a password */ gss_const_buffer_t pwbuf = credential_data; char *pw; if (pwbuf == NULL) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = KRB5_NOCREDS_SUPPLIED; /* see below */ return GSS_S_CALL_INACCESSIBLE_READ; } /* NUL-terminate the password, if it wasn't already */ pw = strndup(pwbuf->value, pwbuf->length); if (pw == NULL) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = krb5_enomem(context); return GSS_S_CALL_INACCESSIBLE_READ; } ret = acquire_cred_with_password(minor_status, context, pw, time_req, desired_mech, cred_usage, handle); free(pw); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } else if (credential_type != GSS_C_NO_OID) { /* * _gss_acquire_cred_ext() called with something other than a password. * * Not supported. * * _gss_acquire_cred_ext() is not a supported public interface, so * we don't have to try too hard as to minor status codes here. */ HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = ENOTSUP; return GSS_S_FAILURE; } else { /* * Acquire a credential from the background credential store (ccache, * keytab). */ if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { ret = acquire_initiator_cred(minor_status, context, time_req, desired_mech, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { ret = acquire_acceptor_cred(minor_status, context, time_req, desired_mech, cred_usage, handle); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } } } ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret != GSS_S_COMPLETE) { if (handle->mechanisms != NULL) gss_release_oid_set(NULL, &handle->mechanisms); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(context, handle->principal); free(handle); return (ret); } handle->usage = cred_usage; *minor_status = 0; *output_cred_handle = (gss_cred_id_t)handle; return (GSS_S_COMPLETE); }
OM_uint32 gss_acquire_cred(OM_uint32 *minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *time_rec) { OM_uint32 major_status; struct acquire_cred_res res; struct acquire_cred_args args; enum clnt_stat stat; gss_cred_id_t cred; int i; CLIENT *cl; *minor_status = 0; cl = kgss_gssd_client(); if (cl == NULL) return (GSS_S_FAILURE); args.uid = curthread->td_ucred->cr_uid; if (desired_name) args.desired_name = desired_name->handle; else args.desired_name = 0; args.time_req = time_req; args.desired_mechs = desired_mechs; args.cred_usage = cred_usage; bzero(&res, sizeof(res)); stat = gssd_acquire_cred_1(&args, &res, cl); CLNT_RELEASE(cl); if (stat != RPC_SUCCESS) { *minor_status = stat; return (GSS_S_FAILURE); } if (res.major_status != GSS_S_COMPLETE) { *minor_status = res.minor_status; return (res.major_status); } cred = malloc(sizeof(struct _gss_cred_id_t), M_GSSAPI, M_WAITOK); cred->handle = res.output_cred; *output_cred_handle = cred; if (actual_mechs) { major_status = gss_create_empty_oid_set(minor_status, actual_mechs); if (major_status) return (major_status); for (i = 0; i < res.actual_mechs->count; i++) { major_status = gss_add_oid_set_member(minor_status, &res.actual_mechs->elements[i], actual_mechs); if (major_status) return (major_status); } } if (time_rec) *time_rec = res.time_rec; xdr_free((xdrproc_t) xdr_acquire_cred_res, &res); return (GSS_S_COMPLETE); }
OM_uint32 _gsskrb5_krb5_import_cred(OM_uint32 *minor_status, krb5_ccache id, krb5_principal keytab_principal, krb5_keytab keytab, gss_cred_id_t *cred) { krb5_context context; krb5_error_code kret; gsskrb5_cred handle; OM_uint32 ret; *cred = NULL; GSSAPI_KRB5_INIT (&context); handle = calloc(1, sizeof(*handle)); if (handle == NULL) { _gsskrb5_clear_status (); *minor_status = ENOMEM; return (GSS_S_FAILURE); } HEIMDAL_MUTEX_init(&handle->cred_id_mutex); handle->usage = 0; if (id) { char *str; handle->usage |= GSS_C_INITIATE; kret = krb5_cc_get_principal(context, id, &handle->principal); if (kret) { free(handle); *minor_status = kret; return GSS_S_FAILURE; } if (keytab_principal) { krb5_boolean match; match = krb5_principal_compare(context, handle->principal, keytab_principal); if (match == FALSE) { krb5_free_principal(context, handle->principal); free(handle); _gsskrb5_clear_status (); *minor_status = EINVAL; return GSS_S_FAILURE; } } ret = __gsskrb5_ccache_lifetime(minor_status, context, id, handle->principal, &handle->lifetime); if (ret != GSS_S_COMPLETE) { krb5_free_principal(context, handle->principal); free(handle); return ret; } kret = krb5_cc_get_full_name(context, id, &str); if (kret) goto out; kret = krb5_cc_resolve(context, str, &handle->ccache); free(str); if (kret) goto out; } if (keytab) { char *str; handle->usage |= GSS_C_ACCEPT; if (keytab_principal && handle->principal == NULL) { kret = krb5_copy_principal(context, keytab_principal, &handle->principal); if (kret) goto out; } kret = krb5_kt_get_full_name(context, keytab, &str); if (kret) goto out; kret = krb5_kt_resolve(context, str, &handle->keytab); free(str); if (kret) goto out; } if (id || keytab) { ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret != GSS_S_COMPLETE) { kret = *minor_status; goto out; } } *minor_status = 0; *cred = (gss_cred_id_t)handle; return GSS_S_COMPLETE; out: gss_release_oid_set(minor_status, &handle->mechanisms); if (handle->ccache) krb5_cc_close(context, handle->ccache); if (handle->keytab) krb5_kt_close(context, handle->keytab); if (handle->principal) krb5_free_principal(context, handle->principal); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); *minor_status = kret; return GSS_S_FAILURE; }
OM_uint32 gss_acquire_cred (OM_uint32 * minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t * output_cred_handle, gss_OID_set * actual_mechs, OM_uint32 * time_rec ) { gss_cred_id_t handle; OM_uint32 ret; if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { *minor_status = GSS_KRB5_S_G_BAD_USAGE; return GSS_S_FAILURE; } GSSAPI_KRB5_INIT (); *output_cred_handle = NULL; if (time_rec) *time_rec = 0; if (actual_mechs) *actual_mechs = GSS_C_NO_OID_SET; if (desired_mechs) { int present = 0; ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM, desired_mechs, &present); if (ret) return ret; if (!present) { *minor_status = 0; return GSS_S_BAD_MECH; } } handle = (gss_cred_id_t)malloc(sizeof(*handle)); if (handle == GSS_C_NO_CREDENTIAL) { *minor_status = ENOMEM; return (GSS_S_FAILURE); } memset(handle, 0, sizeof (*handle)); HEIMDAL_MUTEX_init(&handle->cred_id_mutex); if (desired_name != GSS_C_NO_NAME) { ret = gss_duplicate_name(minor_status, desired_name, &handle->principal); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); free(handle); return (ret); } } if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { ret = acquire_initiator_cred(minor_status, desired_name, time_req, desired_mechs, cred_usage, handle, actual_mechs, time_rec); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(gssapi_krb5_context, handle->principal); free(handle); return (ret); } } if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { ret = acquire_acceptor_cred(minor_status, desired_name, time_req, desired_mechs, cred_usage, handle, actual_mechs, time_rec); if (ret != GSS_S_COMPLETE) { HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(gssapi_krb5_context, handle->principal); free(handle); return (ret); } } ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, &handle->mechanisms); if (ret == GSS_S_COMPLETE) ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL, actual_mechs); if (ret != GSS_S_COMPLETE) { if (handle->mechanisms != NULL) gss_release_oid_set(NULL, &handle->mechanisms); HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); krb5_free_principal(gssapi_krb5_context, handle->principal); free(handle); return (ret); } *minor_status = 0; if (time_rec) { ret = gssapi_lifetime_left(minor_status, handle->lifetime, time_rec); if (ret) return ret; } handle->usage = cred_usage; *output_cred_handle = handle; return (GSS_S_COMPLETE); }