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 = gssspi_set_cred_option(minor_status, cred, (gss_OID)&req_oid, &req_buffer); return major_status; }
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 = gssspi_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 = gssspi_set_cred_option(minor_status, cred_handle, (gss_OID)&req_oid, &req_buffer); return major_status; }
INTERNAL void rpc__ntlmauth_bnd_set_auth ( unsigned_char_p_t server_name, rpc_authn_level_t level, 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 (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 = gssspi_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_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; }
DWORD SMBGSSContextBuild( PCWSTR pwszServerName, PIO_CREDS pCreds, PHANDLE phSMBGSSContext ) { DWORD dwError = 0; DWORD dwMajorStatus = 0; DWORD dwMinorStatus = 0; PSMB_GSS_SEC_CONTEXT pContext = NULL; PSTR pszTargetName = NULL; PSTR pszServerName = NULL; PSTR pszUsername = NULL; PSTR pszDomain = NULL; PSTR pszPassword = NULL; gss_buffer_desc usernameBuffer = {0}; gss_buffer_desc inputNameBuffer = {0}; gss_buffer_desc authDataBuffer = {0}; gss_name_t pUsername = NULL; gss_OID_set_desc desiredMechs; gss_OID_set actualMechs; OM_uint32 timeRec = 0; SEC_WINNT_AUTH_IDENTITY authData; static gss_OID_desc gssCredOptionPasswordOidDesc = { .length = GSS_CRED_OPT_PW_LEN, .elements = GSS_CRED_OPT_PW }; static gss_OID_desc gssNtlmOidDesc = { .length = GSS_MECH_NTLM_LEN, .elements = GSS_MECH_NTLM }; size_t sCopyServerChars = 0; dwError = LwRtlCStringAllocateFromWC16String(&pszServerName, pwszServerName); BAIL_ON_LWIO_ERROR(dwError); LWIO_LOG_DEBUG("Build GSS Context for server [%s]", LWIO_SAFE_LOG_STRING(pszServerName)); dwError = LwIoAllocateMemory( sizeof(SMB_GSS_SEC_CONTEXT), (PVOID*)&pContext); BAIL_ON_LWIO_ERROR(dwError); pContext->state = SMB_GSS_SEC_CONTEXT_STATE_INITIAL; if (pCreds) { switch (pCreds->type) { case IO_CREDS_TYPE_KRB5_CCACHE: dwError = STATUS_ACCESS_DENIED; BAIL_ON_LWIO_ERROR(dwError); break; case IO_CREDS_TYPE_KRB5_TGT: sCopyServerChars = strlen(pszServerName); if (sCopyServerChars > 0 && pszServerName[sCopyServerChars - 1] == '.') { // Strip the trailing dot sCopyServerChars --; } if (sCopyServerChars > INT_MAX) { dwError = STATUS_INTEGER_OVERFLOW; BAIL_ON_LWIO_ERROR(dwError); } dwError = SMBAllocateStringPrintf( &pszTargetName, "cifs/%.*s@", (int)sCopyServerChars, pszServerName); BAIL_ON_LWIO_ERROR(dwError); inputNameBuffer.value = pszTargetName; inputNameBuffer.length = strlen(pszTargetName) + 1; dwMajorStatus = gss_import_name( (OM_uint32 *)&dwMinorStatus, &inputNameBuffer, (gss_OID) gss_nt_krb5_name, &pContext->target_name); smb_display_status("gss_import_name", dwMajorStatus, dwMinorStatus); BAIL_ON_SEC_ERROR(dwMajorStatus); dwError = LwRtlCStringAllocateFromWC16String( &pszUsername, pCreds->payload.krb5Tgt.pwszClientPrincipal); BAIL_ON_NT_STATUS(dwError); usernameBuffer.value = pszUsername; usernameBuffer.length = strlen(pszUsername) + 1; dwMajorStatus = gss_import_name( (OM_uint32 *)&dwMinorStatus, &usernameBuffer, GSS_C_NT_USER_NAME, &pUsername); BAIL_ON_SEC_ERROR(dwMajorStatus); desiredMechs.count = 1; desiredMechs.elements = (gss_OID) gss_mech_krb5; dwMajorStatus = gss_acquire_cred( (OM_uint32 *)&dwMinorStatus, pUsername, 0, &desiredMechs, GSS_C_INITIATE, &pContext->credHandle, &actualMechs, &timeRec); BAIL_ON_SEC_ERROR(dwMajorStatus); break; case IO_CREDS_TYPE_PLAIN: inputNameBuffer.value = (void*) "unset"; inputNameBuffer.length = strlen("unset"); dwMajorStatus = gss_import_name( (OM_uint32 *)&dwMinorStatus, &inputNameBuffer, (gss_OID) gss_nt_krb5_name, &pContext->target_name); smb_display_status("gss_import_name", dwMajorStatus, dwMinorStatus); BAIL_ON_SEC_ERROR(dwMajorStatus); if (pCreds->payload.plain.pwszUsername) { dwError = LwRtlCStringAllocateFromWC16String(&pszUsername, pCreds->payload.plain.pwszUsername); BAIL_ON_LWIO_ERROR(dwError); usernameBuffer.value = pszUsername; usernameBuffer.length = strlen(pszUsername); // If "" is passed in, that means to use anonymous // authentication. gss_import_name fails on "" though if (usernameBuffer.length) { dwMajorStatus = gss_import_name( (OM_uint32 *)&dwMinorStatus, &usernameBuffer, GSS_C_NT_USER_NAME, &pUsername); BAIL_ON_SEC_ERROR(dwMajorStatus); } } desiredMechs.count = 1; desiredMechs.elements = (gss_OID) &gssNtlmOidDesc; dwMajorStatus = gss_acquire_cred( (OM_uint32 *)&dwMinorStatus, pUsername, 0, &desiredMechs, GSS_C_INITIATE, &pContext->credHandle, &actualMechs, &timeRec); BAIL_ON_SEC_ERROR(dwMajorStatus); if (pCreds->payload.plain.pwszUsername && pCreds->payload.plain.pwszPassword && pCreds->payload.plain.pwszDomain) { dwError = LwRtlCStringAllocateFromWC16String(&pszDomain, pCreds->payload.plain.pwszDomain); BAIL_ON_LWIO_ERROR(dwError); dwError = LwRtlCStringAllocateFromWC16String(&pszPassword, pCreds->payload.plain.pwszPassword); BAIL_ON_LWIO_ERROR(dwError); authData.User = pszUsername; authData.UserLength = strlen(pszUsername); authData.Domain = pszDomain; authData.DomainLength = strlen(pszDomain); authData.Password = pszPassword; authData.PasswordLength = strlen(pszPassword); authData.Flags = 0; authDataBuffer.value = &authData; authDataBuffer.length = sizeof(authData); dwMajorStatus = gssspi_set_cred_option( (OM_uint32 *)&dwMinorStatus, pContext->credHandle, (gss_OID) &gssCredOptionPasswordOidDesc, &authDataBuffer); BAIL_ON_SEC_ERROR(dwMajorStatus); } break; } } dwError = LwIoAllocateMemory( sizeof(CtxtHandle), (PVOID*)&pContext->pGSSContext); BAIL_ON_LWIO_ERROR(dwError); *pContext->pGSSContext = GSS_C_NO_CONTEXT; *phSMBGSSContext = (HANDLE)pContext; cleanup: if (pUsername != NULL) { gss_release_name((OM_uint32 *)&dwMinorStatus, &pUsername); } LWIO_SAFE_FREE_STRING(pszTargetName); LWIO_SAFE_FREE_STRING(pszServerName); LWIO_SAFE_FREE_STRING(pszUsername); LWIO_SAFE_FREE_STRING(pszDomain); LWIO_SAFE_FREE_STRING(pszPassword); return dwError; sec_error: dwError = LWIO_ERROR_GSS; error: *phSMBGSSContext = NULL; if (pContext) { SMBGSSContextFree(pContext); } goto cleanup; }