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,
208 DEBUG(3,("sam_password_ok: NTLMv2 password check failed\n"));
209 return NT_STATUS_WRONG_PASSWORD;
211 } else if (auth_flags & AUTH_FLAG_NTLM_RESP) {
212 if (lp_ntlm_auth()) {
213 nt_pw = pdb_get_nt_passwd(sampass);
214 /* We have the NT MD4 hash challenge available - see if we can
215 use it (ie. does it exist in the smbpasswd file).
217 DEBUG(4,("sam_password_ok: Checking NT MD4 password\n"));
218 if (smb_pwd_check_ntlmv1(&user_info->nt_resp,
219 nt_pw, &auth_context->challenge,
224 DEBUG(3,("sam_password_ok: NT MD4 password check failed for user %s\n",pdb_get_username(sampass)));
225 return NT_STATUS_WRONG_PASSWORD;
228 DEBUG(2,("sam_password_ok: NTLMv1 passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
229 /* no return, becouse we might pick up LMv2 in the LM field */
233 if (auth_flags & AUTH_FLAG_LM_RESP) {
234 if (user_info->lm_resp.length != 24) {
235 DEBUG(2,("sam_password_ok: invalid LanMan password length (%d) for user %s\n",
236 user_info->nt_resp.length, pdb_get_username(sampass)));
239 if (!lp_lanman_auth()) {
240 DEBUG(3,("sam_password_ok: Lanman passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
241 } else if (IS_SAM_DEFAULT(sampass, PDB_LMPASSWD)) {
242 DEBUG(3,("sam_password_ok: NO LanMan password set for user %s (and no NT password supplied)\n",pdb_get_username(sampass)));
244 lm_pw = pdb_get_lanman_passwd(sampass);
246 DEBUG(4,("sam_password_ok: Checking LM password\n"));
247 if (smb_pwd_check_ntlmv1(&user_info->lm_resp,
248 lm_pw, &auth_context->challenge,
255 if (IS_SAM_DEFAULT(sampass, PDB_NTPASSWD)) {
256 DEBUG(4,("sam_password_ok: LM password check failed for user, no NT password %s\n",pdb_get_username(sampass)));
257 return NT_STATUS_WRONG_PASSWORD;
260 nt_pw = pdb_get_nt_passwd(sampass);
262 /* This is for 'LMv2' authentication. almost NTLMv2 but limited to 24 bytes.
263 - related to Win9X, legacy NAS pass-though authentication
265 DEBUG(4,("sam_password_ok: Checking LMv2 password with domain %s\n", user_info->client_domain.str));
266 if (smb_pwd_check_ntlmv2( &user_info->lm_resp,
267 nt_pw, &auth_context->challenge,
268 user_info->smb_name.str,
269 user_info->client_domain.str,
275 DEBUG(4,("sam_password_ok: Checking LMv2 password without a domain\n"));
276 if (smb_pwd_check_ntlmv2( &user_info->lm_resp,
277 nt_pw, &auth_context->challenge,
278 user_info->smb_name.str,
285 /* Apparently NT accepts NT responses in the LM field
286 - I think this is related to Win9X pass-though authentication
288 DEBUG(4,("sam_password_ok: Checking NT MD4 password in LM field\n"));
291 if (smb_pwd_check_ntlmv1(&user_info->lm_resp,
292 nt_pw, &auth_context->challenge,
297 DEBUG(3,("sam_password_ok: LM password, NT MD4 password in LM field and LMv2 failed for user %s\n",pdb_get_username(sampass)));
298 return NT_STATUS_WRONG_PASSWORD;
300 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)));
301 return NT_STATUS_WRONG_PASSWORD;
306 /* Should not be reached, but if they send nothing... */
307 DEBUG(3,("sam_password_ok: NEITHER LanMan nor NT password supplied for user %s\n",pdb_get_username(sampass)));
308 return NT_STATUS_WRONG_PASSWORD;
311 /****************************************************************************
312 Do a specific test for a SAM_ACCOUNT being vaild for this connection
313 (ie not disabled, expired and the like).
314 ****************************************************************************/
315 static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx,
316 SAM_ACCOUNT *sampass,
317 const auth_usersupplied_info *user_info)
319 uint16 acct_ctrl = pdb_get_acct_ctrl(sampass);
320 char *workstation_list;
323 DEBUG(4,("sam_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass)));
325 /* Quit if the account was disabled. */
326 if (acct_ctrl & ACB_DISABLED) {
327 DEBUG(1,("Account for user '%s' was disabled.\n", pdb_get_username(sampass)));
328 return NT_STATUS_ACCOUNT_DISABLED;
331 /* Test account expire time */
333 kickoff_time = pdb_get_kickoff_time(sampass);
334 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
335 DEBUG(1,("Account for user '%s' has expried.\n", pdb_get_username(sampass)));
336 DEBUG(3,("Account expired at '%ld' unix time.\n", (long)kickoff_time));
337 return NT_STATUS_ACCOUNT_EXPIRED;
340 if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP)) {
341 time_t must_change_time = pdb_get_pass_must_change_time(sampass);
342 time_t last_set_time = pdb_get_pass_last_set_time(sampass);
344 /* check for immediate expiry "must change at next logon" */
345 if (must_change_time == 0 && last_set_time != 0) {
346 DEBUG(1,("Account for user '%s' password must change!.\n", pdb_get_username(sampass)));
347 return NT_STATUS_PASSWORD_MUST_CHANGE;
350 /* check for expired password */
351 if (must_change_time < time(NULL) && must_change_time != 0) {
352 DEBUG(1,("Account for user '%s' password expired!.\n", pdb_get_username(sampass)));
353 DEBUG(1,("Password expired at '%s' (%ld) unix time.\n", http_timestring(must_change_time), (long)must_change_time));
354 return NT_STATUS_PASSWORD_EXPIRED;
358 /* Test workstation. Workstation list is comma separated. */
360 workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass));
362 if (!workstation_list) return NT_STATUS_NO_MEMORY;
364 if (*workstation_list) {
365 BOOL invalid_ws = True;
366 const char *s = workstation_list;
370 while (next_token(&s, tok, ",", sizeof(tok))) {
371 DEBUG(10,("checking for workstation match %s and %s (len=%d)\n",
372 tok, user_info->wksta_name.str, user_info->wksta_name.len));
373 if(strequal(tok, user_info->wksta_name.str)) {
380 return NT_STATUS_INVALID_WORKSTATION;
383 if (acct_ctrl & ACB_DOMTRUST) {
384 DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", pdb_get_username(sampass)));
385 return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
388 if (acct_ctrl & ACB_SVRTRUST) {
389 DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", pdb_get_username(sampass)));
390 return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
393 if (acct_ctrl & ACB_WSTRUST) {
394 DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", pdb_get_username(sampass)));
395 return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
402 /****************************************************************************
403 check if a username/password is OK assuming the password is a 24 byte
404 SMB hash supplied in the user_info structure
405 return an NT_STATUS constant.
406 ****************************************************************************/
408 static NTSTATUS check_sam_security(const struct auth_context *auth_context,
409 void *my_private_data,
411 const auth_usersupplied_info *user_info,
412 auth_serversupplied_info **server_info)
414 SAM_ACCOUNT *sampass=NULL;
417 uint8 user_sess_key[16];
418 const uint8* lm_hash;
420 if (!user_info || !auth_context) {
421 return NT_STATUS_UNSUCCESSFUL;
424 /* Can't use the talloc version here, because the returned struct gets
425 kept on the server_info */
426 if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(&sampass))) {
430 /* get the account information */
433 ret = pdb_getsampwnam(sampass, user_info->internal_username.str);
438 DEBUG(3,("Couldn't find user '%s' in passdb file.\n", user_info->internal_username.str));
439 pdb_free_sam(&sampass);
440 return NT_STATUS_NO_SUCH_USER;
443 nt_status = sam_password_ok(auth_context, mem_ctx, sampass, user_info, user_sess_key);
445 if (!NT_STATUS_IS_OK(nt_status)) {
446 pdb_free_sam(&sampass);
450 nt_status = sam_account_ok(mem_ctx, sampass, user_info);
452 if (!NT_STATUS_IS_OK(nt_status)) {
453 pdb_free_sam(&sampass);
457 if (!NT_STATUS_IS_OK(nt_status = make_server_info_sam(server_info, sampass))) {
458 DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status)));
462 lm_hash = pdb_get_lanman_passwd((*server_info)->sam_account);
464 memcpy((*server_info)->first_8_lm_hash, lm_hash, 8);
467 memcpy((*server_info)->session_key, user_sess_key, sizeof(user_sess_key));
472 /* module initialisation */
473 static NTSTATUS auth_init_sam(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
475 if (!make_auth_methods(auth_context, auth_method)) {
476 return NT_STATUS_NO_MEMORY;
479 (*auth_method)->auth = check_sam_security;
480 (*auth_method)->name = "sam";
485 /****************************************************************************
486 Check SAM security (above) but with a few extra checks.
487 ****************************************************************************/
489 static NTSTATUS check_samstrict_security(const struct auth_context *auth_context,
490 void *my_private_data,
492 const auth_usersupplied_info *user_info,
493 auth_serversupplied_info **server_info)
496 if (!user_info || !auth_context) {
497 return NT_STATUS_LOGON_FAILURE;
500 /* If we are a domain member, we must not
501 attempt to check the password locally,
502 unless it is one of our aliases. */
504 if (!is_myname(user_info->domain.str)) {
505 DEBUG(7,("The requested user domain is not the local server name. [%s]\\[%s]\n",
506 user_info->domain.str,user_info->internal_username.str));
507 return NT_STATUS_NO_SUCH_USER;
510 return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
513 /* module initialisation */
514 static NTSTATUS auth_init_samstrict(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
516 if (!make_auth_methods(auth_context, auth_method)) {
517 return NT_STATUS_NO_MEMORY;
520 (*auth_method)->auth = check_samstrict_security;
521 (*auth_method)->name = "samstrict";
525 /****************************************************************************
526 Check SAM security (above) but with a few extra checks if we're a DC.
527 ****************************************************************************/
529 static NTSTATUS check_samstrict_dc_security(const struct auth_context *auth_context,
530 void *my_private_data,
532 const auth_usersupplied_info *user_info,
533 auth_serversupplied_info **server_info)
536 if (!user_info || !auth_context) {
537 return NT_STATUS_LOGON_FAILURE;
540 /* If we are a PDC we must not check the password here
541 unless it is one of our aliases, empty
542 or equal to our domain name. Other names may be
546 if ((!is_myworkgroup(user_info->domain.str))&&
547 (!is_myname(user_info->domain.str))) {
548 DEBUG(7,("The requested user domain is not the local server name or our domain. [%s]\\[%s]\n",
549 user_info->domain.str,user_info->internal_username.str));
550 return NT_STATUS_NO_SUCH_USER;
553 return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
556 /* module initialisation */
557 static NTSTATUS auth_init_samstrict_dc(struct auth_context *auth_context, const char *param, auth_methods **auth_method)
559 if (!make_auth_methods(auth_context, auth_method)) {
560 return NT_STATUS_NO_MEMORY;
563 (*auth_method)->auth = check_samstrict_dc_security;
564 (*auth_method)->name = "samstrict_dc";
568 NTSTATUS auth_sam_init(void)
570 smb_register_auth(AUTH_INTERFACE_VERSION, "samstrict_dc", auth_init_samstrict_dc);
571 smb_register_auth(AUTH_INTERFACE_VERSION, "samstrict", auth_init_samstrict);
572 smb_register_auth(AUTH_INTERFACE_VERSION, "sam", auth_init_sam);