/**************************************************************************** Do a specific test for an smb password being correct, given a smb_password and the lanman and NT responses. ****************************************************************************/ static NTSTATUS authsam_password_ok(struct auth4_context *auth_context, TALLOC_CTX *mem_ctx, uint16_t acct_flags, const struct samr_Password *lm_pwd, const struct samr_Password *nt_pwd, const struct auth_usersupplied_info *user_info, DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) { NTSTATUS status; switch (user_info->password_state) { case AUTH_PASSWORD_PLAIN: { const struct auth_usersupplied_info *user_info_temp; status = encrypt_user_info(mem_ctx, auth_context, AUTH_PASSWORD_HASH, user_info, &user_info_temp); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status))); return status; } user_info = user_info_temp; FALL_THROUGH; } case AUTH_PASSWORD_HASH: *lm_sess_key = data_blob(NULL, 0); *user_sess_key = data_blob(NULL, 0); status = hash_password_check(mem_ctx, lpcfg_lanman_auth(auth_context->lp_ctx), user_info->password.hash.lanman, user_info->password.hash.nt, user_info->mapped.account_name, lm_pwd, nt_pwd); NT_STATUS_NOT_OK_RETURN(status); break; case AUTH_PASSWORD_RESPONSE: status = ntlm_password_check(mem_ctx, lpcfg_lanman_auth(auth_context->lp_ctx), lpcfg_ntlm_auth(auth_context->lp_ctx), user_info->logon_parameters, &auth_context->challenge.data, &user_info->password.response.lanman, &user_info->password.response.nt, user_info->mapped.account_name, user_info->client.account_name, user_info->client.domain_name, lm_pwd, nt_pwd, user_sess_key, lm_sess_key); NT_STATUS_NOT_OK_RETURN(status); break; } return NT_STATUS_OK; }
NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, enum auth_password_state to_state, const struct auth_usersupplied_info *user_info_in, const struct auth_usersupplied_info **user_info_encrypted) { NTSTATUS nt_status; struct auth_usersupplied_info *user_info_temp; switch (to_state) { case AUTH_PASSWORD_RESPONSE: switch (user_info_in->password_state) { case AUTH_PASSWORD_PLAIN: { const struct auth_usersupplied_info *user_info_temp2; nt_status = encrypt_user_info(mem_ctx, auth_context, AUTH_PASSWORD_HASH, user_info_in, &user_info_temp2); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } user_info_in = user_info_temp2; /* fall through */ } case AUTH_PASSWORD_HASH: { const uint8_t *challenge; DATA_BLOB chall_blob; user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); if (!user_info_temp) { return NT_STATUS_NO_MEMORY; } if (!talloc_reference(user_info_temp, user_info_in)) { return NT_STATUS_NO_MEMORY; } *user_info_temp = *user_info_in; user_info_temp->mapped_state = to_state; nt_status = auth_get_challenge(auth_context, &challenge); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } chall_blob = data_blob_talloc(mem_ctx, challenge, 8); if (lp_client_ntlmv2_auth(auth_context->lp_ctx)) { DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx)); DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key; if (!SMBNTLMv2encrypt_hash(user_info_temp, user_info_in->client.account_name, user_info_in->client.domain_name, user_info_in->password.hash.nt->hash, &chall_blob, &names_blob, &lmv2_response, &ntlmv2_response, &lmv2_session_key, &ntlmv2_session_key)) { data_blob_free(&names_blob); return NT_STATUS_NO_MEMORY; } data_blob_free(&names_blob); user_info_temp->password.response.lanman = lmv2_response; user_info_temp->password.response.nt = ntlmv2_response; data_blob_free(&lmv2_session_key); data_blob_free(&ntlmv2_session_key); } else { DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24); SMBOWFencrypt(user_info_in->password.hash.nt->hash, challenge, blob.data); user_info_temp->password.response.nt = blob; if (lp_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) { DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24); SMBOWFencrypt(user_info_in->password.hash.lanman->hash, challenge, blob.data); user_info_temp->password.response.lanman = lm_blob; } else { /* if not sending the LM password, send the NT password twice */ user_info_temp->password.response.lanman = user_info_temp->password.response.nt; } } user_info_in = user_info_temp; /* fall through */ } case AUTH_PASSWORD_RESPONSE: *user_info_encrypted = user_info_in; } break; case AUTH_PASSWORD_HASH: { switch (user_info_in->password_state) { case AUTH_PASSWORD_PLAIN: { struct samr_Password lanman; struct samr_Password nt; user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); if (!user_info_temp) { return NT_STATUS_NO_MEMORY; } if (!talloc_reference(user_info_temp, user_info_in)) { return NT_STATUS_NO_MEMORY; } *user_info_temp = *user_info_in; user_info_temp->mapped_state = to_state; if (E_deshash(user_info_in->password.plaintext, lanman.hash)) { user_info_temp->password.hash.lanman = talloc(user_info_temp, struct samr_Password); *user_info_temp->password.hash.lanman = lanman; } else { user_info_temp->password.hash.lanman = NULL; } E_md4hash(user_info_in->password.plaintext, nt.hash); user_info_temp->password.hash.nt = talloc(user_info_temp, struct samr_Password); *user_info_temp->password.hash.nt = nt; user_info_in = user_info_temp; /* fall through */ } case AUTH_PASSWORD_HASH: *user_info_encrypted = user_info_in; break; default: return NT_STATUS_INVALID_PARAMETER; break; } break; }
/* Authenticate a user with a challenge/response using the samba3 winbind protocol */ static NTSTATUS winbind_check_password_samba3(struct auth_method_context *ctx, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) { struct winbindd_request request; struct winbindd_response response; NSS_STATUS result; NTSTATUS nt_status; struct netr_SamInfo3 info3; /* Send off request */ const struct auth_usersupplied_info *user_info_temp; nt_status = encrypt_user_info(mem_ctx, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE, user_info, &user_info_temp); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } user_info = user_info_temp; ZERO_STRUCT(request); ZERO_STRUCT(response); request.flags = WBFLAG_PAM_INFO3_NDR; request.data.auth_crap.logon_parameters = user_info->logon_parameters; safe_strcpy(request.data.auth_crap.user, user_info->client.account_name, sizeof(fstring)); safe_strcpy(request.data.auth_crap.domain, user_info->client.domain_name, sizeof(fstring)); safe_strcpy(request.data.auth_crap.workstation, user_info->workstation_name, sizeof(fstring)); memcpy(request.data.auth_crap.chal, ctx->auth_ctx->challenge.data.data, sizeof(request.data.auth_crap.chal)); request.data.auth_crap.lm_resp_len = MIN(user_info->password.response.lanman.length, sizeof(request.data.auth_crap.lm_resp)); request.data.auth_crap.nt_resp_len = MIN(user_info->password.response.nt.length, sizeof(request.data.auth_crap.nt_resp)); memcpy(request.data.auth_crap.lm_resp, user_info->password.response.lanman.data, request.data.auth_crap.lm_resp_len); memcpy(request.data.auth_crap.nt_resp, user_info->password.response.nt.data, request.data.auth_crap.nt_resp_len); result = winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response); nt_status = NT_STATUS(response.data.auth.nt_status); NT_STATUS_NOT_OK_RETURN(nt_status); if (result == NSS_STATUS_SUCCESS && response.extra_data.data) { union netr_Validation validation; nt_status = get_info3_from_ndr(mem_ctx, lp_iconv_convenience(ctx->auth_ctx->lp_ctx), &response, &info3); SAFE_FREE(response.extra_data.data); NT_STATUS_NOT_OK_RETURN(nt_status); validation.sam3 = &info3; nt_status = make_server_info_netlogon_validation(mem_ctx, user_info->client.account_name, 3, &validation, server_info); return nt_status; } else if (result == NSS_STATUS_SUCCESS && !response.extra_data.data) { DEBUG(0, ("Winbindd authenticated the user [%s]\\[%s], " "but did not include the required info3 reply!\n", user_info->client.domain_name, user_info->client.account_name)); return NT_STATUS_INSUFFICIENT_LOGON_INFO; } else if (NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("Winbindd authentication for [%s]\\[%s] failed, " "but no error code is available!\n", user_info->client.domain_name, user_info->client.account_name)); return NT_STATUS_NO_LOGON_SERVERS; } return nt_status; }