Add samstrict_dc from metze (been sitting in HEAD for way to long waiting for
[bbaumbach/samba-autobuild/.git] / source / auth / auth_sam.c
1 /* 
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
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24
25 #undef DBGC_CLASS
26 #define DBGC_CLASS DBGC_AUTH
27
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])
35 {
36         /* Finish the encryption of part_passwd. */
37         uchar p24[24];
38         
39         if (part_passwd == NULL) {
40                 DEBUG(10,("No password set - DISALLOWING access\n"));
41                 /* No password set - always false ! */
42                 return False;
43         }
44         
45         if (sec_blob->length != 8) {
46                 DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challenge size (%d)\n", sec_blob->length));
47                 return False;
48         }
49         
50         if (nt_response->length != 24) {
51                 DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n", nt_response->length));
52                 return False;
53         }
54
55         SMBOWFencrypt(part_passwd, sec_blob->data, p24);
56         if (user_sess_key != NULL)
57         {
58                 SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key);
59         }
60         
61         
62         
63 #if DEBUG_PASSWORD
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);
72 #endif
73   return (memcmp(p24, nt_response->data, 24) == 0);
74 }
75
76
77 /****************************************************************************
78 core of smb password checking routine. (NTLMv2, LMv2)
79
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])
87 {
88         /* Finish the encryption of part_passwd. */
89         uchar kr[16];
90         uchar value_from_encryption[16];
91         uchar client_response[16];
92         DATA_BLOB client_key_data;
93
94         if (part_passwd == NULL)
95         {
96                 DEBUG(10,("No password set - DISALLOWING access\n"));
97                 /* No password set - always False */
98                 return False;
99         }
100
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));
107                 return False;
108         }
109
110         client_key_data = data_blob(ntv2_response->data+16, ntv2_response->length-16);
111         /* 
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.
114         */
115
116         memcpy(client_response, ntv2_response->data, sizeof(client_response));
117
118         if (!ntv2_owf_gen(part_passwd, user, domain, kr)) {
119                 return False;
120         }
121
122         SMBOWFencrypt_ntv2(kr, sec_blob, &client_key_data, value_from_encryption);
123         if (user_sess_key != NULL)
124         {
125                 SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key);
126         }
127
128 #if DEBUG_PASSWORD
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);
139 #endif
140         data_blob_clear_free(&client_key_data);
141         return (memcmp(value_from_encryption, client_response, 16) == 0);
142 }
143
144
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,
150                                 TALLOC_CTX *mem_ctx,
151                                 SAM_ACCOUNT *sampass, 
152                                 const auth_usersupplied_info *user_info, 
153                                 uint8 user_sess_key[16])
154 {
155         uint16 acct_ctrl;
156         const uint8 *nt_pw, *lm_pw;
157         uint32 auth_flags;
158
159         acct_ctrl = pdb_get_acct_ctrl(sampass);
160         if (acct_ctrl & ACB_PWNOTREQ) 
161         {
162                 if (lp_null_passwords()) 
163                 {
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);
166                 } 
167                 else 
168                 {
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);
171                 }               
172         }
173
174         auth_flags = user_info->auth_flags;
175
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));
181         }
182         
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).
187                 */
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,
193                                           user_sess_key))
194                 {
195                         return NT_STATUS_OK;
196                 }
197
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, 
202                                           "",
203                                           user_sess_key))
204                 {
205                         return NT_STATUS_OK;
206                 } else {
207                         DEBUG(3,("sam_password_ok: NTLMv2 password check failed\n"));
208                         return NT_STATUS_WRONG_PASSWORD;
209                 }
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).
215                         */
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,
219                                                  user_sess_key)) 
220                         {
221                                 return NT_STATUS_OK;
222                         } else {
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;
225                         }
226                 } else {
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 */
229                 }
230         }
231         
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)));                
236                 }
237                 
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)));
242                 } else {
243                         lm_pw = pdb_get_lanman_passwd(sampass);
244                         
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,
248                                                  user_sess_key)) 
249                         {
250                                 return NT_STATUS_OK;
251                         }
252                 }
253
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;
257                 } 
258                 
259                 nt_pw = pdb_get_nt_passwd(sampass);
260
261                 /* This is for 'LMv2' authentication.  almost NTLMv2 but limited to 24 bytes.
262                    - related to Win9X, legacy NAS pass-though authentication
263                 */
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,
269                                           user_sess_key))
270                 {
271                         return NT_STATUS_OK;
272                 }
273
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, 
278                                           "",
279                                           user_sess_key))
280                 {
281                         return NT_STATUS_OK;
282                 }
283
284                 /* Apparently NT accepts NT responses in the LM field
285                    - I think this is related to Win9X pass-though authentication
286                 */
287                 DEBUG(4,("sam_password_ok: Checking NT MD4 password in LM field\n"));
288                 if (lp_ntlm_auth()) 
289                 {
290                         if (smb_pwd_check_ntlmv1(&user_info->lm_resp, 
291                                                  nt_pw, &auth_context->challenge,
292                                                  user_sess_key)) 
293                         {
294                                 return NT_STATUS_OK;
295                         }
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;
298                 } else {
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;
301                 }
302                         
303         }
304                 
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;
308 }
309
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)
317 {
318         uint16  acct_ctrl = pdb_get_acct_ctrl(sampass);
319         char *workstation_list;
320         time_t kickoff_time;
321         
322         DEBUG(4,("sam_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass)));
323
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;
328         }
329
330         /* Test account expire time */
331         
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;
337         }
338
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);
342
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;
347                 }
348
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;
354                 }
355         }
356
357         /* Test workstation. Workstation list is comma separated. */
358
359         workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass));
360
361         if (!workstation_list) return NT_STATUS_NO_MEMORY;
362
363         if (*workstation_list) {
364                 BOOL invalid_ws = True;
365                 const char *s = workstation_list;
366                         
367                 fstring tok;
368                         
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)) {
373                                 invalid_ws = False;
374                                 break;
375                         }
376                 }
377                 
378                 if (invalid_ws) 
379                         return NT_STATUS_INVALID_WORKSTATION;
380         }
381
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;
385         }
386         
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;
390         }
391         
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;
395         }
396         
397         return NT_STATUS_OK;
398 }
399
400
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 ****************************************************************************/
406
407 static NTSTATUS check_sam_security(const struct auth_context *auth_context,
408                                    void *my_private_data, 
409                                    TALLOC_CTX *mem_ctx,
410                                    const auth_usersupplied_info *user_info, 
411                                    auth_serversupplied_info **server_info)
412 {
413         SAM_ACCOUNT *sampass=NULL;
414         BOOL ret;
415         NTSTATUS nt_status;
416         uint8 user_sess_key[16];
417         const uint8* lm_hash;
418
419         if (!user_info || !auth_context) {
420                 return NT_STATUS_UNSUCCESSFUL;
421         }
422
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))) {
426                 return nt_status;
427         }
428
429         /* get the account information */
430
431         become_root();
432         ret = pdb_getsampwnam(sampass, user_info->internal_username.str);
433         unbecome_root();
434
435         if (ret == False)
436         {
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;
440         }
441
442         nt_status = sam_password_ok(auth_context, mem_ctx, sampass, user_info, user_sess_key);
443         
444         if (!NT_STATUS_IS_OK(nt_status)) {
445                 pdb_free_sam(&sampass);
446                 return nt_status;
447         }
448
449         nt_status = sam_account_ok(mem_ctx, sampass, user_info);
450
451         if (!NT_STATUS_IS_OK(nt_status)) {
452                 pdb_free_sam(&sampass);
453                 return nt_status;
454         }
455
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)));
458                 return nt_status;
459         }
460
461         lm_hash = pdb_get_lanman_passwd((*server_info)->sam_account);
462         if (lm_hash) {
463                 memcpy((*server_info)->first_8_lm_hash, lm_hash, 8);
464         }
465         
466         memcpy((*server_info)->session_key, user_sess_key, sizeof(user_sess_key));
467
468         return nt_status;
469 }
470
471 /* module initialisation */
472 NTSTATUS auth_init_sam(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
473 {
474         if (!make_auth_methods(auth_context, auth_method)) {
475                 return NT_STATUS_NO_MEMORY;
476         }
477
478         (*auth_method)->auth = check_sam_security;      
479         (*auth_method)->name = "sam";
480         return NT_STATUS_OK;
481 }
482
483
484 /****************************************************************************
485 Check SAM security (above) but with a few extra checks.
486 ****************************************************************************/
487
488 static NTSTATUS check_samstrict_security(const struct auth_context *auth_context,
489                                          void *my_private_data, 
490                                          TALLOC_CTX *mem_ctx,
491                                          const auth_usersupplied_info *user_info, 
492                                          auth_serversupplied_info **server_info)
493 {
494
495         if (!user_info || !auth_context) {
496                 return NT_STATUS_LOGON_FAILURE;
497         }
498
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. */
502         
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;
507         }
508         
509         return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
510 }
511
512 /* module initialisation */
513 NTSTATUS auth_init_samstrict(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
514 {
515         if (!make_auth_methods(auth_context, auth_method)) {
516                 return NT_STATUS_NO_MEMORY;
517         }
518
519         (*auth_method)->auth = check_samstrict_security;
520         (*auth_method)->name = "samstrict";
521         return NT_STATUS_OK;
522 }
523
524 /****************************************************************************
525 Check SAM security (above) but with a few extra checks if we're a DC.
526 ****************************************************************************/
527
528 static NTSTATUS check_samstrict_dc_security(const struct auth_context *auth_context,
529                                          void *my_private_data, 
530                                          TALLOC_CTX *mem_ctx,
531                                          const auth_usersupplied_info *user_info, 
532                                          auth_serversupplied_info **server_info)
533 {
534
535         if (!user_info || !auth_context) {
536                 return NT_STATUS_LOGON_FAILURE;
537         }
538
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
542            Trusted domains.
543         */
544
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;
550         }               
551
552         return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
553 }
554
555 /* module initialisation */
556 NTSTATUS auth_init_samstrict_dc(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
557 {
558         if (!make_auth_methods(auth_context, auth_method)) {
559                 return NT_STATUS_NO_MEMORY;
560         }
561
562         (*auth_method)->auth = check_samstrict_dc_security;
563         (*auth_method)->name = "samstrict_dc";
564         return NT_STATUS_OK;
565 }
566
567 NTSTATUS auth_sam_init(void)
568 {
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);
572         return NT_STATUS_OK;
573 }