2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Tridgell 1992-2000
5 Copyright (C) Luke Kenneth Casson Leighton 1996-2000
6 Copyright (C) Andrew Bartlett 2001
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #define DBGC_CLASS DBGC_AUTH
28 /****************************************************************************
29 core of smb password checking routine.
30 ****************************************************************************/
31 static BOOL smb_pwd_check_ntlmv1(const DATA_BLOB *nt_response,
32 const uchar *part_passwd,
33 const DATA_BLOB *sec_blob,
34 uint8 user_sess_key[16])
36 /* Finish the encryption of part_passwd. */
39 if (part_passwd == NULL) {
40 DEBUG(10,("No password set - DISALLOWING access\n"));
41 /* No password set - always false ! */
45 if (sec_blob->length != 8) {
46 DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%d)\n", sec_blob->length));
50 if (nt_response->length != 24) {
51 DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n", nt_response->length));
55 SMBOWFencrypt(part_passwd, sec_blob->data, p24);
56 if (user_sess_key != NULL)
58 SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key);
64 DEBUG(100,("Part password (P16) was |\n"));
65 dump_data(100, part_passwd, 16);
66 DEBUGADD(100,("Password from client was |\n"));
67 dump_data(100, nt_response->data, nt_response->length);
68 DEBUGADD(100,("Given challenge was |\n"));
69 dump_data(100, sec_blob->data, sec_blob->length);
70 DEBUGADD(100,("Value from encryption was |\n"));
71 dump_data(100, p24, 24);
73 return (memcmp(p24, nt_response->data, 24) == 0);
77 /****************************************************************************
78 core of smb password checking routine. (NTLMv2, LMv2)
80 Note: The same code works with both NTLMv2 and LMv2.
81 ****************************************************************************/
82 static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB *ntv2_response,
83 const uchar *part_passwd,
84 const DATA_BLOB *sec_blob,
85 const char *user, const char *domain,
86 uint8 user_sess_key[16])
88 /* Finish the encryption of part_passwd. */
90 uchar value_from_encryption[16];
91 uchar client_response[16];
92 DATA_BLOB client_key_data;
94 if (part_passwd == NULL)
96 DEBUG(10,("No password set - DISALLOWING access\n"));
97 /* No password set - always False */
101 if (ntv2_response->length < 24) {
102 /* We MUST have more than 16 bytes, or the stuff below will go
103 crazy. No known implementation sends less than the 24 bytes
104 for LMv2, let alone NTLMv2. */
105 DEBUG(0, ("smb_pwd_check_ntlmv2: incorrect password length (%d)\n",
106 ntv2_response->length));
110 client_key_data = data_blob(ntv2_response->data+16, ntv2_response->length-16);
112 todo: should we be checking this for anything? We can't for LMv2,
113 but for NTLMv2 it is meant to contain the current time etc.
116 memcpy(client_response, ntv2_response->data, sizeof(client_response));
118 if (!ntv2_owf_gen(part_passwd, user, domain, kr)) {
122 SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption);
123 if (user_sess_key != NULL)
125 SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key);
129 DEBUG(100,("Part password (P16) was |\n"));
130 dump_data(100, part_passwd, 16);
131 DEBUGADD(100,("Password from client was |\n"));
132 dump_data(100, ntv2_response->data, ntv2_response->length);
133 DEBUGADD(100,("Variable data from client was |\n"));
134 dump_data(100, client_key_data.data, client_key_data.length);
135 DEBUGADD(100,("Given challenge was |\n"));
136 dump_data(100, sec_blob->data, sec_blob->length);
137 DEBUGADD(100,("Value from encryption was |\n"));
138 dump_data(100, value_from_encryption, 16);
140 data_blob_clear_free(&client_key_data);
141 return (memcmp(value_from_encryption, client_response, 16) == 0);
145 /****************************************************************************
146 Do a specific test for an smb password being correct, given a smb_password and
147 the lanman and NT responses.
148 ****************************************************************************/
149 static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
151 SAM_ACCOUNT *sampass,
152 const auth_usersupplied_info *user_info,
153 uint8 user_sess_key[16])
156 const uint8 *nt_pw, *lm_pw;
159 acct_ctrl = pdb_get_acct_ctrl(sampass);
160 if (acct_ctrl & ACB_PWNOTREQ)
162 if (lp_null_passwords())
164 DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", pdb_get_username(sampass)));
165 return(NT_STATUS_OK);
169 DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", pdb_get_username(sampass)));
170 return(NT_STATUS_LOGON_FAILURE);
174 auth_flags = user_info->auth_flags;
176 if (IS_SAM_DEFAULT(sampass, PDB_NTPASSWD)) {
177 DEBUG(3,("sam_password_ok: NO NT password stored for user %s.\n",
178 pdb_get_username(sampass)));
179 /* No return, we want to check the LM hash below in this case */
180 auth_flags &= (~(AUTH_FLAG_NTLMv2_RESP | AUTH_FLAG_NTLM_RESP));
183 if (auth_flags & AUTH_FLAG_NTLMv2_RESP) {
184 nt_pw = pdb_get_nt_passwd(sampass);
185 /* We have the NT MD4 hash challenge available - see if we can
186 use it (ie. does it exist in the smbpasswd file).
188 DEBUG(4,("sam_password_ok: Checking NTLMv2 password with domain [%s]\n", user_info->client_domain.str));
189 if (smb_pwd_check_ntlmv2( &user_info->nt_resp,
190 nt_pw, &auth_context->challenge,
191 user_info->smb_name.str,
192 user_info->client_domain.str,
198 DEBUG(4,("sam_password_ok: Checking NTLMv2 password without a domain\n"));
199 if (smb_pwd_check_ntlmv2( &user_info->nt_resp,
200 nt_pw, &auth_context->challenge,
201 user_info->smb_name.str,
207 DEBUG(3,("sam_password_ok: NTLMv2 password check failed\n"));
208 return NT_STATUS_WRONG_PASSWORD;
210 } else if (auth_flags & AUTH_FLAG_NTLM_RESP) {
211 if (lp_ntlm_auth()) {
212 nt_pw = pdb_get_nt_passwd(sampass);
213 /* We have the NT MD4 hash challenge available - see if we can
214 use it (ie. does it exist in the smbpasswd file).
216 DEBUG(4,("sam_password_ok: Checking NT MD4 password\n"));
217 if (smb_pwd_check_ntlmv1(&user_info->nt_resp,
218 nt_pw, &auth_context->challenge,
223 DEBUG(3,("sam_password_ok: NT MD4 password check failed for user %s\n",pdb_get_username(sampass)));
224 return NT_STATUS_WRONG_PASSWORD;
227 DEBUG(2,("sam_password_ok: NTLMv1 passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
228 /* no return, because we might pick up LMv2 in the LM feild */
232 if (auth_flags & AUTH_FLAG_LM_RESP) {
233 if (user_info->lm_resp.length != 24) {
234 DEBUG(2,("sam_password_ok: invalid LanMan password length (%d) for user %s\n",
235 user_info->nt_resp.length, pdb_get_username(sampass)));
238 if (!lp_lanman_auth()) {
239 DEBUG(3,("sam_password_ok: Lanman passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
240 } else if (IS_SAM_DEFAULT(sampass, PDB_LMPASSWD)) {
241 DEBUG(3,("sam_password_ok: NO LanMan password set for user %s (and no NT password supplied)\n",pdb_get_username(sampass)));
243 lm_pw = pdb_get_lanman_passwd(sampass);
245 DEBUG(4,("sam_password_ok: Checking LM password\n"));
246 if (smb_pwd_check_ntlmv1(&user_info->lm_resp,
247 lm_pw, &auth_context->challenge,
254 if (IS_SAM_DEFAULT(sampass, PDB_NTPASSWD)) {
255 DEBUG(4,("sam_password_ok: LM password check failed for user, no NT password %s\n",pdb_get_username(sampass)));
256 return NT_STATUS_WRONG_PASSWORD;
259 nt_pw = pdb_get_nt_passwd(sampass);
261 /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes.
262 - related to Win9X, legacy NAS pass-though authentication
264 DEBUG(4,("sam_password_ok: Checking LMv2 password with domain %s\n", user_info->client_domain.str));
265 if (smb_pwd_check_ntlmv2( &user_info->lm_resp,
266 nt_pw, &auth_context->challenge,
267 user_info->smb_name.str,
268 user_info->client_domain.str,
274 DEBUG(4,("sam_password_ok: Checking LMv2 password without a domain\n"));
275 if (smb_pwd_check_ntlmv2( &user_info->lm_resp,
276 nt_pw, &auth_context->challenge,
277 user_info->smb_name.str,
284 /* Apparently NT accepts NT responses in the LM field
285 - I think this is related to Win9X pass-though authentication
287 DEBUG(4,("sam_password_ok: Checking NT MD4 password in LM field\n"));
290 if (smb_pwd_check_ntlmv1(&user_info->lm_resp,
291 nt_pw, &auth_context->challenge,
296 DEBUG(3,("sam_password_ok: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",pdb_get_username(sampass)));
297 return NT_STATUS_WRONG_PASSWORD;
299 DEBUG(3,("sam_password_ok: LM password and LMv2 failed for user %s, and NT MD4 password in LM field not permitted\n",pdb_get_username(sampass)));
300 return NT_STATUS_WRONG_PASSWORD;
305 /* Should not be reached, but if they send nothing... */
306 DEBUG(3,("sam_password_ok: NEITHER LanMan nor NT password supplied for user %s\n",pdb_get_username(sampass)));
307 return NT_STATUS_WRONG_PASSWORD;
310 /****************************************************************************
311 Do a specific test for a SAM_ACCOUNT being vaild for this connection
312 (ie not disabled, expired and the like).
313 ****************************************************************************/
314 static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx,
315 SAM_ACCOUNT *sampass,
316 const auth_usersupplied_info *user_info)
318 uint16 acct_ctrl = pdb_get_acct_ctrl(sampass);
319 char *workstation_list;
322 DEBUG(4,("sam_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass)));
324 /* Quit if the account was disabled. */
325 if (acct_ctrl & ACB_DISABLED) {
326 DEBUG(1,("Account for user '%s' was disabled.\n", pdb_get_username(sampass)));
327 return NT_STATUS_ACCOUNT_DISABLED;
330 /* Test account expire time */
332 kickoff_time = pdb_get_kickoff_time(sampass);
333 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
334 DEBUG(1,("Account for user '%s' has expried.\n", pdb_get_username(sampass)));
335 DEBUG(3,("Account expired at '%ld' unix time.\n", (long)kickoff_time));
336 return NT_STATUS_ACCOUNT_EXPIRED;
339 if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP)) {
340 time_t must_change_time = pdb_get_pass_must_change_time(sampass);
341 time_t last_set_time = pdb_get_pass_last_set_time(sampass);
343 /* check for immediate expiry "must change at next logon" */
344 if (must_change_time == 0 && last_set_time != 0) {
345 DEBUG(1,("Account for user '%s' password must change!.\n", pdb_get_username(sampass)));
346 return NT_STATUS_PASSWORD_MUST_CHANGE;
349 /* check for expired password */
350 if (must_change_time < time(NULL) && must_change_time != 0) {
351 DEBUG(1,("Account for user '%s' password expired!.\n", pdb_get_username(sampass)));
352 DEBUG(1,("Password expired at '%s' (%ld) unix time.\n", http_timestring(must_change_time), (long)must_change_time));
353 return NT_STATUS_PASSWORD_EXPIRED;
357 /* Test workstation. Workstation list is comma separated. */
359 workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass));
361 if (!workstation_list) return NT_STATUS_NO_MEMORY;
363 if (*workstation_list) {
364 BOOL invalid_ws = True;
365 const char *s = workstation_list;
369 while (next_token(&s, tok, ",", sizeof(tok))) {
370 DEBUG(10,("checking for workstation match %s and %s (len=%d)\n",
371 tok, user_info->wksta_name.str, user_info->wksta_name.len));
372 if(strequal(tok, user_info->wksta_name.str)) {
379 return NT_STATUS_INVALID_WORKSTATION;
382 if (acct_ctrl & ACB_DOMTRUST) {
383 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", pdb_get_username(sampass)));
384 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
387 if (acct_ctrl & ACB_SVRTRUST) {
388 DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", pdb_get_username(sampass)));
389 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
392 if (acct_ctrl & ACB_WSTRUST) {
393 DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", pdb_get_username(sampass)));
394 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
401 /****************************************************************************
402 check if a username/password is OK assuming the password is a 24 byte
403 SMB hash supplied in the user_info structure
404 return an NT_STATUS constant.
405 ****************************************************************************/
407 static NTSTATUS check_sam_security(const struct auth_context *auth_context,
408 void *my_private_data,
410 const auth_usersupplied_info *user_info,
411 auth_serversupplied_info **server_info)
413 SAM_ACCOUNT *sampass=NULL;
416 uint8 user_sess_key[16];
417 const uint8* lm_hash;
419 if (!user_info || !auth_context) {
420 return NT_STATUS_UNSUCCESSFUL;
423 /* Can't use the talloc version here, because the returned struct gets
424 kept on the server_info */
425 if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(&sampass))) {
429 /* get the account information */
432 ret = pdb_getsampwnam(sampass, user_info->internal_username.str);
437 DEBUG(3,("Couldn't find user '%s' in passdb file.\n", user_info->internal_username.str));
438 pdb_free_sam(&sampass);
439 return NT_STATUS_NO_SUCH_USER;
442 nt_status = sam_password_ok(auth_context, mem_ctx, sampass, user_info, user_sess_key);
444 if (!NT_STATUS_IS_OK(nt_status)) {
445 pdb_free_sam(&sampass);
449 nt_status = sam_account_ok(mem_ctx, sampass, user_info);
451 if (!NT_STATUS_IS_OK(nt_status)) {
452 pdb_free_sam(&sampass);
456 if (!NT_STATUS_IS_OK(nt_status = make_server_info_sam(server_info, sampass))) {
457 DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status)));
461 lm_hash = pdb_get_lanman_passwd((*server_info)->sam_account);
463 memcpy((*server_info)->first_8_lm_hash, lm_hash, 8);
466 memcpy((*server_info)->session_key, user_sess_key, sizeof(user_sess_key));
471 /* module initialisation */
472 NTSTATUS auth_init_sam(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
474 if (!make_auth_methods(auth_context, auth_method)) {
475 return NT_STATUS_NO_MEMORY;
478 (*auth_method)->auth = check_sam_security;
479 (*auth_method)->name = "sam";
484 /****************************************************************************
485 Check SAM security (above) but with a few extra checks.
486 ****************************************************************************/
488 static NTSTATUS check_samstrict_security(const struct auth_context *auth_context,
489 void *my_private_data,
491 const auth_usersupplied_info *user_info,
492 auth_serversupplied_info **server_info)
495 if (!user_info || !auth_context) {
496 return NT_STATUS_LOGON_FAILURE;
499 /* If we are a domain member, we must not
500 attempt to check the password locally,
501 unless it is one of our aliases. */
503 if (!is_myname(user_info->domain.str)) {
504 DEBUG(7,("The requested user domain is not the local server name. [%s]\\[%s]\n",
505 user_info->domain.str,user_info->internal_username.str));
506 return NT_STATUS_NO_SUCH_USER;
509 return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
512 /* module initialisation */
513 NTSTATUS auth_init_samstrict(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
515 if (!make_auth_methods(auth_context, auth_method)) {
516 return NT_STATUS_NO_MEMORY;
519 (*auth_method)->auth = check_samstrict_security;
520 (*auth_method)->name = "samstrict";
524 /****************************************************************************
525 Check SAM security (above) but with a few extra checks if we're a DC.
526 ****************************************************************************/
528 static NTSTATUS check_samstrict_dc_security(const struct auth_context *auth_context,
529 void *my_private_data,
531 const auth_usersupplied_info *user_info,
532 auth_serversupplied_info **server_info)
535 if (!user_info || !auth_context) {
536 return NT_STATUS_LOGON_FAILURE;
539 /* If we are a PDC we must not check the password here
540 unless it is one of our aliases, empty
541 or equal to our domain name. Other names may be
545 if ((!is_myworkgroup(user_info->domain.str))&&
546 (!is_myname(user_info->domain.str))) {
547 DEBUG(7,("The requested user domain is not the local server name or our domain. [%s]\\[%s]\n",
548 user_info->domain.str,user_info->internal_username.str));
549 return NT_STATUS_NO_SUCH_USER;
552 return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
555 /* module initialisation */
556 NTSTATUS auth_init_samstrict_dc(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
558 if (!make_auth_methods(auth_context, auth_method)) {
559 return NT_STATUS_NO_MEMORY;
562 (*auth_method)->auth = check_samstrict_dc_security;
563 (*auth_method)->name = "samstrict_dc";
567 NTSTATUS auth_sam_init(void)
569 smb_register_auth(AUTH_INTERFACE_VERSION, "samstrict_dc", auth_init_samstrict_dc);
570 smb_register_auth(AUTH_INTERFACE_VERSION, "samstrict", auth_init_samstrict);
571 smb_register_auth(AUTH_INTERFACE_VERSION, "sam", auth_init_sam);