static void check_replay_error(const char *msg, OM_uint32 major, OM_uint32 minor) { OM_uint32 tmpmin, msg_ctx = 0; const char *replay = "Request is a replay"; gss_buffer_desc m; if (major != GSS_S_FAILURE) { fprintf(stderr, "%s: expected major code GSS_S_FAILURE\n", msg); check_gsserr(msg, major, minor); exit(1); } (void)gss_display_status(&tmpmin, minor, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &m); if (m.length != strlen(replay) || memcmp(m.value, replay, m.length) != 0) { fprintf(stderr, "%s: expected replay error; got %.*s\n", msg, (int)m.length, (char *)m.value); exit(1); } (void)gss_release_buffer(&tmpmin, &m); }
static int exim_gssapi_error_defer(uschar *store_reset_point, OM_uint32 major, OM_uint32 minor, const char *format, ...) { va_list ap; uschar buffer[STRING_SPRINTF_BUFFER_SIZE]; OM_uint32 maj_stat, min_stat; OM_uint32 msgcontext = 0; gss_buffer_desc status_string; va_start(ap, format); if (!string_vformat(buffer, sizeof(buffer), format, ap)) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "exim_gssapi_error_defer expansion larger than %lu", sizeof(buffer)); va_end(ap); auth_defer_msg = NULL; do { maj_stat = gss_display_status(&min_stat, major, GSS_C_GSS_CODE, GSS_C_NO_OID, &msgcontext, &status_string); if (auth_defer_msg == NULL) { auth_defer_msg = string_copy(US status_string.value); } HDEBUG(D_auth) debug_printf("heimdal %s: %.*s\n", buffer, (int)status_string.length, CS status_string.value); gss_release_buffer(&min_stat, &status_string); } while (msgcontext != 0); if (store_reset_point) store_reset(store_reset_point); return DEFER; }
static void gsslib_display_status_1(const char *m, OM_uint32 code, int type) { OM_uint32 maj_stat, min_stat; gss_buffer_desc msg; GSSAPI_INT msg_ctx; memset((void *)&msg, 0, sizeof(msg)); msg_ctx = 0; while (1) { maj_stat = gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, &msg_ctx, &msg); snprintf(msgptr, sizeof msgbuf - strlen(msgptr), MSG_GSS_APIERRORXY_SS, m?m:"<>", (char *)msg.value?(char *)msg.value:"<>"); msgptr += strlen(msgptr); snprintf(msgptr, sizeof msgbuf - strlen(msgptr), "\n"); (void) gss_release_buffer(&min_stat, &msg); msgptr += strlen(msgptr); if (!msg_ctx) break; } }
static void cssp_gss_report_error(OM_uint32 code, char *str, OM_uint32 major_status, OM_uint32 minor_status) { OM_uint32 msgctx = 0, ms; gss_buffer_desc status_string; error("GSS error [%d:%d:%d]: %s\n", (major_status & 0xff000000) >> 24, // Calling error (major_status & 0xff0000) >> 16, // Routine error major_status & 0xffff, // Supplementary info bits str); do { ms = gss_display_status(&minor_status, major_status, code, GSS_C_NULL_OID, &msgctx, &status_string); if (ms != GSS_S_COMPLETE) continue; error(" - %s\n", status_string.value); } while (ms == GSS_S_COMPLETE && msgctx); }
static int sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min, int logonly) { OM_uint32 maj_stat, min_stat; gss_buffer_desc msg; OM_uint32 msg_ctx; int ret; char *out = NULL; size_t len, curlen = 0; const char prefix[] = "GSSAPI Error: "; len = sizeof(prefix); ret = _plug_buf_alloc(utils, &out, &curlen, 256); if(ret != SASL_OK) return SASL_OK; strcpy(out, prefix); msg_ctx = 0; while (1) { GSS_LOCK_MUTEX(utils); maj_stat = gss_display_status(&min_stat, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &msg); GSS_UNLOCK_MUTEX(utils); if(GSS_ERROR(maj_stat)) { if (logonly) { utils->log(utils->conn, SASL_LOG_FAIL, "GSSAPI Failure: (could not get major error message)"); } else { utils->seterror(utils->conn, 0, "GSSAPI Failure " "(could not get major error message)"); } utils->free(out); return SASL_OK; } len += len + msg.length; ret = _plug_buf_alloc(utils, &out, &curlen, len); if(ret != SASL_OK) { utils->free(out); return SASL_OK; } strcat(out, msg.value); GSS_LOCK_MUTEX(utils); gss_release_buffer(&min_stat, &msg); GSS_UNLOCK_MUTEX(utils); if (!msg_ctx) break; } /* Now get the minor status */ len += 2; ret = _plug_buf_alloc(utils, &out, &curlen, len); if(ret != SASL_OK) { utils->free(out); return SASL_NOMEM; } strcat(out, " ("); msg_ctx = 0; while (1) { GSS_LOCK_MUTEX(utils); maj_stat = gss_display_status(&min_stat, min, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &msg); GSS_UNLOCK_MUTEX(utils); if(GSS_ERROR(maj_stat)) { if (logonly) { utils->log(utils->conn, SASL_LOG_FAIL, "GSSAPI Failure: (could not get minor error message)"); } else { utils->seterror(utils->conn, 0, "GSSAPI Failure " "(could not get minor error message)"); } utils->free(out); return SASL_OK; } len += len + msg.length; ret = _plug_buf_alloc(utils, &out, &curlen, len); if(ret != SASL_OK) { utils->free(out); return SASL_NOMEM; } strcat(out, msg.value); GSS_LOCK_MUTEX(utils); gss_release_buffer(&min_stat, &msg); GSS_UNLOCK_MUTEX(utils); if (!msg_ctx) break; } len += 1; ret = _plug_buf_alloc(utils, &out, &curlen, len); if(ret != SASL_OK) { utils->free(out); return SASL_NOMEM; } strcat(out, ")"); if (logonly) { utils->log(utils->conn, SASL_LOG_FAIL, out); } else { utils->seterror(utils->conn, 0, out); } utils->free(out); return SASL_OK; }
DWORD VMCARESTVerifyKrbAuth( PVMCA_AUTHORIZATION_PARAM pAuthorization, PVMCA_ACCESS_TOKEN* ppAccessToken ) { DWORD dwError = 0; PSTR pszNegotiate = NULL; PSTR pszDecode = NULL; PSTR pszUser = NULL; char *pszToken = NULL; int nLength = 0; OM_uint32 major_status; OM_uint32 minor_status; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc display_name = GSS_C_EMPTY_BUFFER; gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; gss_name_t client_name = GSS_C_NO_NAME; static gss_OID_desc gss_spnego_mech_oid_desc = {6, (void *)"\x2b\x06\x01\x05\x05\x02"}; static gss_OID gss_spnego_mech_oid = &gss_spnego_mech_oid_desc; gss_cred_id_t server_creds; pszNegotiate = pAuthorization->pszAuthorizationToken; if ( IsNullOrEmptyString(pszNegotiate) ) { dwError = EACCES; BAIL_ON_VMREST_ERROR(dwError); } if (!strcmp(pszNegotiate,"testing")) // TODO: REMOVE // TODO: DO NOT CHECK IN {// Kerberos backdoor for testing dwError = VMCARESTMakeKrbAccessToken(ppAccessToken); BAIL_ON_VMREST_ERROR(dwError); goto cleanup; } dwError = base64_decode( pszNegotiate, &pszDecode, &nLength ); BAIL_ON_VMREST_ERROR(dwError); dwError = server_acquire_creds( "HTTP", &gss_spnego_mech_oid_desc, &server_creds ); BAIL_ON_VMREST_ERROR(dwError); input_token.length = nLength; input_token.value = pszDecode; major_status = gss_accept_sec_context( &minor_status, &gss_context, server_creds, &input_token, GSS_C_NO_CHANNEL_BINDINGS, &client_name, &gss_spnego_mech_oid, &output_token, NULL, NULL, NULL ); if (GSS_ERROR(major_status) ) { //TODO: insert show error dwError = EACCES; BAIL_ON_VMREST_ERROR(dwError); } if (output_token.length) { dwError = make_negotiate_token(&output_token, &pszToken); BAIL_ON_VMREST_ERROR(dwError); } if (major_status == GSS_S_CONTINUE_NEEDED) { OM_uint32 min2; gss_buffer_desc mech_msg = GSS_C_EMPTY_BUFFER; gss_buffer_desc gss_msg = GSS_C_EMPTY_BUFFER; gss_buffer_desc minor_msg = GSS_C_EMPTY_BUFFER; OM_uint32 msg_ctx = 0; PSTR pszError = NULL; gss_oid_to_str(&min2, gss_spnego_mech_oid, &mech_msg); gss_display_status(&min2, major_status, GSS_C_GSS_CODE, gss_spnego_mech_oid, &msg_ctx, &gss_msg); gss_display_status(&min2, minor_status, GSS_C_MECH_CODE, gss_spnego_mech_oid, &msg_ctx, &minor_msg); VMCAAllocateStringPrintfA(&pszError, "gss_rc[%d:%*s] mech[%*s] minor[%u:%*s]", major_status, (int)gss_msg.length, (const char *)(gss_msg.value?gss_msg.value:""), (int)mech_msg.length, (const char *)(mech_msg.value?mech_msg.value:""), minor_status, (int)minor_msg.length, (const char *)(minor_msg.value?minor_msg.value:"")); gss_release_buffer(&min2, &mech_msg); gss_release_buffer(&min2, &gss_msg); gss_release_buffer(&min2, &minor_msg); } if (major_status == GSS_S_COMPLETE) { gss_display_name(&minor_status, client_name, &display_name, NULL); dwError = VMCAAllocateStringA(display_name.value, &pszUser); BAIL_ON_VMREST_ERROR(dwError); } dwError = VMCARESTMakeKrbAccessToken(ppAccessToken); BAIL_ON_VMREST_ERROR(dwError); cleanup: if (pszUser) { VMCA_SAFE_FREE_MEMORY(pszUser); } return dwError; error: goto cleanup; }
/** * Return a copy of the short description from the instance data * @ingroup globus_gssapi_error_object * * @param error * The error object to retrieve the data from. * @return * String containing the short description if it exists, NULL * otherwise. */ static char * globus_l_error_gssapi_printable( globus_object_t * error) { OM_uint32 minor_status; OM_uint32 message_context; gss_buffer_desc status_string_desc = GSS_C_EMPTY_BUFFER; gss_buffer_t status_string = &status_string_desc; char * msg = NULL; char * tmp; int len = 0; globus_l_gssapi_error_data_t * data; data = (globus_l_gssapi_error_data_t *) globus_object_get_local_instance_data(error); if(data->is_globus_gsi) { message_context = 0; do { if(gss_display_status(&minor_status, data->major_status, GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, status_string) == GSS_S_COMPLETE) { if(status_string->length) { if(msg) { tmp = globus_realloc( msg, sizeof(char) * (len + status_string->length + 1)); } else { tmp = globus_malloc( sizeof(char) * (status_string->length + 1)); } if(tmp) { memcpy( tmp + len, status_string->value, status_string->length); msg = tmp; len += status_string->length; } } gss_release_buffer(&minor_status, status_string); } } while(message_context != 0); if(msg) { if(msg[len - 1] == '\n') { len--; } msg[len] = '\0'; } } else { globus_gss_assist_display_status_str( &msg, NULL, data->major_status, data->minor_status, 0); } return msg; }/* globus_l_error_gssapi_printable */
const char *msg, int maj_stat, int min_stat) { gss_buffer_desc msg_maj = { .length = 0, }; gss_buffer_desc msg_min = { .length = 0, }; OM_uint32 dummy_maj, dummy_min; OM_uint32 message_context = 0; dummy_maj = gss_display_status(&dummy_min, maj_stat, GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &msg_maj); if (dummy_maj != 0) { goto out; } dummy_maj = gss_display_status(&dummy_min, min_stat, GSS_C_MECH_CODE, GSS_C_NO_OID, &message_context, &msg_min); if (dummy_maj != 0) { goto out; }
static int gss_auth(void *app_data, char *host) { OM_uint32 maj_stat, min_stat; gss_name_t target_name; gss_buffer_desc input, output_token; int context_established = 0; char *p; int n; gss_channel_bindings_t bindings; struct gssapi_data *d = app_data; OM_uint32 mech_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG; const char *knames[] = { "ftp", "host", NULL }, **kname = knames; if(import_name(*kname++, host, &target_name)) return AUTH_ERROR; input.length = 0; input.value = NULL; if (ftp_do_gss_bindings) { bindings = malloc(sizeof(*bindings)); if (bindings == NULL) errx(1, "out of memory"); sockaddr_to_gss_address (myctladdr, &bindings->initiator_addrtype, &bindings->initiator_address); sockaddr_to_gss_address (hisctladdr, &bindings->acceptor_addrtype, &bindings->acceptor_address); bindings->application_data.length = 0; bindings->application_data.value = NULL; } else bindings = GSS_C_NO_CHANNEL_BINDINGS; if (ftp_do_gss_delegate) mech_flags |= GSS_C_DELEG_FLAG; while(!context_established) { maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &d->context_hdl, target_name, GSS_C_NO_OID, mech_flags, 0, bindings, &input, NULL, &output_token, NULL, NULL); if (GSS_ERROR(maj_stat)) { OM_uint32 new_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; d->context_hdl = GSS_C_NO_CONTEXT; gss_release_name(&min_stat, &target_name); if(*kname != NULL) { if(import_name(*kname++, host, &target_name)) { if (bindings != GSS_C_NO_CHANNEL_BINDINGS) free(bindings); return AUTH_ERROR; } continue; } if (bindings != GSS_C_NO_CHANNEL_BINDINGS) free(bindings); gss_display_status(&new_stat, min_stat, GSS_C_MECH_CODE, GSS_C_NO_OID, &msg_ctx, &status_string); printf("Error initializing security context: %.*s\n", (int)status_string.length, (char*)status_string.value); gss_release_buffer(&new_stat, &status_string); return AUTH_CONTINUE; } if (input.value) { free(input.value); input.value = NULL; input.length = 0; } if (output_token.length != 0) { base64_encode(output_token.value, output_token.length, &p); gss_release_buffer(&min_stat, &output_token); n = command("ADAT %s", p); free(p); } if (GSS_ERROR(maj_stat)) { if (d->context_hdl != GSS_C_NO_CONTEXT) gss_delete_sec_context (&min_stat, &d->context_hdl, GSS_C_NO_BUFFER); break; } if (maj_stat & GSS_S_CONTINUE_NEEDED) { p = strstr(reply_string, "ADAT="); if(p == NULL){ printf("Error: expected ADAT in reply. got: %s\n", reply_string); if (bindings != GSS_C_NO_CHANNEL_BINDINGS) free(bindings); return AUTH_ERROR; } else { p+=5; input.value = malloc(strlen(p)); input.length = base64_decode(p, input.value); } } else { if(code != 235) { printf("Unrecognized response code: %d\n", code); if (bindings != GSS_C_NO_CHANNEL_BINDINGS) free(bindings); return AUTH_ERROR; } context_established = 1; } } gss_release_name(&min_stat, &target_name); if (bindings != GSS_C_NO_CHANNEL_BINDINGS) free(bindings); if (input.value) free(input.value); { gss_name_t targ_name; maj_stat = gss_inquire_context(&min_stat, d->context_hdl, NULL, &targ_name, NULL, NULL, NULL, NULL, NULL); if (GSS_ERROR(maj_stat) == 0) { gss_buffer_desc name; maj_stat = gss_display_name (&min_stat, targ_name, &name, NULL); if (GSS_ERROR(maj_stat) == 0) { printf("Authenticated to <%.*s>\n", (int)name.length, (char *)name.value); gss_release_buffer(&min_stat, &name); } gss_release_name(&min_stat, &targ_name); } else printf("Failed to get gss name of peer.\n"); } return AUTH_OK; }
static int gss_adat(void *app_data, void *buf, size_t len) { char *p = NULL; gss_buffer_desc input_token, output_token; OM_uint32 maj_stat, min_stat; gss_name_t client_name; struct gssapi_data *d = app_data; gss_channel_bindings_t bindings; if (ftp_do_gss_bindings) { bindings = malloc(sizeof(*bindings)); if (bindings == NULL) errx(1, "out of memory"); sockaddr_to_gss_address (his_addr, &bindings->initiator_addrtype, &bindings->initiator_address); sockaddr_to_gss_address (ctrl_addr, &bindings->acceptor_addrtype, &bindings->acceptor_address); bindings->application_data.length = 0; bindings->application_data.value = NULL; } else bindings = GSS_C_NO_CHANNEL_BINDINGS; input_token.value = buf; input_token.length = len; maj_stat = gss_accept_sec_context (&min_stat, &d->context_hdl, GSS_C_NO_CREDENTIAL, &input_token, bindings, &client_name, NULL, &output_token, NULL, NULL, &d->delegated_cred_handle); if (bindings != GSS_C_NO_CHANNEL_BINDINGS) free(bindings); if(output_token.length) { if(base64_encode(output_token.value, output_token.length, &p) < 0) { reply(535, "Out of memory base64-encoding."); return -1; } gss_release_buffer(&min_stat, &output_token); } if(maj_stat == GSS_S_COMPLETE){ d->client_name = client_name; client_name = GSS_C_NO_NAME; if(p) reply(235, "ADAT=%s", p); else reply(235, "ADAT Complete"); sec_complete = 1; } else if(maj_stat == GSS_S_CONTINUE_NEEDED) { if(p) reply(335, "ADAT=%s", p); else reply(335, "OK, need more data"); } else { OM_uint32 new_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; gss_display_status(&new_stat, min_stat, GSS_C_MECH_CODE, GSS_C_NO_OID, &msg_ctx, &status_string); syslog(LOG_ERR, "gss_accept_sec_context: %.*s", (int)status_string.length, (char*)status_string.value); gss_release_buffer(&new_stat, &status_string); reply(431, "Security resource unavailable"); } if (client_name) gss_release_name(&min_stat, &client_name); free(p); return 0; }
NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx, gss_ctx_id_t gssapi_context, gss_name_t gss_client_name, DATA_BLOB *pac_blob) { NTSTATUS status; OM_uint32 gss_maj, gss_min; #ifdef HAVE_GSS_GET_NAME_ATTRIBUTE /* * gss_get_name_attribute() in MIT krb5 1.10.0 can return unintialized pac_display_buffer * and later gss_release_buffer() will crash on attempting to release it. * * So always initialize the buffer descriptors. * * See following links for more details: * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=658514 * http://krbdev.mit.edu/rt/Ticket/Display.html?user=guest&pass=guest&id=7087 */ gss_buffer_desc pac_buffer = { .value = NULL, .length = 0 }; gss_buffer_desc pac_display_buffer = { .value = NULL, .length = 0 }; gss_buffer_desc pac_name = { .value = discard_const("urn:mspac:"), .length = sizeof("urn:mspac:")-1 }; int more = -1; int authenticated = false; int complete = false; gss_maj = gss_get_name_attribute( &gss_min, gss_client_name, &pac_name, &authenticated, &complete, &pac_buffer, &pac_display_buffer, &more); if (gss_maj != 0) { gss_OID oid = discard_const(gss_mech_krb5); DBG_NOTICE("obtaining PAC via GSSAPI gss_get_name_attribute " "failed: %s\n", gssapi_error_string(mem_ctx, gss_maj, gss_min, oid)); return NT_STATUS_ACCESS_DENIED; } else if (authenticated && complete) { /* The PAC blob is returned directly */ *pac_blob = data_blob_talloc(mem_ctx, pac_buffer.value, pac_buffer.length); if (!pac_blob->data) { status = NT_STATUS_NO_MEMORY; } else { status = NT_STATUS_OK; } gss_maj = gss_release_buffer(&gss_min, &pac_buffer); gss_maj = gss_release_buffer(&gss_min, &pac_display_buffer); return status; } else { DEBUG(0, ("obtaining PAC via GSSAPI failed: authenticated: %s, complete: %s, more: %s\n", authenticated ? "true" : "false", complete ? "true" : "false", more ? "true" : "false")); return NT_STATUS_ACCESS_DENIED; } #elif defined(HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID) gss_OID_desc pac_data_oid = { .elements = discard_const(EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID), .length = EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH }; gss_buffer_set_t set = GSS_C_NO_BUFFER_SET; /* If we didn't have the routine to get a verified, validated * PAC (supplied only by MIT at the time of writing), then try * with the Heimdal OID (fetches the PAC directly and always * validates) */ gss_maj = gss_inquire_sec_context_by_oid( &gss_min, gssapi_context, &pac_data_oid, &set); /* First check for the error MIT gives for an unknown OID */ if (gss_maj == GSS_S_UNAVAILABLE) { DEBUG(1, ("unable to obtain a PAC against this GSSAPI library. " "GSSAPI secured connections are available only with Heimdal or MIT Kerberos >= 1.8\n")); } else if (gss_maj != 0) { DEBUG(2, ("obtaining PAC via GSSAPI gss_inqiure_sec_context_by_oid (Heimdal OID) failed: %s\n", gssapi_error_string(mem_ctx, gss_maj, gss_min, gss_mech_krb5))); } else { if (set == GSS_C_NO_BUFFER_SET) { DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown " "data in results.\n")); return NT_STATUS_INTERNAL_ERROR; } /* The PAC blob is returned directly */ *pac_blob = data_blob_talloc(mem_ctx, set->elements[0].value, set->elements[0].length); if (!pac_blob->data) { status = NT_STATUS_NO_MEMORY; } else { status = NT_STATUS_OK; } gss_maj = gss_release_buffer_set(&gss_min, &set); return status; } #else DEBUG(1, ("unable to obtain a PAC against this GSSAPI library. " "GSSAPI secured connections are available only with Heimdal or MIT Kerberos >= 1.8\n")); #endif return NT_STATUS_ACCESS_DENIED; } NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx, gss_ctx_id_t gssapi_context, DATA_BLOB *session_key, uint32_t *keytype) { OM_uint32 gss_min, gss_maj; gss_buffer_set_t set = GSS_C_NO_BUFFER_SET; gss_maj = gss_inquire_sec_context_by_oid( &gss_min, gssapi_context, &gse_sesskey_inq_oid, &set); if (gss_maj) { DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n", gssapi_error_string(mem_ctx, gss_maj, gss_min, discard_const_p(struct gss_OID_desc_struct, gss_mech_krb5)))); return NT_STATUS_NO_USER_SESSION_KEY; } if ((set == GSS_C_NO_BUFFER_SET) || (set->count == 0)) { #ifdef HAVE_GSSKRB5_GET_SUBKEY krb5_keyblock *subkey; gss_maj = gsskrb5_get_subkey(&gss_min, gssapi_context, &subkey); if (gss_maj != 0) { DEBUG(1, ("NO session key for this mech\n")); return NT_STATUS_NO_USER_SESSION_KEY; } if (session_key) { *session_key = data_blob_talloc(mem_ctx, KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey)); } if (keytype) { *keytype = KRB5_KEY_TYPE(subkey); } krb5_free_keyblock(NULL /* should be krb5_context */, subkey); return NT_STATUS_OK; #else DEBUG(0, ("gss_inquire_sec_context_by_oid didn't return any session key (and no alternative method available)\n")); return NT_STATUS_NO_USER_SESSION_KEY; #endif } if (session_key) { *session_key = data_blob_talloc(mem_ctx, set->elements[0].value, set->elements[0].length); } if (keytype) { int diflen, i; const uint8_t *p; *keytype = 0; if (set->count < 2) { #ifdef HAVE_GSSKRB5_GET_SUBKEY krb5_keyblock *subkey; gss_maj = gsskrb5_get_subkey(&gss_min, gssapi_context, &subkey); if (gss_maj == 0) { *keytype = KRB5_KEY_TYPE(subkey); krb5_free_keyblock(NULL /* should be krb5_context */, subkey); } #endif gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_OK; } else if (memcmp(set->elements[1].value, gse_sesskeytype_oid.elements, gse_sesskeytype_oid.length) != 0) { /* Perhaps a non-krb5 session key */ gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_OK; } p = (const uint8_t *)set->elements[1].value + gse_sesskeytype_oid.length; diflen = set->elements[1].length - gse_sesskeytype_oid.length; if (diflen <= 0) { gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_INVALID_PARAMETER; } for (i = 0; i < diflen; i++) { *keytype = (*keytype << 7) | (p[i] & 0x7f); if (i + 1 != diflen && (p[i] & 0x80) == 0) { gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_INVALID_PARAMETER; } } } gss_maj = gss_release_buffer_set(&gss_min, &set); return NT_STATUS_OK; } char *gssapi_error_string(TALLOC_CTX *mem_ctx, OM_uint32 maj_stat, OM_uint32 min_stat, const gss_OID mech) { OM_uint32 disp_min_stat, disp_maj_stat; gss_buffer_desc maj_error_message; gss_buffer_desc min_error_message; char *maj_error_string, *min_error_string; OM_uint32 msg_ctx = 0; char *ret; maj_error_message.value = NULL; min_error_message.value = NULL; maj_error_message.length = 0; min_error_message.length = 0; disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE, mech, &msg_ctx, &maj_error_message); if (disp_maj_stat != 0) { maj_error_message.value = NULL; maj_error_message.length = 0; } disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE, mech, &msg_ctx, &min_error_message); if (disp_maj_stat != 0) { min_error_message.value = NULL; min_error_message.length = 0; } maj_error_string = talloc_strndup(mem_ctx, (char *)maj_error_message.value, maj_error_message.length); min_error_string = talloc_strndup(mem_ctx, (char *)min_error_message.value, min_error_message.length); ret = talloc_asprintf(mem_ctx, "%s: %s", maj_error_string, min_error_string); talloc_free(maj_error_string); talloc_free(min_error_string); gss_release_buffer(&disp_min_stat, &maj_error_message); gss_release_buffer(&disp_min_stat, &min_error_message); return ret; }
static int gss_auth(void *app_data, char *host) { OM_uint32 maj_stat, min_stat; gss_name_t target_name; gss_buffer_desc input, output_token; int context_established = 0; char *p; int n; gss_channel_bindings_t bindings; struct gss_data *d = app_data; const char *knames[] = { "ftp", "host", NULL }, **kname = knames; if(import_name(*kname++, host, &target_name)) return AUTH_ERROR; input.length = 0; input.value = NULL; bindings = malloc(sizeof(*bindings)); sockaddr_to_gss_address (myctladdr, &bindings->initiator_addrtype, &bindings->initiator_address); sockaddr_to_gss_address (hisctladdr, &bindings->acceptor_addrtype, &bindings->acceptor_address); bindings->application_data.length = 0; bindings->application_data.value = NULL; while(!context_established) { maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &d->context_hdl, target_name, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG, 0, bindings, &input, NULL, &output_token, NULL, NULL); if (GSS_ERROR(maj_stat)) { OM_uint32 new_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; if(min_stat == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN && *kname != NULL) { if(import_name(*kname++, host, &target_name)) return AUTH_ERROR; continue; } gss_display_status(&new_stat, min_stat, GSS_C_MECH_CODE, GSS_C_NO_OID, &msg_ctx, &status_string); printf("Error initializing security context: %s\n", (char*)status_string.value); gss_release_buffer(&new_stat, &status_string); return AUTH_CONTINUE; } gss_release_buffer(&min_stat, &input); if (output_token.length != 0) { base64_encode(output_token.value, output_token.length, &p); gss_release_buffer(&min_stat, &output_token); n = ftp_cmd("ADAT %s", p); free(p); } if (GSS_ERROR(maj_stat)) { if (d->context_hdl != GSS_C_NO_CONTEXT) gss_delete_sec_context (&min_stat, &d->context_hdl, GSS_C_NO_BUFFER); break; } if (maj_stat & GSS_S_CONTINUE_NEEDED) { p = strstr(ftp->reply, "ADAT="); if(p == NULL){ printf("Error: expected ADAT in reply. got: %s\n", ftp->reply); return AUTH_ERROR; } else { p+=5; input.value = malloc(strlen(p)); input.length = base64_decode(p, input.value); } } else { if(ftp->fullcode != 235) { printf("Unrecognized response code: %d\n", ftp->fullcode); return AUTH_ERROR; } context_established = 1; } } return AUTH_OK; }
static uint32_t NetSecurityNative_AcquireCredSpNego(uint32_t* minorStatus, GssName* desiredName, gss_cred_usage_t credUsage, GssCredId** outputCredHandle) { assert(minorStatus != NULL); assert(desiredName != NULL); assert(outputCredHandle != NULL); assert(*outputCredHandle == NULL); #if HAVE_GSS_SPNEGO_MECHANISM gss_OID_set_desc gss_mech_spnego_OID_set_desc = {.count = 1, .elements = GSS_SPNEGO_MECHANISM}; #else gss_OID_set_desc gss_mech_spnego_OID_set_desc = {.count = 1, .elements = &gss_mech_spnego_OID_desc}; #endif uint32_t majorStatus = gss_acquire_cred( minorStatus, desiredName, 0, &gss_mech_spnego_OID_set_desc, 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_InitiateCredSpNego(uint32_t* minorStatus, GssName* desiredName, GssCredId** outputCredHandle) { return NetSecurityNative_AcquireCredSpNego(minorStatus, desiredName, GSS_C_INITIATE, outputCredHandle); } uint32_t NetSecurityNative_DeleteSecContext(uint32_t* minorStatus, GssCtxId** contextHandle) { assert(minorStatus != NULL); assert(contextHandle != NULL); return gss_delete_sec_context(minorStatus, contextHandle, GSS_C_NO_BUFFER); } static uint32_t NetSecurityNative_DisplayStatus(uint32_t* minorStatus, uint32_t statusValue, int statusType, PAL_GssBuffer* outBuffer) { assert(minorStatus != NULL); assert(outBuffer != NULL); uint32_t messageContext = 0; // Must initialize to 0 before calling gss_display_status. GssBuffer gssBuffer = {.length = 0, .value = NULL}; uint32_t majorStatus = gss_display_status(minorStatus, statusValue, statusType, GSS_C_NO_OID, &messageContext, &gssBuffer); NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer); return majorStatus; } uint32_t NetSecurityNative_DisplayMinorStatus(uint32_t* minorStatus, uint32_t statusValue, PAL_GssBuffer* outBuffer) { return NetSecurityNative_DisplayStatus(minorStatus, statusValue, GSS_C_MECH_CODE, outBuffer); } uint32_t NetSecurityNative_DisplayMajorStatus(uint32_t* minorStatus, uint32_t statusValue, PAL_GssBuffer* outBuffer) { return NetSecurityNative_DisplayStatus(minorStatus, statusValue, GSS_C_GSS_CODE, outBuffer); } uint32_t NetSecurityNative_ImportUserName(uint32_t* minorStatus, char* inputName, uint32_t inputNameLen, GssName** outputName) { assert(minorStatus != NULL); assert(inputName != NULL); assert(outputName != NULL); assert(*outputName == NULL); GssBuffer inputNameBuffer = {.length = inputNameLen, .value = inputName}; return gss_import_name(minorStatus, &inputNameBuffer, GSS_C_NT_USER_NAME, outputName); }
static void ssh_gssapi_log_error(int verb, const char *msg, int maj_stat){ gss_buffer_desc buffer; OM_uint32 dummy, message_context; gss_display_status(&dummy,maj_stat,GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buffer); SSH_LOG(verb, "GSSAPI(%s): %s", msg, (const char *)buffer.value); }
static char * gss_mk_err(OM_uint32 maj_stat, OM_uint32 min_stat, const char *preamble) { gss_buffer_desc status; OM_uint32 new_stat; OM_uint32 cur_stat; OM_uint32 msg_ctx = 0; OM_uint32 ret; int type; size_t newlen; char *str = NULL; char *tmp = NULL; cur_stat = maj_stat; type = GSS_C_GSS_CODE; for (;;) { /* * GSS_S_FAILURE produces a rather unhelpful message, so * we skip straight to the mech specific error in this case. */ if (type == GSS_C_GSS_CODE && cur_stat == GSS_S_FAILURE) { type = GSS_C_MECH_CODE; cur_stat = min_stat; } ret = gss_display_status(&new_stat, cur_stat, type, GSS_C_NO_OID, &msg_ctx, &status); if (GSS_ERROR(ret)) return str; /* XXXrcd: hmmm, not quite?? */ if (str) newlen = strlen(str); else newlen = strlen(preamble); newlen += status.length + 3; tmp = str; str = malloc(newlen); if (!str) { gss_release_buffer(&new_stat, &status); return tmp; /* XXXrcd: hmmm, not quite?? */ } snprintf(str, newlen, "%s%s%.*s", tmp?tmp:preamble, tmp?", ":": ", (int)status.length, (char *)status.value); gss_release_buffer(&new_stat, &status); free(tmp); /* * If we are finished processing for maj_stat, then * move onto min_stat. */ if (msg_ctx == 0 && type == GSS_C_GSS_CODE && min_stat != 0) { type = GSS_C_MECH_CODE; cur_stat = min_stat; continue; } if (msg_ctx == 0) break; } return str; }
char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[]) { char *ret = NIL; char tmp[MAILTMPLEN]; unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE); int conf; OM_uint32 smj,smn,dsmj,dsmn,flags; OM_uint32 mctx = 0; gss_name_t crname,name; gss_OID mech; gss_buffer_desc chal,resp,buf; gss_cred_id_t crd; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_qop_t qop = GSS_C_QOP_DEFAULT; /* make service name */ sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL), tcp_serverhost ()); buf.length = strlen (buf.value = tmp); /* acquire credentials */ if ((gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname)) == GSS_S_COMPLETE) { if ((smj = gss_acquire_cred (&smn,crname,0,NIL,GSS_C_ACCEPT,&crd,NIL,NIL)) == GSS_S_COMPLETE) { if ((resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) != NULL) { do { /* negotiate authentication */ smj = gss_accept_sec_context (&smn,&ctx,crd,&resp, GSS_C_NO_CHANNEL_BINDINGS,&name,&mech, &chal,&flags,NIL,NIL); /* don't need response any more */ fs_give ((void **) &resp.value); switch (smj) { /* how did it go? */ case GSS_S_COMPLETE: /* successful */ case GSS_S_CONTINUE_NEEDED: if (chal.value) { /* send challenge, get next response */ resp.value = (*responder) (chal.value,chal.length, (unsigned long *) &resp.length); gss_release_buffer (&smn,&chal); } break; } } while (resp.value && resp.length && (smj == GSS_S_CONTINUE_NEEDED)); /* successful exchange? */ if ((smj == GSS_S_COMPLETE) && (gss_display_name (&smn,name,&buf,&mech) == GSS_S_COMPLETE)) { /* send security and size */ memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4); tmp[0] = AUTH_GSSAPI_P_NONE; if (gss_wrap (&smn,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){ resp.value = (*responder) (chal.value,chal.length, (unsigned long *) &resp.length); gss_release_buffer (&smn,&chal); if (gss_unwrap (&smn,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) { /* client request valid */ if (chal.value && (chal.length > 4) && (chal.length < (MAILTMPLEN - 1)) && memcpy (tmp,chal.value,chal.length) && (tmp[0] & AUTH_GSSAPI_P_NONE)) { /* tie off authorization ID */ tmp[chal.length] = '\0'; ret = kerberos_login (tmp+4,buf.value,argc,argv); } /* done with user name */ gss_release_buffer (&smn,&chal); } /* finished with response */ fs_give ((void **) &resp.value); } /* don't need name buffer any more */ gss_release_buffer (&smn,&buf); } /* don't need client name any more */ gss_release_name (&smn,&name); /* don't need context any more */ if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,NIL); } /* finished with credentials */ gss_release_cred (&smn,&crd); } else { /* can't acquire credentials! */ if (gss_display_name (&dsmn,crname,&buf,&mech) == GSS_S_COMPLETE) SERVER_LOG ("Failed to acquire credentials for %s",buf.value); if (smj != GSS_S_FAILURE) do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: mctx = 0; case GSS_S_CONTINUE_NEEDED: SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: case GSS_S_CONTINUE_NEEDED: SERVER_LOG ("GSSAPI mechanism status: %s",resp.value); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); } /* finished with credentials name */ gss_release_name (&smn,&crname); } return ret; /* return status */ }
long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal, authrespond_t responder,char *service,NETMBX *mb, void *stream,char *user,kinit_t ki) { char tmp[MAILTMPLEN]; OM_uint32 smj,smn,dsmj,dsmn; OM_uint32 mctx = 0; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_buffer_desc resp,buf; long i; int conf; gss_qop_t qop; gss_name_t crname = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data; long ret = NIL; sprintf (tmp,"%s@%s",service,mb->host); buf.length = strlen (buf.value = tmp); /* get service name */ if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname) != GSS_S_COMPLETE) { mm_log ("Can't import Kerberos service name",WARN); (*responder) (stream,NIL,0); } else { data = (*bn) (BLOCK_SENSITIVE,NIL); /* negotiate with KDC */ smj = gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname,NIL, GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS, GSS_C_NO_BUFFER,NIL,&resp,NIL,NIL); (*bn) (BLOCK_NONSENSITIVE,data); /* while continuation needed */ while (smj == GSS_S_CONTINUE_NEEDED) { if (chal.value) fs_give ((void **) &chal.value); /* send response, get next challenge */ i = (*responder) (stream,resp.value,resp.length) && (chal.value = (*challenger) (stream,(unsigned long *) &chal.length)); gss_release_buffer (&smn,&resp); if (i) { /* negotiate continuation with KDC */ data = (*bn) (BLOCK_SENSITIVE,NIL); switch (smj = /* make sure continuation going OK */ gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx, crname,GSS_C_NO_OID,GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0, GSS_C_NO_CHANNEL_BINDINGS,&chal,NIL, &resp,NIL,NIL)) { case GSS_S_CONTINUE_NEEDED: case GSS_S_COMPLETE: break; default: /* error, don't need context any more */ gss_delete_sec_context (&smn,&ctx,NIL); } (*bn) (BLOCK_NONSENSITIVE,data); } else { /* error in continuation */ mm_log ("Error in negotiating Kerberos continuation",WARN); (*responder) (stream,NIL,0); /* don't need context any more */ gss_delete_sec_context (&smn,&ctx,NIL); break; } } switch (smj) { /* done - deal with final condition */ case GSS_S_COMPLETE: if (chal.value) fs_give ((void **) &chal.value); /* get prot mechanisms and max size */ if ((*responder) (stream,resp.value ? resp.value : "",resp.length) && (chal.value = (*challenger) (stream,(unsigned long *)&chal.length))&& (gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop) == GSS_S_COMPLETE) && (resp.length >= 4) && (*((char *) resp.value) & AUTH_GSSAPI_P_NONE)){ /* make copy of flags and length */ memcpy (tmp,resp.value,4); gss_release_buffer (&smn,&resp); /* no session protection */ tmp[0] = AUTH_GSSAPI_P_NONE; /* install user name */ strcpy (tmp+4,strcpy (user,mb->user[0] ? mb->user : myusername ())); buf.value = tmp; buf.length = strlen (user) + 4; /* successful negotiation */ switch (smj = gss_wrap (&smn,ctx,NIL,qop,&buf,&conf,&resp)) { case GSS_S_COMPLETE: if ((*responder) (stream,resp.value,resp.length)) ret = T; gss_release_buffer (&smn,&resp); break; default: do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: mctx = 0; case GSS_S_CONTINUE_NEEDED: sprintf (tmp,"Unknown gss_wrap failure: %s",(char *) resp.value); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: case GSS_S_CONTINUE_NEEDED: sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); (*responder) (stream,NIL,0); } } /* flush final challenge */ if (chal.value) fs_give ((void **) &chal.value); /* don't need context any more */ gss_delete_sec_context (&smn,&ctx,NIL); break; case GSS_S_CREDENTIALS_EXPIRED: if (chal.value) fs_give ((void **) &chal.value); /* retry if application kinits */ if (ki && (*ki) (mb->host,"Kerberos credentials expired")) ret = auth_gssapi_client_work (challenger,chal,responder,service,mb, stream,user,NIL); else { /* application can't kinit */ sprintf (tmp,"Kerberos credentials expired (try running kinit) for %s", mb->host); mm_log (tmp,WARN); (*responder) (stream,NIL,0); } break; case GSS_S_FAILURE: if (chal.value) fs_give ((void **) &chal.value); do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: /* end of message, can kinit? */ if (ki && kerberos_try_kinit (smn) && (*ki) (mb->host,(char *) resp.value)) { gss_release_buffer (&dsmn,&resp); ret = auth_gssapi_client_work (challenger,chal,responder,service,mb, stream,user,NIL); break; /* done */ } else (*responder) (stream,NIL,0); case GSS_S_CONTINUE_NEEDED: sprintf (tmp,kerberos_try_kinit (smn) ? "Kerberos error: %.80s (try running kinit) for %.80s" : "GSSAPI failure: %s for %.80s",(char *) resp.value,mb->host); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); break; default: /* miscellaneous errors */ if (chal.value) fs_give ((void **) &chal.value); do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: mctx = 0; case GSS_S_CONTINUE_NEEDED: sprintf (tmp,"Unknown GSSAPI failure: %s",(char *) resp.value); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE, GSS_C_NO_OID,&mctx,&resp)) { case GSS_S_COMPLETE: case GSS_S_CONTINUE_NEEDED: sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value); mm_log (tmp,WARN); gss_release_buffer (&dsmn,&resp); } while (dsmj == GSS_S_CONTINUE_NEEDED); (*responder) (stream,NIL,0); break; } /* finished with credentials name */ if (crname) gss_release_name (&smn,&crname); } return ret; /* return status */ }
/* Acquire GSSAPI credentials and set up RPC auth flavor. */ static kadm5_ret_t setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in, krb5_principal client, krb5_principal server) { OM_uint32 gssstat, minor_stat; gss_buffer_desc buf; gss_name_t gss_client; gss_name_t gss_target; gss_cred_id_t gss_client_creds; const char *c_ccname_orig; char *ccname_orig; gss_client_creds = GSS_C_NO_CREDENTIAL; ccname_orig = NULL; gss_client = gss_target = GSS_C_NO_NAME; /* Temporarily use the kadm5 cache. */ gssstat = gss_krb5_ccache_name(&minor_stat, handle->cache_name, &c_ccname_orig); if (gssstat != GSS_S_COMPLETE) goto error; if (c_ccname_orig) ccname_orig = strdup(c_ccname_orig); else ccname_orig = 0; buf.value = &server; buf.length = sizeof(server); gssstat = gss_import_name(&minor_stat, &buf, (gss_OID)gss_nt_krb5_principal, &gss_target); if (gssstat != GSS_S_COMPLETE) goto error; if (client != NULL) { buf.value = &client; buf.length = sizeof(client); gssstat = gss_import_name(&minor_stat, &buf, (gss_OID)gss_nt_krb5_principal, &gss_client); } else gss_client = GSS_C_NO_NAME; if (gssstat != GSS_S_COMPLETE) goto error; gssstat = gss_acquire_cred(&minor_stat, gss_client, 0, GSS_C_NULL_OID_SET, GSS_C_INITIATE, &gss_client_creds, NULL, NULL); if (gssstat != GSS_S_COMPLETE) { #if 0 /* for debugging only */ { OM_uint32 maj_status, min_status, message_context = 0; gss_buffer_desc status_string; do { maj_status = gss_display_status(&min_status, gssstat, GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &status_string); if (maj_status == GSS_S_COMPLETE) { fprintf(stderr, "MAJ: %.*s\n", (int) status_string.length, (char *)status_string.value); gss_release_buffer(&min_status, &status_string); } else { fprintf(stderr, "MAJ? gss_display_status returns 0x%lx?!\n", (unsigned long) maj_status); message_context = 0; } } while (message_context != 0); do { maj_status = gss_display_status(&min_status, minor_stat, GSS_C_MECH_CODE, GSS_C_NO_OID, &message_context, &status_string); if (maj_status == GSS_S_COMPLETE) { fprintf(stderr, "MIN: %.*s\n", (int) status_string.length, (char *)status_string.value); gss_release_buffer(&min_status, &status_string); } else { fprintf(stderr, "MIN? gss_display_status returns 0x%lx?!\n", (unsigned long) maj_status); message_context = 0; } } while (message_context != 0); } #endif goto error; } /* * Do actual creation of RPC auth handle. Implements auth flavor * fallback. */ rpc_auth(handle, params_in, gss_client_creds, gss_target); error: if (gss_client_creds != GSS_C_NO_CREDENTIAL) (void) gss_release_cred(&minor_stat, &gss_client_creds); if (gss_client) gss_release_name(&minor_stat, &gss_client); if (gss_target) gss_release_name(&minor_stat, &gss_target); /* Revert to prior gss_krb5 ccache. */ if (ccname_orig) { gssstat = gss_krb5_ccache_name(&minor_stat, ccname_orig, NULL); if (gssstat) { return KADM5_GSS_ERROR; } free(ccname_orig); } else { gssstat = gss_krb5_ccache_name(&minor_stat, NULL, NULL); if (gssstat) { return KADM5_GSS_ERROR; } } if (handle->clnt->cl_auth == NULL) { return KADM5_GSS_ERROR; } return 0; }
/* * Helper gssapi error functions. */ static int check_gss_err(struct SessionHandle *data, OM_uint32 major_status, OM_uint32 minor_status, const char* function) { if (GSS_ERROR(major_status)) { OM_uint32 maj_stat, min_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; char buf[1024]; size_t len; len = 0; msg_ctx = 0; while (!msg_ctx) { /* convert major status code (GSS-API error) to text */ maj_stat = gss_display_status(&min_stat, major_status, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); if (maj_stat == GSS_S_COMPLETE) { if (sizeof(buf) > len + status_string.length + 1) { strcpy(buf + len, (char*) status_string.value); len += status_string.length; } gss_release_buffer(&min_stat, &status_string); break; } gss_release_buffer(&min_stat, &status_string); } if (sizeof(buf) > len + 3) { strcpy(buf + len, ".\n"); len += 2; } msg_ctx = 0; while (!msg_ctx) { /* convert minor status code (underlying routine error) to text */ maj_stat = gss_display_status(&min_stat, minor_status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &status_string); if (maj_stat == GSS_S_COMPLETE) { if (sizeof(buf) > len + status_string.length) { strcpy(buf + len, (char*) status_string.value); len += status_string.length; } gss_release_buffer(&min_stat, &status_string); break; } gss_release_buffer(&min_stat, &status_string); } failf(data, "GSSAPI error: %s failed:\n%s\n", function, buf); return(1); } return(0); }
static const char * gssapi_strerror (OM_uint32 major_status, OM_uint32 minor_status) { static char buffer[1024]; OM_uint32 major, minor; OM_uint32 ctx; gss_buffer_desc status; char *buf; size_t len; int had_major; int had_minor; debug ("gssapi: major_status: %8.8x, minor_status: %8.8x", major_status, minor_status); buf = buffer; len = sizeof (buffer); buf[0] = '\0'; had_major = 0; ctx = 0; if (major_status != GSS_S_FAILURE || minor_status == 0) { for (;;) { major = gss_display_status (&minor, major_status, GSS_C_GSS_CODE, GSS_C_NO_OID, &ctx, &status); if (GSS_ERROR (major)) break; if (had_major) build_string (&buf, &len, ": ", 2); had_major = 1; build_string (&buf, &len, status.value, status.length); gss_release_buffer (&minor, &status); if (!ctx) break; } } ctx = 0; had_minor = 0; for (;;) { major = gss_display_status (&minor, minor_status, GSS_C_MECH_CODE, GSS_C_NULL_OID, &ctx, &status); if (GSS_ERROR (major)) break; if (had_minor) build_string (&buf, &len, ", ", 2); else if (had_major) build_string (&buf, &len, " (", 2); had_minor = 1; build_string (&buf, &len, status.value, status.length); gss_release_buffer (&minor, &status); if (!ctx) break; } if (had_major && had_minor) build_string (&buf, &len, ")", 1); return buffer; }
static DWORD LwGssGetSingleErrorMessage( OUT PSTR* ppszErrorMessage, IN OM_uint32 Status, IN BOOLEAN IsMajor ) { DWORD dwError = 0; PSTR pszErrorMessage = NULL; OM_uint32 majorStatus = 0; OM_uint32 minorStatus = 0; gss_buffer_desc message = GSS_C_EMPTY_BUFFER; OM_uint32 messageContext = 0; int statusType = IsMajor ? GSS_C_GSS_CODE : GSS_C_MECH_CODE; do { majorStatus = gss_display_status( &minorStatus, Status, statusType, GSS_C_NULL_OID, &messageContext, &message); if (majorStatus != GSS_S_COMPLETE) { LW_LOG_ERROR("Call to gss_display_status() failed with " "majorStatus = 0x%08x, minorStatus = 0x%08x", majorStatus, minorStatus); dwError = ERROR_INTERNAL_ERROR; BAIL_ON_LW_ERROR(dwError); } if (!pszErrorMessage) { dwError = LwAllocateString((PSTR)message.value, &pszErrorMessage); BAIL_ON_LW_ERROR(dwError); } else { PSTR pszNewErrorMessage = NULL; dwError = LwAllocateStringPrintf(&pszNewErrorMessage, "%s; %s", pszErrorMessage, (PSTR)message.value); BAIL_ON_LW_ERROR(dwError); LW_SAFE_FREE_STRING(pszErrorMessage); pszErrorMessage = pszNewErrorMessage; } majorStatus = gss_release_buffer(&minorStatus, &message); } while (messageContext); error: if (dwError) { LW_SAFE_FREE_STRING(pszErrorMessage); } if (message.value) { majorStatus = gss_release_buffer(&minorStatus, &message); } *ppszErrorMessage = pszErrorMessage; return dwError; }