r443: Update Samba4 to the auth and NTLMSSP code from Samba3.
[abartlet/samba.git/.git] / source4 / auth / auth.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Bartlett         2001-2002
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_AUTH
25
26 /****************************************************************************
27  Try to get a challenge out of the various authentication modules.
28  Returns a const char of length 8 bytes.
29 ****************************************************************************/
30
31 static const uint8 *get_ntlm_challenge(struct auth_context *auth_context) 
32 {
33         DATA_BLOB challenge = data_blob(NULL, 0);
34         const char *challenge_set_by = NULL;
35         auth_methods *auth_method;
36         TALLOC_CTX *mem_ctx;
37
38         if (auth_context->challenge.length) {
39                 DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n", 
40                           auth_context->challenge_set_by));
41                 return auth_context->challenge.data;
42         }
43
44         auth_context->challenge_may_be_modified = False;
45
46         for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) {
47                 if (auth_method->get_chal == NULL) {
48                         DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name));
49                         continue;
50                 }
51
52                 DEBUG(5, ("auth_get_challenge: getting challenge from module %s\n", auth_method->name));
53                 if (challenge_set_by != NULL) {
54                         DEBUG(1, ("auth_get_challenge: CONFIGURATION ERROR: authentication method %s has already specified a challenge.  Challenge by %s ignored.\n", 
55                                   challenge_set_by, auth_method->name));
56                         continue;
57                 }
58
59                 mem_ctx = talloc_init("auth_get_challenge for module %s", auth_method->name);
60                 if (!mem_ctx) {
61                         smb_panic("talloc_init() failed!");
62                 }
63                 
64                 challenge = auth_method->get_chal(auth_context, &auth_method->private_data, mem_ctx);
65                 if (!challenge.length) {
66                         DEBUG(3, ("auth_get_challenge: getting challenge from authentication method %s FAILED.\n", 
67                                   auth_method->name));
68                 } else {
69                         DEBUG(5, ("auth_get_challenge: sucessfully got challenge from module %s\n", auth_method->name));
70                         auth_context->challenge = challenge;
71                         challenge_set_by = auth_method->name;
72                         auth_context->challenge_set_method = auth_method;
73                 }
74                 talloc_destroy(mem_ctx);
75         }
76         
77         if (!challenge_set_by) {
78                 uchar chal[8];
79                 
80                 generate_random_buffer(chal, sizeof(chal), False);
81                 auth_context->challenge = data_blob_talloc(auth_context->mem_ctx, 
82                                                            chal, sizeof(chal));
83                 
84                 challenge_set_by = "random";
85                 auth_context->challenge_may_be_modified = True;
86         } 
87         
88         DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by));
89         DEBUG(5, ("challenge is: \n"));
90         dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
91         
92         SMB_ASSERT(auth_context->challenge.length == 8);
93
94         auth_context->challenge_set_by=challenge_set_by;
95
96         return auth_context->challenge.data;
97 }
98
99
100 /**
101  * Check user is in correct domain (if required)
102  *
103  * @param user Only used to fill in the debug message
104  * 
105  * @param domain The domain to be verified
106  *
107  * @return True if the user can connect with that domain, 
108  *         False otherwise.
109 **/
110
111 static BOOL check_domain_match(const char *user, const char *domain) 
112 {
113         /*
114          * If we aren't serving to trusted domains, we must make sure that
115          * the validation request comes from an account in the same domain
116          * as the Samba server
117          */
118
119         if (!lp_allow_trusted_domains() &&
120             !(strequal("", domain) || 
121               strequal(lp_workgroup(), domain) || 
122               is_myname(domain))) {
123                 DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
124                 return False;
125         } else {
126                 return True;
127         }
128 }
129
130 /**
131  * Check a user's Plaintext, LM or NTLM password.
132  *
133  * Check a user's password, as given in the user_info struct and return various
134  * interesting details in the server_info struct.
135  *
136  * This function does NOT need to be in a become_root()/unbecome_root() pair
137  * as it makes the calls itself when needed.
138  *
139  * The return value takes precedence over the contents of the server_info 
140  * struct.  When the return is other than NT_STATUS_OK the contents 
141  * of that structure is undefined.
142  *
143  * @param user_info Contains the user supplied components, including the passwords.
144  *                  Must be created with make_user_info() or one of its wrappers.
145  *
146  * @param auth_context Supplies the challenges and some other data. 
147  *                  Must be created with make_auth_context(), and the challenges should be 
148  *                  filled in, either at creation or by calling the challenge geneation 
149  *                  function auth_get_challenge().  
150  *
151  * @param server_info If successful, contains information about the authentication, 
152  *                    including a SAM_ACCOUNT struct describing the user.
153  *
154  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
155  *
156  **/
157
158 static NTSTATUS check_ntlm_password(const struct auth_context *auth_context,
159                                     const struct auth_usersupplied_info *user_info, 
160                                     struct auth_serversupplied_info **server_info)
161 {
162         /* if all the modules say 'not for me' this is reasonable */
163         NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
164         auth_methods *auth_method;
165         TALLOC_CTX *mem_ctx;
166
167         if (!user_info || !auth_context || !server_info)
168                 return NT_STATUS_LOGON_FAILURE;
169
170         DEBUG(3, ("check_ntlm_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
171                   user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str));
172
173         DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
174                   user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
175
176         if (auth_context->challenge.length != 8) {
177                 DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
178                 return NT_STATUS_LOGON_FAILURE;
179         }
180
181         if (auth_context->challenge_set_by)
182                 DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
183                                         auth_context->challenge_set_by));
184
185         DEBUG(10, ("challenge is: \n"));
186         dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
187
188 #ifdef DEBUG_PASSWORD
189         DEBUG(100, ("user_info has passwords of length %d and %d\n", 
190                     user_info->lm_resp.length, user_info->nt_resp.length));
191         DEBUG(100, ("lm:\n"));
192         dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length);
193         DEBUG(100, ("nt:\n"));
194         dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length);
195 #endif
196
197         /* This needs to be sorted:  If it doesn't match, what should we do? */
198         if (!check_domain_match(user_info->smb_name.str, user_info->domain.str))
199                 return NT_STATUS_LOGON_FAILURE;
200
201         for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {
202                 NTSTATUS result;
203                 
204                 mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name, 
205                                             user_info->domain.str, user_info->smb_name.str);
206
207                 result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);
208
209                 /* check if the module did anything */
210                 if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) {
211                         DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name));
212                         talloc_destroy(mem_ctx);
213                         continue;
214                 }
215
216                 nt_status = result;
217
218                 if (NT_STATUS_IS_OK(nt_status)) {
219                         DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", 
220                                   auth_method->name, user_info->smb_name.str));
221                 } else {
222                         DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", 
223                                   auth_method->name, user_info->smb_name.str, nt_errstr(nt_status)));
224                 }
225
226                 talloc_destroy(mem_ctx);
227
228                 if ( NT_STATUS_IS_OK(nt_status))
229                 {
230                                 break;                  
231                 }
232         }
233
234         /* This is one of the few places the *relies* (rather than just sets defaults
235            on the value of lp_security().  This needs to change.  A new paramater 
236            perhaps? */
237         if (lp_security() >= SEC_SERVER)
238                 smb_user_control(user_info, *server_info, nt_status);
239
240         if (NT_STATUS_IS_OK(nt_status)) {
241                 if (NT_STATUS_IS_OK(nt_status)) {
242                         DEBUG((*server_info)->guest ? 5 : 2, 
243                               ("check_ntlm_password:  %sauthentication for user [%s] -> [%s] succeeded\n", 
244                                (*server_info)->guest ? "guest " : "", 
245                                user_info->smb_name.str, 
246                                user_info->internal_username.str));
247                 }
248         }
249
250         if (!NT_STATUS_IS_OK(nt_status)) {
251                 DEBUG(2, ("check_ntlm_password:  Authentication for user [%s] -> [%s] FAILED with error %s\n", 
252                           user_info->smb_name.str, user_info->internal_username.str, 
253                           nt_errstr(nt_status)));
254                 ZERO_STRUCTP(server_info);
255         }
256         return nt_status;
257 }
258
259 /***************************************************************************
260  Clear out a auth_context, and destroy the attached TALLOC_CTX
261 ***************************************************************************/
262
263 static void free_auth_context(struct auth_context **auth_context)
264 {
265         auth_methods *auth_method;
266
267         if (*auth_context) {
268                 /* Free private data of context's authentication methods */
269                 for (auth_method = (*auth_context)->auth_method_list; auth_method; auth_method = auth_method->next) {
270                         if (auth_method->free_private_data) {
271                                 auth_method->free_private_data (&auth_method->private_data);
272                                 auth_method->private_data = NULL;
273                         }
274                 }
275
276                 talloc_destroy((*auth_context)->mem_ctx);
277                 *auth_context = NULL;
278         }
279 }
280
281 /***************************************************************************
282  Make a auth_info struct
283 ***************************************************************************/
284
285 static NTSTATUS make_auth_context(struct auth_context **auth_context) 
286 {
287         TALLOC_CTX *mem_ctx;
288
289         mem_ctx = talloc_init("authentication context");
290         
291         *auth_context = talloc(mem_ctx, sizeof(**auth_context));
292         if (!*auth_context) {
293                 DEBUG(0,("make_auth_context: talloc failed!\n"));
294                 talloc_destroy(mem_ctx);
295                 return NT_STATUS_NO_MEMORY;
296         }
297         ZERO_STRUCTP(*auth_context);
298
299         (*auth_context)->mem_ctx = mem_ctx;
300         (*auth_context)->check_ntlm_password = check_ntlm_password;
301         (*auth_context)->get_ntlm_challenge = get_ntlm_challenge;
302         (*auth_context)->free = free_auth_context;
303         
304         return NT_STATUS_OK;
305 }
306
307 /***************************************************************************
308  Make a auth_info struct for the auth subsystem
309 ***************************************************************************/
310
311 static NTSTATUS make_auth_context_text_list(struct auth_context **auth_context, char **text_list) 
312 {
313         auth_methods *list = NULL;
314         auth_methods *t = NULL;
315         int i;
316         NTSTATUS nt_status;
317
318         if (!text_list) {
319                 DEBUG(2,("make_auth_context_text_list: No auth method list!?\n"));
320                 return NT_STATUS_UNSUCCESSFUL;
321         }
322         
323         if (!NT_STATUS_IS_OK(nt_status = make_auth_context(auth_context)))
324                 return nt_status;
325         
326         for (;*text_list; text_list++) {
327                 char *module_name = smb_xstrdup(*text_list);
328                 char *module_params = NULL;
329                 char *p;
330                 const struct auth_operations *ops;
331
332                 DEBUG(5,("make_auth_context_text_list: Attempting to find an auth method to match %s\n",
333                                         *text_list));
334
335                 p = strchr(module_name, ':');
336                 if (p) {
337                         *p = 0;
338                         module_params = p+1;
339                         trim_string(module_params, " ", " ");
340                 }
341
342                 trim_string(module_name, " ", " ");
343
344                 ops = auth_backend_byname(module_name);
345                 if (!ops) {
346                         DEBUG(5,("make_auth_context_text_list: Found auth method %s (at pos %d)\n", *text_list, i));
347                         SAFE_FREE(module_name);
348                         break;
349                 }
350
351                 if (NT_STATUS_IS_OK(ops->init(*auth_context, module_params, &t))) {
352                         DEBUG(5,("make_auth_context_text_list: auth method %s has a valid init\n",
353                                                 *text_list));
354                         DLIST_ADD_END(list, t, auth_methods *);
355                 } else {
356                         DEBUG(0,("make_auth_context_text_list: auth method %s did not correctly init\n",
357                                                 *text_list));
358                 }
359                 SAFE_FREE(module_name);
360         }
361         
362         (*auth_context)->auth_method_list = list;
363         
364         return nt_status;
365 }
366
367 /***************************************************************************
368  Make a auth_context struct for the auth subsystem
369 ***************************************************************************/
370
371 NTSTATUS make_auth_context_subsystem(struct auth_context **auth_context) 
372 {
373         char **auth_method_list = NULL; 
374         NTSTATUS nt_status;
375
376         if (lp_auth_methods() && !str_list_copy(&auth_method_list, lp_auth_methods())) {
377                 return NT_STATUS_NO_MEMORY;
378         }
379
380         if (auth_method_list == NULL) {
381                 switch (lp_security()) 
382                 {
383                 case SEC_DOMAIN:
384                         DEBUG(5,("Making default auth method list for security=domain\n"));
385                         auth_method_list = str_list_make("guest sam winbind:ntdomain", NULL);
386                         break;
387                 case SEC_SERVER:
388                         DEBUG(5,("Making default auth method list for security=server\n"));
389                         auth_method_list = str_list_make("guest sam smbserver", NULL);
390                         break;
391                 case SEC_USER:
392                         if (lp_encrypted_passwords()) { 
393                                 DEBUG(5,("Making default auth method list for security=user, encrypt passwords = yes\n"));
394                                 auth_method_list = str_list_make("guest sam", NULL);
395                         } else {
396                                 DEBUG(5,("Making default auth method list for security=user, encrypt passwords = no\n"));
397                                 auth_method_list = str_list_make("guest unix", NULL);
398                         }
399                         break;
400                 case SEC_SHARE:
401                         if (lp_encrypted_passwords()) {
402                                 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = yes\n"));
403                                 auth_method_list = str_list_make("guest sam", NULL);
404                         } else {
405                                 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = no\n"));
406                                 auth_method_list = str_list_make("guest unix", NULL);
407                         }
408                         break;
409                 case SEC_ADS:
410                         DEBUG(5,("Making default auth method list for security=ADS\n"));
411                         auth_method_list = str_list_make("guest sam winbind:ntdomain", NULL);
412                         break;
413                 default:
414                         DEBUG(5,("Unknown auth method!\n"));
415                         return NT_STATUS_UNSUCCESSFUL;
416                 }
417         } else {
418                 DEBUG(5,("Using specified auth order\n"));
419         }
420         
421         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_text_list(auth_context, auth_method_list))) {
422                 str_list_free(&auth_method_list);
423                 return nt_status;
424         }
425         
426         str_list_free(&auth_method_list);
427         return nt_status;
428 }
429
430 /***************************************************************************
431  Make a auth_info struct with a fixed challenge
432 ***************************************************************************/
433
434 NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[8]) 
435 {
436         NTSTATUS nt_status;
437         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(auth_context))) {
438                 return nt_status;
439         }
440         
441         (*auth_context)->challenge = data_blob_talloc((*auth_context)->mem_ctx, chal, 8);
442         (*auth_context)->challenge_set_by = "fixed";
443         return nt_status;
444 }
445
446 /* the list of currently registered AUTH backends */
447 static struct {
448         const struct auth_operations *ops;
449 } *backends = NULL;
450 static int num_backends;
451
452 /*
453   register a AUTH backend. 
454
455   The 'name' can be later used by other backends to find the operations
456   structure for this backend.
457 */
458 static NTSTATUS auth_register(void *_ops)
459 {
460         const struct auth_operations *ops = _ops;
461         struct auth_operations *new_ops;
462         
463         if (auth_backend_byname(ops->name) != NULL) {
464                 /* its already registered! */
465                 DEBUG(0,("AUTH backend '%s' already registered\n", 
466                          ops->name));
467                 return NT_STATUS_OBJECT_NAME_COLLISION;
468         }
469
470         backends = Realloc(backends, sizeof(backends[0]) * (num_backends+1));
471         if (!backends) {
472                 smb_panic("out of memory in auth_register");
473         }
474
475         new_ops = smb_xmemdup(ops, sizeof(*ops));
476         new_ops->name = smb_xstrdup(ops->name);
477
478         backends[num_backends].ops = new_ops;
479
480         num_backends++;
481
482         DEBUG(3,("AUTH backend '%s' registered\n", 
483                  ops->name));
484
485         return NT_STATUS_OK;
486 }
487
488 /*
489   return the operations structure for a named backend of the specified type
490 */
491 const struct auth_operations *auth_backend_byname(const char *name)
492 {
493         int i;
494
495         for (i=0;i<num_backends;i++) {
496                 if (strcmp(backends[i].ops->name, name) == 0) {
497                         return backends[i].ops;
498                 }
499         }
500
501         return NULL;
502 }
503
504 /*
505   return the AUTH interface version, and the size of some critical types
506   This can be used by backends to either detect compilation errors, or provide
507   multiple implementations for different smbd compilation options in one module
508 */
509 const struct auth_critical_sizes *auth_interface_version(void)
510 {
511         static const struct auth_critical_sizes critical_sizes = {
512                 AUTH_INTERFACE_VERSION,
513                 sizeof(struct auth_operations),
514                 sizeof(struct auth_methods),
515                 sizeof(struct auth_context),
516                 sizeof(struct auth_ntlmssp_state),
517                 sizeof(struct auth_usersupplied_info),
518                 sizeof(struct auth_serversupplied_info),
519                 sizeof(struct auth_str),
520         };
521
522         return &critical_sizes;
523 }
524
525 /*
526   initialise the AUTH subsystem
527 */
528 BOOL auth_init(void)
529 {
530         NTSTATUS status;
531
532         status = register_subsystem("auth", auth_register); 
533         if (!NT_STATUS_IS_OK(status)) {
534                 return False;
535         }
536
537         /* FIXME: Perhaps panic if a basic backend, such as SAM, fails to initialise? */
538         static_init_auth;
539
540         DEBUG(3,("AUTH subsystem version %d initialised\n", AUTH_INTERFACE_VERSION));
541         return True;
542 }