int listMechanisms(int argc, char* argv[]) { OM_uint32 major, minor; gss_OID_set mechanisms; int index,i; gss_OID currElem = NULL; printf("\tListing available mechanisms\n"); major = gss_indicate_mechs(&minor, &mechanisms); checkError(major, minor, "gss_indicate_mechs"); printf("\tFound %zu elements:\n", mechanisms->count); for(index = 0; index < mechanisms->count; index++) { currElem = &(mechanisms->elements[index]); printf("\t{ %d,", currElem->length); for(i = 0; i < currElem->length; i++) printf("\\x%x", ((char *)currElem->elements)[i]); printf("}\n"); printOid(currElem); } if (major != GSS_S_COMPLETE) { fprintf(stderr, "failed to get the mechanisms "); return 1; } printf("\tfreeing the oidset..\n"); major = gss_release_oid_set(&minor, &mechanisms); checkError(major, minor, "gss_release_oid_set"); return 0; }
/* 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); }
static void *mag_create_server_config(apr_pool_t *p, server_rec *s) { struct mag_server_config *scfg; uint32_t maj, min; apr_status_t rc; scfg = apr_pcalloc(p, sizeof(struct mag_server_config)); maj = gss_indicate_mechs(&min, &scfg->default_mechs); if (maj != GSS_S_COMPLETE) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "gss_indicate_mechs() failed"); } else { /* Register the set in pool */ apr_pool_cleanup_register(p, (void *)scfg->default_mechs, mag_oid_set_destroy, apr_pool_cleanup_null); } rc = SEAL_KEY_CREATE(p, &scfg->mag_skey, NULL); if (rc != OK) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Failed to generate random sealing key!"); } return scfg; }
int supported_mechanisms(void *argptr, int argc, char **argv) { OM_uint32 maj_stat, min_stat; gss_OID_set mechs; rtbl_t ct; size_t i; maj_stat = gss_indicate_mechs(&min_stat, &mechs); if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_indicate_mechs failed"); printf("Supported mechanisms:\n"); ct = rtbl_create(); if (ct == NULL) errx(1, "rtbl_create"); rtbl_set_separator(ct, " "); rtbl_add_column(ct, COL_OID, 0); rtbl_add_column(ct, COL_NAME, 0); rtbl_add_column(ct, COL_DESC, 0); rtbl_add_column(ct, COL_SASL, 0); for (i = 0; i < mechs->count; i++) { gss_buffer_desc str, sasl_name, mech_name, mech_desc; maj_stat = gss_oid_to_str(&min_stat, &mechs->elements[i], &str); if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_oid_to_str failed"); rtbl_add_column_entryv(ct, COL_OID, "%.*s", (int)str.length, (char *)str.value); gss_release_buffer(&min_stat, &str); (void)gss_inquire_saslname_for_mech(&min_stat, &mechs->elements[i], &sasl_name, &mech_name, &mech_desc); rtbl_add_column_entryv(ct, COL_NAME, "%.*s", (int)mech_name.length, (char *)mech_name.value); rtbl_add_column_entryv(ct, COL_DESC, "%.*s", (int)mech_desc.length, (char *)mech_desc.value); rtbl_add_column_entryv(ct, COL_SASL, "%.*s", (int)sasl_name.length, (char *)sasl_name.value); gss_release_buffer(&min_stat, &mech_name); gss_release_buffer(&min_stat, &mech_desc); gss_release_buffer(&min_stat, &sasl_name); } gss_release_oid_set(&min_stat, &mechs); rtbl_format(ct, stdout); rtbl_destroy(ct); return 0; }
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; }
/** * Initialize a previously allocated error of type * GLOBUS_ERROR_TYPE_GSSAPI * @ingroup globus_gssapi_error_object * * @param error * The previously allocated error object. * @param base_source * Pointer to the originating module. * @param base_cause * The error object causing the error. If this is the original * error this paramater may be NULL. * @param major_status * The GSSAPI major status * @param minor_status * The GSSAPI minor status * @return * The resulting error object. You may have to call * globus_error_put() on this object before passing it on. */ globus_object_t * globus_error_initialize_gssapi_error( globus_object_t * error, globus_module_descriptor_t * base_source, globus_object_t * base_cause, const OM_uint32 major_status, const OM_uint32 minor_status) { globus_l_gssapi_error_data_t * instance_data; globus_object_t * minor_obj; gss_OID_set actual_mechs; OM_uint32 local_minor_status; extern gss_OID gss_mech_globus_gssapi_openssl; instance_data = (globus_l_gssapi_error_data_t *) malloc(sizeof(globus_l_gssapi_error_data_t)); instance_data->major_status = major_status; instance_data->minor_status = minor_status; instance_data->is_globus_gsi = GLOBUS_FALSE; if(gss_indicate_mechs( &local_minor_status, &actual_mechs) == GSS_S_COMPLETE) { int boolean; if(gss_test_oid_set_member( &local_minor_status, gss_mech_globus_gssapi_openssl, actual_mechs, &boolean) == GSS_S_COMPLETE && boolean) { instance_data->is_globus_gsi = GLOBUS_TRUE; } gss_release_oid_set(&local_minor_status, &actual_mechs); } if(instance_data->is_globus_gsi) { minor_obj = globus_error_get((globus_result_t) minor_status); if(!base_cause) { base_cause = minor_obj; } else if(minor_obj) { base_cause = globus_error_initialize_base( minor_obj, globus_error_get_source(base_cause), base_cause); } } globus_object_set_local_instance_data(error, instance_data); return globus_error_initialize_base(error, base_source, base_cause); }/* globus_error_initialize_gssapi_error() */
char * ssh_gssapi_client_mechanisms(const char *host) { gss_OID_set gss_supported; OM_uint32 min_status; gss_indicate_mechs(&min_status, &gss_supported); return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, host)); }
char * ssh_gssapi_client_mechanisms(const char *host, const char *client) { gss_OID_set gss_supported; OM_uint32 min_status; if (GSS_ERROR(gss_indicate_mechs(&min_status, &gss_supported))) return NULL; return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism, host, client)); }
static int negotiate_init_context( http_auth_negotiate_context *ctx, const gitno_connection_data *connection_data) { OM_uint32 status_major, status_minor; gss_OID item, *oid; gss_OID_set mechanism_list; size_t i; /* Query supported mechanisms looking for SPNEGO) */ if (GSS_ERROR(status_major = gss_indicate_mechs(&status_minor, &mechanism_list))) { negotiate_err_set(status_major, status_minor, "could not query mechanisms"); return -1; } if (mechanism_list) { for (oid = negotiate_oids; *oid; oid++) { for (i = 0; i < mechanism_list->count; i++) { item = &mechanism_list->elements[i]; if (item->length == (*oid)->length && memcmp(item->elements, (*oid)->elements, item->length) == 0) { ctx->oid = *oid; break; } } if (ctx->oid) break; } } gss_release_oid_set(&status_minor, &mechanism_list); if (!ctx->oid) { giterr_set(GITERR_NET, "Negotiate authentication is not supported"); return -1; } git_buf_puts(&ctx->target, "HTTP@"); git_buf_puts(&ctx->target, connection_data->host); if (git_buf_oom(&ctx->target)) return -1; ctx->gss_context = GSS_C_NO_CONTEXT; ctx->configured = 1; return 0; }
int supported_mechanisms(void *argptr, int argc, char **argv) { OM_uint32 maj_stat, min_stat; gss_OID_set mechs; rtbl_t ct; size_t i; maj_stat = gss_indicate_mechs(&min_stat, &mechs); if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_indicate_mechs failed"); printf("Supported mechanisms:\n"); ct = rtbl_create(); if (ct == NULL) errx(1, "rtbl_create"); rtbl_set_separator(ct, " "); rtbl_add_column(ct, COL_OID, 0); rtbl_add_column(ct, COL_NAME, 0); for (i = 0; i < mechs->count; i++) { gss_buffer_desc name; maj_stat = gss_oid_to_str(&min_stat, &mechs->elements[i], &name); if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_oid_to_str failed"); rtbl_add_column_entryv(ct, COL_OID, "%.*s", (int)name.length, (char *)name.value); gss_release_buffer(&min_stat, &name); if (gss_oid_equal(&mechs->elements[i], GSS_KRB5_MECHANISM)) rtbl_add_column_entry(ct, COL_NAME, "Kerberos 5"); else if (gss_oid_equal(&mechs->elements[i], GSS_SPNEGO_MECHANISM)) rtbl_add_column_entry(ct, COL_NAME, "SPNEGO"); else if (gss_oid_equal(&mechs->elements[i], GSS_NTLM_MECHANISM)) rtbl_add_column_entry(ct, COL_NAME, "NTLM"); } gss_release_oid_set(&min_stat, &mechs); rtbl_format(ct, stdout); rtbl_destroy(ct); return 0; }
uint32_t sapgss_indicate_mechs( uint32_t *minor_status, sapgss_OID_set *mech_set) { gss_OID_set mech_set_loc; uint32_t major_status; int ret; memset(&mech_set_loc, 0, sizeof(mech_set_loc)); major_status = gss_indicate_mechs(minor_status, &mech_set_loc); ret = gss_OID_set_loc_to_sap(mech_set_loc, mech_set); if (ret != 0) { *minor_status = ret; return GSS_S_FAILURE; } return major_status; }
int gssd_check_mechs(void) { u_int32_t maj_stat, min_stat; gss_OID_set supported_mechs = GSS_C_NO_OID_SET; int retval = -1; maj_stat = gss_indicate_mechs(&min_stat, &supported_mechs); if (maj_stat != GSS_S_COMPLETE) { printerr(0, "Unable to obtain list of supported mechanisms. " "Check that gss library is properly configured.\n"); goto out; } if (supported_mechs == GSS_C_NO_OID_SET || supported_mechs->count == 0) { printerr(0, "Unable to obtain list of supported mechanisms. " "Check that gss library is properly configured.\n"); goto out; } maj_stat = gss_release_oid_set(&min_stat, &supported_mechs); retval = 0; out: return retval; }
static RD_BOOL cssp_gss_mech_available(gss_OID mech) { int mech_found; OM_uint32 major_status, minor_status; gss_OID_set mech_set; mech_found = 0; if (mech == GSS_C_NO_OID) return True; major_status = gss_indicate_mechs(&minor_status, &mech_set); if (!mech_set) return False; if (GSS_ERROR(major_status)) { cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to get available mechs on system", major_status, minor_status); return False; } gss_test_oid_set_member(&minor_status, mech, mech_set, &mech_found); if (GSS_ERROR(major_status)) { cssp_gss_report_error(GSS_C_GSS_CODE, "Failed to match mechanism in set", major_status, minor_status); return False; } if (!mech_found) return False; return True; }
void ssh_gssapi_client_mechs(const char *server_host, gss_OID_set *mechs) { gss_OID_set indicated = GSS_C_NULL_OID_SET; gss_OID_set acquired, supported; gss_OID mech; gss_cred_id_t creds; Gssctxt *ctxt = NULL; gss_buffer_desc tok; OM_uint32 maj, min; int i; char *errmsg; if (!mechs) return; *mechs = GSS_C_NULL_OID_SET; maj = gss_indicate_mechs(&min, &indicated); if (GSS_ERROR(maj)) { debug("No GSS-API mechanisms are installed"); return; } maj = gss_create_empty_oid_set(&min, &supported); if (GSS_ERROR(maj)) { errmsg = ssh_gssapi_last_error(NULL, &maj, &min); debug("Failed to allocate resources (%s) for GSS-API", errmsg); xfree(errmsg); (void) gss_release_oid_set(&min, &indicated); return; } maj = gss_acquire_cred(&min, GSS_C_NO_NAME, 0, indicated, GSS_C_INITIATE, &creds, &acquired, NULL); if (GSS_ERROR(maj)) { errmsg = ssh_gssapi_last_error(NULL, &maj, &min); debug("Failed to acquire GSS-API credentials for any " "mechanisms (%s)", errmsg); xfree(errmsg); (void) gss_release_oid_set(&min, &indicated); (void) gss_release_oid_set(&min, &supported); return; } (void) gss_release_cred(&min, &creds); for (i = 0; i < acquired->count; i++) { mech = &acquired->elements[i]; if (ssh_gssapi_is_spnego(mech)) continue; ssh_gssapi_build_ctx(&ctxt, 1, mech); if (!ctxt) continue; /* * This is useful for mechs like Kerberos, which can * detect unknown target princs here, but not for * mechs like SPKM, which cannot detect unknown princs * until context tokens are actually exchanged. * * 'Twould be useful to have a test that could save us * the bother of trying this for SPKM and the such... */ maj = ssh_gssapi_init_ctx(ctxt, server_host, 0, NULL, &tok); if (GSS_ERROR(maj)) { errmsg = ssh_gssapi_last_error(ctxt, NULL, NULL); debug("Skipping GSS-API mechanism %s (%s)", ssh_gssapi_oid_to_name(mech), errmsg); xfree(errmsg); continue; } (void) gss_release_buffer(&min, &tok); maj = gss_add_oid_set_member(&min, mech, &supported); if (GSS_ERROR(maj)) { errmsg = ssh_gssapi_last_error(NULL, &maj, &min); debug("Failed to allocate resources (%s) for GSS-API", errmsg); xfree(errmsg); } } *mechs = supported; }
OM_uint32 GSSAPI_CALLCONV _gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status, gss_name_t target_name, OM_uint32 (*func)(void *, gss_name_t, const gss_cred_id_t, gss_OID), void *userctx, int includeMSCompatOID, const gss_cred_id_t cred_handle, MechTypeList *mechtypelist, gss_OID *preferred_mech) { gss_OID_set supported_mechs = GSS_C_NO_OID_SET; gss_OID first_mech = GSS_C_NO_OID; OM_uint32 ret, junk; int present = 0; size_t i; mechtypelist->len = 0; mechtypelist->val = NULL; if (cred_handle) { ret = gss_inquire_cred(minor_status, cred_handle, NULL, NULL, NULL, &supported_mechs); } else { ret = gss_indicate_mechs(minor_status, &supported_mechs); } if (ret != GSS_S_COMPLETE) { return ret; } if (supported_mechs->count == 0) { *minor_status = ENOENT; gss_release_oid_set(minor_status, &supported_mechs); return GSS_S_FAILURE; } /* * Propose Kerberos mech first if we have Kerberos credentials/supported mechs */ ret = gss_test_oid_set_member(&junk, GSS_KRB5_MECHANISM, supported_mechs, &present); if (ret == GSS_S_COMPLETE && present) { ret = (*func)(userctx, target_name, cred_handle, GSS_KRB5_MECHANISM); if (ret == GSS_S_COMPLETE) { ret = add_mech_type(GSS_KRB5_MECHANISM, includeMSCompatOID, mechtypelist); if (!GSS_ERROR(ret)) { if (includeMSCompatOID) first_mech = &_gss_spnego_mskrb_mechanism_oid_desc; else first_mech = GSS_KRB5_MECHANISM; } #ifdef __APPLE_PRIVATE__ (void)add_mech_type(GSS_APPL_LKDC_SUPPORTED, 0, mechtypelist); #endif } } ret = GSS_S_COMPLETE; /* * Now lets, check all other mechs */ for (i = 0; i < supported_mechs->count; i++) { OM_uint32 subret; if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM)) continue; if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM)) continue; if (gss_oid_equal(&supported_mechs->elements[i], GSS_NETLOGON_MECHANISM)) continue; subret = (*func)(userctx, target_name, cred_handle, &supported_mechs->elements[i]); if (subret != GSS_S_COMPLETE) continue; ret = add_mech_type(&supported_mechs->elements[i], includeMSCompatOID, mechtypelist); if (ret != 0) { *minor_status = ret; ret = GSS_S_FAILURE; break; } if (first_mech == GSS_C_NO_OID) first_mech = &supported_mechs->elements[i]; } if (mechtypelist->len == 0) { gss_release_oid_set(minor_status, &supported_mechs); *minor_status = 0; return GSS_S_BAD_MECH; } if (preferred_mech != NULL) { ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech); if (ret != GSS_S_COMPLETE) free_MechTypeList(mechtypelist); } gss_release_oid_set(minor_status, &supported_mechs); return ret; }
/* * For now, just a simple wrapper that avoids recursion. When * we support gss_{get,set}_neg_mechs() we will need to expose * more functionality. */ OM_uint32 GSSAPI_CALLCONV _gss_spnego_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 ) { const spnego_name dname = (const spnego_name)desired_name; gss_name_t name = GSS_C_NO_NAME; OM_uint32 ret, tmp; gss_OID_set_desc actual_desired_mechs; gss_OID_set mechs; size_t i, j; *output_cred_handle = GSS_C_NO_CREDENTIAL; if (dname) { ret = gss_import_name(minor_status, &dname->value, &dname->type, &name); if (ret) { return ret; } } ret = gss_indicate_mechs(minor_status, &mechs); if (ret != GSS_S_COMPLETE) { gss_release_name(minor_status, &name); return ret; } /* Remove ourselves from this list */ actual_desired_mechs.count = mechs->count; actual_desired_mechs.elements = malloc(actual_desired_mechs.count * sizeof(gss_OID_desc)); if (actual_desired_mechs.elements == NULL) { *minor_status = ENOMEM; ret = GSS_S_FAILURE; goto out; } for (i = 0, j = 0; i < mechs->count; i++) { if (gss_oid_equal(&mechs->elements[i], GSS_SPNEGO_MECHANISM)) continue; actual_desired_mechs.elements[j] = mechs->elements[i]; j++; } actual_desired_mechs.count = j; ret = gss_acquire_cred(minor_status, name, time_req, &actual_desired_mechs, cred_usage, output_cred_handle, actual_mechs, time_rec); if (ret != GSS_S_COMPLETE) goto out; out: gss_release_name(minor_status, &name); gss_release_oid_set(&tmp, &mechs); if (actual_desired_mechs.elements != NULL) { free(actual_desired_mechs.elements); } if (ret != GSS_S_COMPLETE) { _gss_spnego_release_cred(&tmp, output_cred_handle); } return ret; }
int main(int argc, char *argv[]) { gss_OID_set mechs; OM_uint32 major, minor; size_t i; major = gss_indicate_mechs(&minor, &mechs); if (GSS_ERROR(major)) { displayStatus("gss_indicate_mechs", major, minor); return major; } for (i = 0; i < mechs->count; i++) { gss_buffer_desc oidstr = GSS_C_EMPTY_BUFFER; gss_buffer_desc sasl_mech_name = GSS_C_EMPTY_BUFFER; gss_buffer_desc mech_name = GSS_C_EMPTY_BUFFER; gss_buffer_desc mech_description = GSS_C_EMPTY_BUFFER; gss_OID oid = GSS_C_NO_OID; major = gss_oid_to_str(&minor, &mechs->elements[i], &oidstr); if (GSS_ERROR(major)) continue; major = gss_inquire_saslname_for_mech(&minor, &mechs->elements[i], &sasl_mech_name, &mech_name, &mech_description); if (GSS_ERROR(major)) { gss_release_buffer(&minor, &oidstr); continue; } printf("-------------------------------------------------------------" "-----------------\n"); printf("OID : %.*s\n", (int)oidstr.length, (char *)oidstr.value); printf("SASL mech : %.*s\n", (int)sasl_mech_name.length, (char *)sasl_mech_name.value); printf("Mech name : %.*s\n", (int)mech_name.length, (char *)mech_name.value); printf("Mech desc : %.*s\n", (int)mech_description.length, (char *)mech_description.value); dumpMechAttrs(&minor, &mechs->elements[i]); printf("-------------------------------------------------------------" "-----------------\n"); if (GSS_ERROR(gss_inquire_mech_for_saslname(&minor, &sasl_mech_name, &oid))) { displayStatus("gss_inquire_mech_for_saslname", major, minor); } else if (oid == GSS_C_NO_OID || (oid->length != mechs->elements[i].length && memcmp(oid->elements, mechs->elements[i].elements, oid->length) != 0)) { gss_release_buffer(&minor, &oidstr); (void) gss_oid_to_str(&minor, oid, &oidstr); fprintf(stderr, "Got different OID %.*s for mechanism %.*s\n", (int)oidstr.length, (char *)oidstr.value, (int)sasl_mech_name.length, (char *)sasl_mech_name.value); } gss_release_buffer(&minor, &oidstr); gss_release_buffer(&minor, &sasl_mech_name); gss_release_buffer(&minor, &mech_name); gss_release_buffer(&minor, &mech_description); } gss_release_oid_set(&minor, &mechs); return GSS_ERROR(major) ? 1 : 0; }
/** @internal * @brief handles an user authentication using GSSAPI */ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids){ char service_name[]="host"; gss_buffer_desc name_buf; gss_name_t server_name; /* local server fqdn */ OM_uint32 maj_stat, min_stat; unsigned int i; char *ptr; gss_OID_set supported; /* oids supported by server */ gss_OID_set both_supported; /* oids supported by both client and server */ gss_OID_set selected; /* oid selected for authentication */ int present=0; int oid_count=0; struct gss_OID_desc_struct oid; int rc; if (ssh_callbacks_exists(session->server_callbacks, gssapi_select_oid_function)){ ssh_string oid_s = session->server_callbacks->gssapi_select_oid_function(session, user, n_oid, oids, session->server_callbacks->userdata); if (oid_s != NULL){ if (ssh_gssapi_init(session) == SSH_ERROR) return SSH_ERROR; session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN; rc = ssh_gssapi_send_response(session, oid_s); ssh_string_free(oid_s); return rc; } else { return ssh_auth_reply_default(session,0); } } gss_create_empty_oid_set(&min_stat, &both_supported); maj_stat = gss_indicate_mechs(&min_stat, &supported); for (i=0; i < supported->count; ++i){ ptr = ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length); SSH_LOG(SSH_LOG_DEBUG, "Supported mech %d: %s\n", i, ptr); free(ptr); } for (i=0 ; i< n_oid ; ++i){ unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]); size_t len = ssh_string_len(oids[i]); if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){ SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID"); continue; } oid.elements = &oid_s[2]; oid.length = len - 2; gss_test_oid_set_member(&min_stat,&oid,supported,&present); if(present){ gss_add_oid_set_member(&min_stat,&oid,&both_supported); oid_count++; } } gss_release_oid_set(&min_stat, &supported); if (oid_count == 0){ SSH_LOG(SSH_LOG_PROTOCOL,"GSSAPI: no OID match"); ssh_auth_reply_default(session, 0); gss_release_oid_set(&min_stat, &both_supported); return SSH_OK; } /* from now we have room for context */ if (ssh_gssapi_init(session) == SSH_ERROR) return SSH_ERROR; name_buf.value = service_name; name_buf.length = strlen(name_buf.value) + 1; maj_stat = gss_import_name(&min_stat, &name_buf, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name); if (maj_stat != GSS_S_COMPLETE) { SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat); ssh_gssapi_log_error(SSH_LOG_WARNING, "importing name", maj_stat); return -1; } maj_stat = gss_acquire_cred(&min_stat, server_name, 0, both_supported, GSS_C_ACCEPT, &session->gssapi->server_creds, &selected, NULL); gss_release_name(&min_stat, &server_name); gss_release_oid_set(&min_stat, &both_supported); if (maj_stat != GSS_S_COMPLETE) { SSH_LOG(SSH_LOG_WARNING, "error acquiring credentials %d, %d", maj_stat, min_stat); ssh_gssapi_log_error(SSH_LOG_WARNING, "acquiring creds", maj_stat); ssh_auth_reply_default(session,0); return SSH_ERROR; } SSH_LOG(SSH_LOG_PROTOCOL, "acquiring credentials %d, %d", maj_stat, min_stat); /* finding which OID from client we selected */ for (i=0 ; i< n_oid ; ++i){ unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]); size_t len = ssh_string_len(oids[i]); if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){ SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID"); continue; } oid.elements = &oid_s[2]; oid.length = len - 2; gss_test_oid_set_member(&min_stat,&oid,selected,&present); if(present){ SSH_LOG(SSH_LOG_PACKET, "Selected oid %d", i); break; } } session->gssapi->mech.length = oid.length; session->gssapi->mech.elements = malloc(oid.length); if (session->gssapi->mech.elements == NULL){ ssh_set_error_oom(session); return SSH_ERROR; } memcpy(session->gssapi->mech.elements, oid.elements, oid.length); gss_release_oid_set(&min_stat, &selected); session->gssapi->user = strdup(user); session->gssapi->service = service_name; session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN; return ssh_gssapi_send_response(session, oids[i]); }
OM_uint32 GSSAPI_CALLCONV _gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status, gss_name_t target_name, OM_uint32 (*func)(gss_name_t, gss_OID), int includeMSCompatOID, const gss_cred_id_t cred_handle, MechTypeList *mechtypelist, gss_OID *preferred_mech) { gss_OID_set supported_mechs = GSS_C_NO_OID_SET; gss_OID first_mech = GSS_C_NO_OID; OM_uint32 ret; size_t i; mechtypelist->len = 0; mechtypelist->val = NULL; if (cred_handle) { ret = gss_inquire_cred(minor_status, cred_handle, NULL, NULL, NULL, &supported_mechs); } else { ret = gss_indicate_mechs(minor_status, &supported_mechs); } if (ret != GSS_S_COMPLETE) { return ret; } if (supported_mechs->count == 0) { *minor_status = ENOENT; gss_release_oid_set(minor_status, &supported_mechs); return GSS_S_FAILURE; } ret = (*func)(target_name, GSS_KRB5_MECHANISM); if (ret == GSS_S_COMPLETE) { ret = add_mech_type(GSS_KRB5_MECHANISM, includeMSCompatOID, mechtypelist); if (!GSS_ERROR(ret)) first_mech = GSS_KRB5_MECHANISM; } ret = GSS_S_COMPLETE; for (i = 0; i < supported_mechs->count; i++) { OM_uint32 subret; if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM)) continue; if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM)) continue; subret = (*func)(target_name, &supported_mechs->elements[i]); if (subret != GSS_S_COMPLETE) continue; ret = add_mech_type(&supported_mechs->elements[i], includeMSCompatOID, mechtypelist); if (ret != 0) { *minor_status = ret; ret = GSS_S_FAILURE; break; } if (first_mech == GSS_C_NO_OID) first_mech = &supported_mechs->elements[i]; } if (mechtypelist->len == 0) { gss_release_oid_set(minor_status, &supported_mechs); *minor_status = 0; return GSS_S_BAD_MECH; } if (preferred_mech != NULL) { ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech); if (ret != GSS_S_COMPLETE) free_MechTypeList(mechtypelist); } gss_release_oid_set(minor_status, &supported_mechs); return ret; }
uint32_t NetSecurityNative_Wrap(uint32_t* minorStatus, GssCtxId* contextHandle, int32_t isEncrypt, uint8_t* inputBytes, int32_t offset, int32_t count, PAL_GssBuffer* outBuffer) { assert(minorStatus != NULL); assert(contextHandle != NULL); assert(isEncrypt == 1 || isEncrypt == 0); assert(inputBytes != NULL); assert(offset >= 0); assert(count >= 0); assert(outBuffer != NULL); // count refers to the length of the input message. That is, number of bytes of inputBytes // starting at offset that need to be wrapped. int confState; GssBuffer inputMessageBuffer = {.length = (size_t)count, .value = inputBytes + offset}; GssBuffer gssBuffer; uint32_t majorStatus = gss_wrap(minorStatus, contextHandle, isEncrypt, GSS_C_QOP_DEFAULT, &inputMessageBuffer, &confState, &gssBuffer); NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer); return majorStatus; } uint32_t NetSecurityNative_Unwrap(uint32_t* minorStatus, GssCtxId* contextHandle, uint8_t* inputBytes, int32_t offset, int32_t count, PAL_GssBuffer* outBuffer) { assert(minorStatus != NULL); assert(contextHandle != NULL); assert(inputBytes != NULL); assert(offset >= 0); assert(count >= 0); assert(outBuffer != NULL); // count refers to the length of the input message. That is, the number of bytes of inputBytes // starting at offset that need to be wrapped. GssBuffer inputMessageBuffer = {.length = (size_t)count, .value = inputBytes + offset}; GssBuffer gssBuffer = {.length = 0, .value = NULL}; uint32_t majorStatus = gss_unwrap(minorStatus, contextHandle, &inputMessageBuffer, &gssBuffer, NULL, NULL); NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer); return majorStatus; } static uint32_t NetSecurityNative_AcquireCredWithPassword(uint32_t* minorStatus, int32_t isNtlm, GssName* desiredName, char* password, uint32_t passwdLen, gss_cred_usage_t credUsage, GssCredId** outputCredHandle) { assert(minorStatus != NULL); assert(isNtlm == 1 || isNtlm == 0); assert(desiredName != NULL); assert(password != NULL); assert(outputCredHandle != NULL); assert(*outputCredHandle == NULL); #if HAVE_GSS_SPNEGO_MECHANISM (void)isNtlm; // unused // Specifying GSS_SPNEGO_MECHANISM as a desiredMech on OSX fails. gss_OID_set desiredMech = GSS_C_NO_OID_SET; #else gss_OID_desc gss_mech_OID_desc; if (isNtlm) { gss_mech_OID_desc = gss_mech_ntlm_OID_desc; } else { gss_mech_OID_desc = gss_mech_spnego_OID_desc; } gss_OID_set_desc gss_mech_OID_set_desc = {.count = 1, .elements = &gss_mech_OID_desc}; gss_OID_set desiredMech = &gss_mech_OID_set_desc; #endif GssBuffer passwordBuffer = {.length = passwdLen, .value = password}; uint32_t majorStatus = gss_acquire_cred_with_password( minorStatus, desiredName, &passwordBuffer, 0, desiredMech, credUsage, outputCredHandle, NULL, NULL); // call gss_set_cred_option with GSS_KRB5_CRED_NO_CI_FLAGS_X to support Kerberos Sign Only option from *nix client against a windows server #if HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X if (majorStatus == GSS_S_COMPLETE) { GssBuffer emptyBuffer = GSS_C_EMPTY_BUFFER; majorStatus = gss_set_cred_option(minorStatus, outputCredHandle, GSS_KRB5_CRED_NO_CI_FLAGS_X, &emptyBuffer); } #endif return majorStatus; } uint32_t NetSecurityNative_InitiateCredWithPassword(uint32_t* minorStatus, int32_t isNtlm, GssName* desiredName, char* password, uint32_t passwdLen, GssCredId** outputCredHandle) { return NetSecurityNative_AcquireCredWithPassword( minorStatus, isNtlm, desiredName, password, passwdLen, GSS_C_INITIATE, outputCredHandle); } uint32_t NetSecurityNative_IsNtlmInstalled() { #if HAVE_GSS_SPNEGO_MECHANISM gss_OID ntlmOid = GSS_NTLM_MECHANISM; #else gss_OID ntlmOid = &gss_mech_ntlm_OID_desc; #endif uint32_t majorStatus; uint32_t minorStatus; gss_OID_set mechSet; gss_OID_desc oid; uint32_t foundNtlm = 0; majorStatus = gss_indicate_mechs(&minorStatus, &mechSet); if (majorStatus == GSS_S_COMPLETE) { for (size_t i = 0; i < mechSet->count; i++) { oid = mechSet->elements[i]; if ((oid.length == ntlmOid->length) && (memcmp(oid.elements, ntlmOid->elements, oid.length) == 0)) { foundNtlm = 1; break; } } gss_release_oid_set(&minorStatus, &mechSet); } return foundNtlm; }
char * ssh_gssapi_client_mechanisms(const char *host) { gss_OID_set supported; OM_uint32 min_status; Buffer buf; int i = 0; char *mechs; char *encoded; int enclen; char digest[EVP_MAX_MD_SIZE]; char deroid[2]; const EVP_MD *evp_md = EVP_md5(); EVP_MD_CTX md; int oidpos=0; gss_indicate_mechs(&min_status,&supported); if (datafellows & SSH_BUG_GSSAPI_BER) { gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping) *((supported->count*2)+1)); } else { gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping) *(supported->count+1)); } buffer_init(&buf); for (i=0;i<supported->count;i++) { gss_enc2oid[oidpos].encoded=NULL; if (supported->elements[i].length<128 && ssh_gssapi_check_mechanism(&(supported->elements[i]),host)) { /* Earlier versions of this code interpreted the * spec incorrectly with regard to OID encoding. They * also mis-encoded the krb5 OID. The following * _temporary_ code interfaces with these broken * servers */ if (datafellows & SSH_BUG_GSSAPI_BER) { char *bodge=NULL; gss_OID_desc krb5oid={9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}; gss_OID_desc gsioid={9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"}; if (supported->elements[i].length==krb5oid.length && memcmp(supported->elements[i].elements, krb5oid.elements, krb5oid.length)==0) { bodge="Se3H81ismmOC3OE+FwYCiQ=="; } if (supported->elements[i].length==gsioid.length && memcmp(supported->elements[i].elements, gsioid.elements, gsioid.length)==0) { bodge="N3+k7/4wGxHyuP8Yxi4RhA=="; } if (bodge) { if (oidpos!=0) { buffer_put_char(&buf,','); } buffer_append(&buf, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1); buffer_append(&buf, bodge, strlen(bodge)); gss_enc2oid[oidpos].oid=&(supported->elements[i]); gss_enc2oid[oidpos].encoded=bodge; oidpos++; } } /* Add the required DER encoding octets and MD5 hash */ deroid[0]=0x06; /* Object Identifier */ deroid[1]=supported->elements[i].length; EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md,deroid,2); EVP_DigestUpdate(&md, supported->elements[i].elements, supported->elements[i].length); EVP_DigestFinal(&md, digest, NULL); /* Base64 encode it */ encoded=xmalloc(EVP_MD_size(evp_md)*2); enclen=__b64_ntop(digest, EVP_MD_size(evp_md), encoded,EVP_MD_size(evp_md)*2); if (oidpos!=0) { buffer_put_char(&buf,','); } buffer_append(&buf, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1); buffer_append(&buf, encoded, enclen); debug("Mechanism encoded as %s",encoded); gss_enc2oid[oidpos].oid=&(supported->elements[i]); gss_enc2oid[oidpos].encoded=encoded; oidpos++; } } gss_enc2oid[oidpos].oid=NULL; gss_enc2oid[oidpos].encoded=NULL; buffer_put_char(&buf,'\0'); mechs=xmalloc(buffer_len(&buf)); buffer_get(&buf,mechs,buffer_len(&buf)); buffer_free(&buf); if (strlen(mechs)==0) return(NULL); else return(mechs); }
static OM_uint32 select_mech(OM_uint32 *minor_status, MechType *mechType, int verify_p, gss_OID *mech_p) { char mechbuf[64]; size_t mech_len; gss_OID_desc oid; gss_OID oidp; gss_OID_set mechs; int i; OM_uint32 ret, junk; ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1, sizeof(mechbuf), mechType, &mech_len); if (ret) { return GSS_S_DEFECTIVE_TOKEN; } oid.length = mech_len; oid.elements = mechbuf + sizeof(mechbuf) - mech_len; if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) { return GSS_S_BAD_MECH; } *minor_status = 0; /* Translate broken MS Kebreros OID */ if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc)) oidp = &_gss_spnego_krb5_mechanism_oid_desc; else oidp = &oid; ret = gss_indicate_mechs(&junk, &mechs); if (ret) return (ret); for (i = 0; i < mechs->count; i++) if (gss_oid_equal(&mechs->elements[i], oidp)) break; if (i == mechs->count) { gss_release_oid_set(&junk, &mechs); return GSS_S_BAD_MECH; } gss_release_oid_set(&junk, &mechs); ret = gss_duplicate_oid(minor_status, &oid, /* possibly this should be oidp */ mech_p); if (verify_p) { gss_name_t name = GSS_C_NO_NAME; gss_buffer_desc namebuf; char *str = NULL, *host, hostname[MAXHOSTNAMELEN]; host = getenv("GSSAPI_SPNEGO_NAME"); if (host == NULL || issuid()) { if (gethostname(hostname, sizeof(hostname)) != 0) { *minor_status = errno; return GSS_S_FAILURE; } i = asprintf(&str, "host@%s", hostname); if (i < 0 || str == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } host = str; } namebuf.length = strlen(host); namebuf.value = host; ret = gss_import_name(minor_status, &namebuf, GSS_C_NT_HOSTBASED_SERVICE, &name); if (str) free(str); if (ret != GSS_S_COMPLETE) return ret; ret = acceptor_approved(name, *mech_p); gss_release_name(&junk, &name); } return ret; }
/** @brief returns the OIDs of the mechs that work with both * hostname and username */ static int ssh_gssapi_match(ssh_session session, char *hostname, char *username, gss_OID_set *valid_oids, int deleg){ gss_buffer_desc host_namebuf, user_namebuf; gss_name_t host_name, user_name; OM_uint32 maj_stat, min_stat; gss_OID_set supported; gss_OID oid; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL; unsigned int i; char *ptr; char hostname_buf[256]; gss_create_empty_oid_set(&min_stat, valid_oids); maj_stat = gss_indicate_mechs(&min_stat, &supported); for (i=0; i < supported->count; ++i){ ptr=ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length); SSH_LOG(SSH_LOG_DEBUG, "GSSAPI oid supported %d : %s\n",i, ptr); SAFE_FREE(ptr); } user_namebuf.value = username; user_namebuf.length = strlen(username) + 1; maj_stat = gss_import_name(&min_stat, &user_namebuf, (gss_OID) GSS_C_NT_USER_NAME, &user_name); if (maj_stat != GSS_S_COMPLETE) { SSH_LOG(SSH_LOG_DEBUG, "importing name %d, %d", maj_stat, min_stat); ssh_gssapi_log_error(SSH_LOG_DEBUG, "importing name", maj_stat); return -1; } snprintf(hostname_buf, sizeof(hostname_buf),"host@%s", hostname); host_namebuf.value = hostname_buf; host_namebuf.length = strlen(hostname_buf) + 1; maj_stat = gss_import_name(&min_stat, &host_namebuf, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &host_name); if (maj_stat != GSS_S_COMPLETE) { SSH_LOG(0, "importing name %d, %d", maj_stat, min_stat); ssh_gssapi_log_error(0, "importing name", maj_stat); return -1; } ssh_gssapi_init(session); session->gssapi->client_name = user_name; session->gssapi->client.server_name = host_name; session->gssapi->user = strdup(username); for (i=0; i<supported->count; ++i){ oid = &supported->elements[i]; maj_stat = gss_init_sec_context(&min_stat, session->gssapi->client.client_deleg_creds, &ctx, host_name, oid, GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | (deleg ? GSS_C_DELEG_FLAG : 0), 0, NULL, &input_token, NULL, &output_token, NULL, NULL); if (!GSS_ERROR(maj_stat)){ gss_OID_set tmp; if (session->gssapi->client.client_deleg_creds != GSS_C_NO_CREDENTIAL){ /* we know the oid is ok since init_sec_context worked */ gss_add_oid_set_member(&min_stat, oid, valid_oids); SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server (with forwarding)", i); } else { gss_create_empty_oid_set(&min_stat, &tmp); gss_add_oid_set_member(&min_stat, oid, &tmp); maj_stat = gss_acquire_cred(&min_stat, user_name, 0, tmp, GSS_C_INITIATE, &client_creds, NULL, NULL); gss_release_oid_set(&min_stat, &tmp); if (!GSS_ERROR(maj_stat)){ gss_release_cred(&min_stat, &client_creds); gss_add_oid_set_member(&min_stat,oid,valid_oids); SSH_LOG(SSH_LOG_PROTOCOL, "Matched oid %u for server", i); } } } gss_delete_sec_context(&min_stat,&ctx, &output_token); ctx = GSS_C_NO_CONTEXT; } return SSH_OK; }