Add some static. Patch by Stefan Metzmacher <metze@metzemix.de>
[sfrench/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                 {
206                         return NT_STATUS_OK;
207                 } else {
208                         DEBUG(3,("sam_password_ok: NTLMv2 password check failed\n"));
209                         return NT_STATUS_WRONG_PASSWORD;
210                 }
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).
216                         */
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,
220                                                  user_sess_key)) 
221                         {
222                                 return NT_STATUS_OK;
223                         } else {
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;
226                         }
227                 } else {
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 */
230                 }
231         }
232         
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)));                
237                 }
238                 
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)));
243                 } else {
244                         lm_pw = pdb_get_lanman_passwd(sampass);
245                         
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,
249                                                  user_sess_key)) 
250                         {
251                                 return NT_STATUS_OK;
252                         }
253                 }
254
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;
258                 } 
259                 
260                 nt_pw = pdb_get_nt_passwd(sampass);
261
262                 /* This is for 'LMv2' authentication.  almost NTLMv2 but limited to 24 bytes.
263                    - related to Win9X, legacy NAS pass-though authentication
264                 */
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,
270                                           user_sess_key))
271                 {
272                         return NT_STATUS_OK;
273                 }
274
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, 
279                                           "",
280                                           user_sess_key))
281                 {
282                         return NT_STATUS_OK;
283                 }
284
285                 /* Apparently NT accepts NT responses in the LM field
286                    - I think this is related to Win9X pass-though authentication
287                 */
288                 DEBUG(4,("sam_password_ok: Checking NT MD4 password in LM field\n"));
289                 if (lp_ntlm_auth()) 
290                 {
291                         if (smb_pwd_check_ntlmv1(&user_info->lm_resp, 
292                                                  nt_pw, &auth_context->challenge,
293                                                  user_sess_key)) 
294                         {
295                                 return NT_STATUS_OK;
296                         }
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;
299                 } else {
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;
302                 }
303                         
304         }
305                 
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;
309 }
310
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)
318 {
319         uint16  acct_ctrl = pdb_get_acct_ctrl(sampass);
320         char *workstation_list;
321         time_t kickoff_time;
322         
323         DEBUG(4,("sam_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass)));
324
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;
329         }
330
331         /* Test account expire time */
332         
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;
338         }
339
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);
343
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;
348                 }
349
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;
355                 }
356         }
357
358         /* Test workstation. Workstation list is comma separated. */
359
360         workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass));
361
362         if (!workstation_list) return NT_STATUS_NO_MEMORY;
363
364         if (*workstation_list) {
365                 BOOL invalid_ws = True;
366                 const char *s = workstation_list;
367                         
368                 fstring tok;
369                         
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)) {
374                                 invalid_ws = False;
375                                 break;
376                         }
377                 }
378                 
379                 if (invalid_ws) 
380                         return NT_STATUS_INVALID_WORKSTATION;
381         }
382
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;
386         }
387         
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;
391         }
392         
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;
396         }
397         
398         return NT_STATUS_OK;
399 }
400
401
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 ****************************************************************************/
407
408 static NTSTATUS check_sam_security(const struct auth_context *auth_context,
409                                    void *my_private_data, 
410                                    TALLOC_CTX *mem_ctx,
411                                    const auth_usersupplied_info *user_info, 
412                                    auth_serversupplied_info **server_info)
413 {
414         SAM_ACCOUNT *sampass=NULL;
415         BOOL ret;
416         NTSTATUS nt_status;
417         uint8 user_sess_key[16];
418         const uint8* lm_hash;
419
420         if (!user_info || !auth_context) {
421                 return NT_STATUS_UNSUCCESSFUL;
422         }
423
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))) {
427                 return nt_status;
428         }
429
430         /* get the account information */
431
432         become_root();
433         ret = pdb_getsampwnam(sampass, user_info->internal_username.str);
434         unbecome_root();
435
436         if (ret == False)
437         {
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;
441         }
442
443         nt_status = sam_password_ok(auth_context, mem_ctx, sampass, user_info, user_sess_key);
444         
445         if (!NT_STATUS_IS_OK(nt_status)) {
446                 pdb_free_sam(&sampass);
447                 return nt_status;
448         }
449
450         nt_status = sam_account_ok(mem_ctx, sampass, user_info);
451
452         if (!NT_STATUS_IS_OK(nt_status)) {
453                 pdb_free_sam(&sampass);
454                 return nt_status;
455         }
456
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)));
459                 return nt_status;
460         }
461
462         lm_hash = pdb_get_lanman_passwd((*server_info)->sam_account);
463         if (lm_hash) {
464                 memcpy((*server_info)->first_8_lm_hash, lm_hash, 8);
465         }
466         
467         memcpy((*server_info)->session_key, user_sess_key, sizeof(user_sess_key));
468
469         return nt_status;
470 }
471
472 /* module initialisation */
473 static NTSTATUS auth_init_sam(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
474 {
475         if (!make_auth_methods(auth_context, auth_method)) {
476                 return NT_STATUS_NO_MEMORY;
477         }
478
479         (*auth_method)->auth = check_sam_security;      
480         (*auth_method)->name = "sam";
481         return NT_STATUS_OK;
482 }
483
484
485 /****************************************************************************
486 Check SAM security (above) but with a few extra checks.
487 ****************************************************************************/
488
489 static NTSTATUS check_samstrict_security(const struct auth_context *auth_context,
490                                          void *my_private_data, 
491                                          TALLOC_CTX *mem_ctx,
492                                          const auth_usersupplied_info *user_info, 
493                                          auth_serversupplied_info **server_info)
494 {
495
496         if (!user_info || !auth_context) {
497                 return NT_STATUS_LOGON_FAILURE;
498         }
499
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. */
503         
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;
508         }
509         
510         return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
511 }
512
513 /* module initialisation */
514 static NTSTATUS auth_init_samstrict(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
515 {
516         if (!make_auth_methods(auth_context, auth_method)) {
517                 return NT_STATUS_NO_MEMORY;
518         }
519
520         (*auth_method)->auth = check_samstrict_security;
521         (*auth_method)->name = "samstrict";
522         return NT_STATUS_OK;
523 }
524
525 /****************************************************************************
526 Check SAM security (above) but with a few extra checks if we're a DC.
527 ****************************************************************************/
528
529 static NTSTATUS check_samstrict_dc_security(const struct auth_context *auth_context,
530                                          void *my_private_data, 
531                                          TALLOC_CTX *mem_ctx,
532                                          const auth_usersupplied_info *user_info, 
533                                          auth_serversupplied_info **server_info)
534 {
535
536         if (!user_info || !auth_context) {
537                 return NT_STATUS_LOGON_FAILURE;
538         }
539
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
543            Trusted domains.
544         */
545
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;
551         }               
552
553         return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info);
554 }
555
556 /* module initialisation */
557 static NTSTATUS auth_init_samstrict_dc(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
558 {
559         if (!make_auth_methods(auth_context, auth_method)) {
560                 return NT_STATUS_NO_MEMORY;
561         }
562
563         (*auth_method)->auth = check_samstrict_dc_security;
564         (*auth_method)->name = "samstrict_dc";
565         return NT_STATUS_OK;
566 }
567
568 NTSTATUS auth_sam_init(void)
569 {
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);
573         return NT_STATUS_OK;
574 }