OM_uint32 KRB5_CALLCONV gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, gss_cred_id_t cred, OM_uint32 num_ktypes, krb5_enctype *ktypes) { static const gss_OID_desc req_oid = { GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID_LENGTH, GSS_KRB5_SET_ALLOWABLE_ENCTYPES_OID }; OM_uint32 major_status; struct krb5_gss_set_allowable_enctypes_req req; gss_buffer_desc req_buffer; req.num_ktypes = num_ktypes; req.ktypes = ktypes; req_buffer.length = sizeof(req); req_buffer.value = &req; major_status = gss_set_cred_option(minor_status, &cred, (gss_OID)&req_oid, &req_buffer); return major_status; }
OM_uint32 gssi_set_cred_option(OM_uint32 *minor_status, gss_cred_id_t *cred_handle, const gss_OID desired_object, const gss_buffer_t value) { struct gpp_cred_handle *cred = NULL; OM_uint32 maj, min; GSSI_TRACE(); *minor_status = 0; if (*cred_handle == GSS_C_NO_CREDENTIAL) { return GSS_S_CALL_INACCESSIBLE_READ; } cred = (struct gpp_cred_handle *)*cred_handle; /* NOTE: For now we can do this only for known objects * or local credentials */ if (cred->remote) { return gpp_remote_options(minor_status, cred->remote, desired_object, value); } if (!cred->local) { return GSS_S_UNAVAILABLE; } maj = gss_set_cred_option(&min, &cred->local, desired_object, value); *minor_status = gpp_map_error(min); return maj; }
OM_uint32 KRB5_CALLCONV gss_krb5_import_cred(OM_uint32 *minor_status, krb5_ccache id, krb5_principal keytab_principal, krb5_keytab keytab, gss_cred_id_t *cred) { static const gss_OID_desc req_oid = { GSS_KRB5_IMPORT_CRED_OID_LENGTH, GSS_KRB5_IMPORT_CRED_OID }; OM_uint32 major_status; struct krb5_gss_import_cred_req req; gss_buffer_desc req_buffer; if (cred == NULL) return GSS_S_CALL_INACCESSIBLE_WRITE; *cred = GSS_C_NO_CREDENTIAL; req.id = id; req.keytab_principal = keytab_principal; req.keytab = keytab; req_buffer.value = &req; req_buffer.length = sizeof(req); major_status = gss_set_cred_option(minor_status, cred, (gss_OID)&req_oid, &req_buffer); return major_status; }
OM_uint32 KRB5_CALLCONV gssspi_set_cred_option(OM_uint32 *minor_status, gss_cred_id_t cred, const gss_OID desired_object, const gss_buffer_t value) { return gss_set_cred_option(minor_status, &cred, desired_object, value); }
OM_uint32 gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status, gss_cred_id_t cred, OM_uint32 num_enctypes, int32_t *enctypes) { krb5_error_code ret; OM_uint32 maj_status; gss_buffer_desc buffer; krb5_storage *sp; krb5_data data; int i; sp = krb5_storage_emem(); if (sp == NULL) { *minor_status = ENOMEM; maj_status = GSS_S_FAILURE; goto out; } for (i = 0; i < num_enctypes; i++) { ret = krb5_store_int32(sp, enctypes[i]); if (ret) { *minor_status = ret; maj_status = GSS_S_FAILURE; goto out; } } ret = krb5_storage_to_data(sp, &data); if (ret) { *minor_status = ret; maj_status = GSS_S_FAILURE; goto out; } buffer.value = data.data; buffer.length = data.length; maj_status = gss_set_cred_option(minor_status, &cred, GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X, &buffer); krb5_data_free(&data); out: if (sp) krb5_storage_free(sp); return maj_status; }
OM_uint32 GSSAPI_CALLCONV _gss_spnego_set_cred_option (OM_uint32 *minor_status, gss_cred_id_t *cred_handle, const gss_OID object, const gss_buffer_t value) { if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) { *minor_status = 0; return GSS_S_NO_CRED; } return gss_set_cred_option(minor_status, cred_handle, object, value); }
OM_uint32 _gss_spnego_set_cred_option (OM_uint32 *minor_status, gss_cred_id_t *cred_handle, const gss_OID object, const gss_buffer_t value) { gssspnego_cred cred; if (cred_handle == NULL || *cred_handle == GSS_C_NO_CREDENTIAL) { *minor_status = 0; return GSS_S_NO_CRED; } cred = (gssspnego_cred)*cred_handle; return gss_set_cred_option(minor_status, &cred->negotiated_cred_id, object, value); }
OM_uint32 KRB5_CALLCONV gss_krb5_set_cred_rcache(OM_uint32 *minor_status, gss_cred_id_t cred, krb5_rcache rcache) { static const gss_OID_desc req_oid = { GSS_KRB5_SET_CRED_RCACHE_OID_LENGTH, GSS_KRB5_SET_CRED_RCACHE_OID }; OM_uint32 major_status; gss_buffer_desc req_buffer; req_buffer.length = sizeof(rcache); req_buffer.value = rcache; major_status = gss_set_cred_option(minor_status, &cred, (gss_OID)&req_oid, &req_buffer); return major_status; }
OM_uint32 KRB5_CALLCONV gss_krb5_copy_ccache(OM_uint32 *minor_status, gss_cred_id_t cred_handle, krb5_ccache out_ccache) { static const gss_OID_desc req_oid = { GSS_KRB5_COPY_CCACHE_OID_LENGTH, GSS_KRB5_COPY_CCACHE_OID }; OM_uint32 major_status; gss_buffer_desc req_buffer; if (out_ccache == NULL) return GSS_S_CALL_INACCESSIBLE_WRITE; req_buffer.value = out_ccache; req_buffer.length = sizeof(out_ccache); major_status = gss_set_cred_option(minor_status, &cred_handle, (gss_OID)&req_oid, &req_buffer); return major_status; }
_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, struct tevent_context *event_ctx, struct loadparm_context *lp_ctx, struct gssapi_creds_container **_gcc, const char **error_string) { int ret = 0; OM_uint32 maj_stat, min_stat; struct gssapi_creds_container *gcc; struct ccache_container *ccache; #ifdef SAMBA4_USES_HEIMDAL gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; #endif krb5_enctype *etypes = NULL; if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold && cred->client_gss_creds_obtained > CRED_UNINITIALISED) { bool expired = false; OM_uint32 lifetime = 0; gss_cred_usage_t usage = 0; maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds, NULL, &lifetime, &usage, NULL); if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) { DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred))); expired = true; } else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) { DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime)); expired = true; } else if (maj_stat != GSS_S_COMPLETE) { *error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n", gssapi_error_string(cred, maj_stat, min_stat, NULL)); return EINVAL; } if (expired) { cli_credentials_unconditionally_invalidate_client_gss_creds(cred); } else { DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n", cli_credentials_get_principal(cred, cred), (unsigned int)lifetime)); *_gcc = cred->client_gss_creds; return 0; } } ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, &ccache, error_string); if (ret) { if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) { DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string)); } else { DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string)); } return ret; } gcc = talloc(cred, struct gssapi_creds_container); if (!gcc) { (*error_string) = error_message(ENOMEM); return ENOMEM; } maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, &gcc->creds); if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) { /* This CCACHE is no good. Ensure we don't use it again */ cli_credentials_unconditionally_invalidate_ccache(cred); /* Now try again to get a ccache */ ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, &ccache, error_string); if (ret) { DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret))); return ret; } maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, &gcc->creds); } if (maj_stat) { talloc_free(gcc); if (min_stat) { ret = min_stat; } else { ret = EINVAL; } (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret)); return ret; } /* * transfer the enctypes from the smb_krb5_context to the gssapi layer * * We use 'our' smb_krb5_context to do the AS-REQ and it is possible * to configure the enctypes via the krb5.conf. * * And the gss_init_sec_context() creates it's own krb5_context and * the TGS-REQ had all enctypes in it and only the ones configured * and used for the AS-REQ, so it wasn't possible to disable the usage * of AES keys. */ min_stat = get_kerberos_allowed_etypes(ccache->smb_krb5_context->krb5_context, &etypes); if (min_stat == 0) { OM_uint32 num_ktypes; for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++); maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds, num_ktypes, (int32_t *) etypes); SAFE_FREE(etypes); if (maj_stat) { talloc_free(gcc); if (min_stat) { ret = min_stat; } else { ret = EINVAL; } (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret)); return ret; } } #ifdef SAMBA4_USES_HEIMDAL /* MIT lacks GSS_KRB5_CRED_NO_CI_FLAGS_X */ /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */ maj_stat = gss_set_cred_option(&min_stat, &gcc->creds, GSS_KRB5_CRED_NO_CI_FLAGS_X, &empty_buffer); if (maj_stat) { talloc_free(gcc); if (min_stat) { ret = min_stat; } else { ret = EINVAL; } (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret)); return ret; } #endif cred->client_gss_creds_obtained = cred->ccache_obtained; talloc_set_destructor(gcc, free_gssapi_creds); cred->client_gss_creds = gcc; *_gcc = gcc; return 0; }
OM_uint32 gss_krb5_import_cred(OM_uint32 *minor_status, krb5_ccache id, krb5_principal keytab_principal, krb5_keytab keytab, gss_cred_id_t *cred) { gss_buffer_desc buffer; OM_uint32 major_status; krb5_context context; krb5_error_code ret; krb5_storage *sp; krb5_data data; char *str; *cred = GSS_C_NO_CREDENTIAL; ret = krb5_init_context(&context); if (ret) { *minor_status = ret; return GSS_S_FAILURE; } sp = krb5_storage_emem(); if (sp == NULL) { *minor_status = ENOMEM; major_status = GSS_S_FAILURE; goto out; } if (id) { ret = krb5_cc_get_full_name(context, id, &str); if (ret == 0) { ret = krb5_store_string(sp, str); free(str); } } else ret = krb5_store_string(sp, ""); if (ret) { *minor_status = ret; major_status = GSS_S_FAILURE; goto out; } if (keytab_principal) { ret = krb5_unparse_name(context, keytab_principal, &str); if (ret == 0) { ret = krb5_store_string(sp, str); free(str); } } else krb5_store_string(sp, ""); if (ret) { *minor_status = ret; major_status = GSS_S_FAILURE; goto out; } if (keytab) { ret = krb5_kt_get_full_name(context, keytab, &str); if (ret == 0) { ret = krb5_store_string(sp, str); free(str); } } else krb5_store_string(sp, ""); if (ret) { *minor_status = ret; major_status = GSS_S_FAILURE; goto out; } ret = krb5_storage_to_data(sp, &data); if (ret) { *minor_status = ret; major_status = GSS_S_FAILURE; goto out; } buffer.value = data.data; buffer.length = data.length; major_status = gss_set_cred_option(minor_status, cred, GSS_KRB5_IMPORT_CRED_X, &buffer); krb5_data_free(&data); out: if (sp) krb5_storage_free(sp); krb5_free_context(context); return major_status; }
DWORD VMCARpcCreateSrpAuthIdentity( PCSTR user, PCSTR domain, PCSTR password, PSTR *retUpn, rpc_auth_identity_handle_t *rpc_identity_h ) { OM_uint32 min = 0; OM_uint32 maj = 0; const gss_OID_desc gss_srp_password_oid = {GSSAPI_SRP_CRED_OPT_PW_LEN, (void *) GSSAPI_SRP_CRED_OPT_PW}; const gss_OID_desc spnego_mech_oid = {SPNEGO_OID_LENGTH, (void *) SPNEGO_OID}; gss_buffer_desc name_buf = {0}; gss_name_t gss_name_buf = NULL; gss_buffer_desc gss_pwd = {0}; size_t upn_len = 0; char *upn = NULL; gss_cred_id_t cred_handle = NULL; gss_OID_desc mech_oid_array[1]; gss_OID_set_desc desired_mech = {0}; if (domain) { /* user@DOMAIN\0 */ upn_len = strlen(user) + 1 + strlen(domain) + 1; upn = calloc(upn_len, sizeof(char)); if (!upn) { maj = GSS_S_FAILURE; min = ENOMEM; } snprintf(upn, upn_len, "%s@%s", user, domain); } else { /* Assume a UPN-like name form when no domain is provided */ upn = strdup((char *) user); if (!upn) { maj = GSS_S_FAILURE; min = ENOMEM; } } name_buf.value = upn; name_buf.length = strlen(name_buf.value); maj = gss_import_name( &min, &name_buf, GSS_C_NT_USER_NAME, &gss_name_buf); if (maj) { goto error; } /* * Hard code desired mech OID to SRP */ desired_mech.count = 1; desired_mech.elements = mech_oid_array; desired_mech.elements[0] = spnego_mech_oid; maj = gss_acquire_cred( &min, gss_name_buf, 0, &desired_mech, GSS_C_INITIATE, &cred_handle, NULL, NULL); if (maj) { goto error; } gss_pwd.value = (char *) password; gss_pwd.length = strlen(gss_pwd.value); maj = gss_set_cred_option( &min, &cred_handle, (gss_OID) &gss_srp_password_oid, &gss_pwd); if (maj) { goto error; } *retUpn = upn; upn = NULL; *rpc_identity_h = (rpc_auth_identity_handle_t) cred_handle; error: if (maj) { maj = min ? min : maj; } if (upn) { free(upn); } if (gss_name_buf) { gss_release_name(&min, &gss_name_buf); } return (DWORD) maj; }
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); }
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; }
INTERNAL void rpc__ntlmauth_bnd_set_auth ( unsigned_char_p_t server_name, rpc_authn_level_t level, rpc_authn_flags_t flags, rpc_auth_identity_handle_t auth_ident, rpc_authz_protocol_id_t authz_prot, rpc_binding_handle_t binding_h, rpc_auth_info_p_t *infop, unsigned32 *stp ) { unsigned32 st = rpc_s_ok; rpc_ntlmssp_auth_ident_t_p auth_info = NULL; rpc_ntlmauth_info_p_t ntlmauth_info = NULL; gss_name_t gss_server_name = {0}; unsigned char *str_server_name = NULL; gss_buffer_desc username_buf = {0}; gss_name_t gss_user_name = NULL; int gss_rc = 0; OM_uint32 minor_status = 0; gss_OID_set_desc desired_mech; gss_OID_set ret_mech; gss_cred_id_t cred_handle = GSS_C_NO_CREDENTIAL; OM_uint32 time_rec = 0; gss_OID_desc gss_ntlm_oid_desc = {0}; gss_OID_desc gss_cred_opt_password_oid_desc = {0}; gss_buffer_desc auth_buffer = {0}; RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_ROUTINE_TRACE, ("(rpc__gssauth_bnd_set_auth)\n")); rpc_g_ntlmauth_alloc_count++; RPC_MEM_ALLOC(ntlmauth_info, rpc_ntlmauth_info_p_t, sizeof (*ntlmauth_info), RPC_C_MEM_NTLMAUTH_INFO, RPC_C_MEM_WAITOK); memset(ntlmauth_info, 0, sizeof(*ntlmauth_info)); if (authz_prot != rpc_c_authz_name) { st = rpc_s_authn_authz_mismatch; goto poison; } if ((level != rpc_c_authn_level_connect) && (level != rpc_c_authn_level_pkt_integrity) && (level != rpc_c_authn_level_pkt_privacy)) { st = rpc_s_unsupported_authn_level; goto poison; } if (flags & (~rpc_c_protect_flags_header_sign)) { st = rpc_s_unsupported_protect_level; goto poison; } // Header signing extension has to be enabled in ntlmssp flags |= rpc_c_protect_flags_header_sign; if (server_name == NULL || auth_ident == NULL) { st = rpc_s_invalid_arg; goto poison; } auth_info = (rpc_ntlmssp_auth_ident_t_p)auth_ident; if (authz_prot == rpc_c_authz_name) { gss_buffer_desc input_name; /* GSS_KRB5_NT_PRINCIPAL_NAME */ gss_OID_desc nt_principal = {10, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"}; int gss_rc = 0; OM_uint32 minor_status = 0; if (server_name == NULL) { rpc_mgmt_inq_server_princ_name(binding_h, rpc_c_authn_winnt, &str_server_name, &st); if (st != rpc_s_ok) { goto poison; } } else { str_server_name = rpc_stralloc(server_name); } input_name.value = (void *)str_server_name; input_name.length = strlen((char *)str_server_name); gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &gss_server_name); if (gss_rc != GSS_S_COMPLETE) { char msg[256] = {0}; rpc__ntlmauth_error_map(gss_rc, minor_status, GSS_C_NO_OID, msg, sizeof(msg), &st); RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL, ("(rpc__gssauth_bnd_set_auth): import: %s\n", msg)); goto poison; } } gss_ntlm_oid_desc.length = GSS_MECH_NTLM_LEN; gss_ntlm_oid_desc.elements = GSS_MECH_NTLM; gss_cred_opt_password_oid_desc.length = GSS_CRED_OPT_PW_LEN; gss_cred_opt_password_oid_desc.elements = GSS_CRED_OPT_PW; username_buf.value = auth_info->User; username_buf.length = auth_info->UserLength; gss_rc = gss_import_name(&minor_status, &username_buf, GSS_C_NT_USER_NAME, &gss_user_name); if (gss_rc != GSS_S_COMPLETE) { char msg[256] = {0}; rpc__ntlmauth_error_map(gss_rc, minor_status, GSS_C_NO_OID, msg, sizeof(msg), &st); RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL, ("(rpc__ntlmauth_bnd_set_auth): import: %s\n", msg)); goto poison; } desired_mech.elements = (gss_OID)&gss_ntlm_oid_desc; desired_mech.count = 1; gss_rc = gss_acquire_cred(&minor_status, gss_user_name, 0, &desired_mech, GSS_C_INITIATE, &cred_handle, &ret_mech, &time_rec); if (gss_rc != GSS_S_COMPLETE) { char msg[256] = {0}; rpc__ntlmauth_error_map(gss_rc, minor_status, GSS_C_NO_OID, msg, sizeof(msg), &st); RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL, ("(rpc__ntlmauth_bnd_set_auth): import: %s\n", msg)); goto poison; } auth_buffer.value = auth_info; auth_buffer.length = sizeof(*auth_info); gss_rc = gss_set_cred_option(&minor_status, &cred_handle, (gss_OID)&gss_cred_opt_password_oid_desc, &auth_buffer); if (gss_rc != GSS_S_COMPLETE) { char msg[256] = {0}; rpc__ntlmauth_error_map(gss_rc, minor_status, GSS_C_NO_OID, msg, sizeof(msg), &st); RPC_DBG_PRINTF(rpc_e_dbg_auth, RPC_C_CN_DBG_AUTH_GENERAL, ("(rpc__ntlmauth_bnd_set_auth): import: %s\n", msg)); goto poison; } ntlmauth_info->auth_info.server_princ_name = str_server_name; ntlmauth_info->auth_info.authn_level = level; ntlmauth_info->auth_info.authn_flags = flags; ntlmauth_info->auth_info.authn_protocol = rpc_c_authn_winnt; ntlmauth_info->auth_info.authz_protocol = authz_prot; ntlmauth_info->auth_info.is_server = 0; ntlmauth_info->auth_info.u.auth_identity = auth_ident; ntlmauth_info->auth_info.refcount = 1; ntlmauth_info->gss_server_name = gss_server_name; ntlmauth_info->gss_creds = cred_handle; if (gss_user_name) { gss_release_name(&minor_status, &gss_user_name); } *infop = &ntlmauth_info->auth_info; *stp = st; return; poison: *infop = NULL; *stp = st; return; }