Cause the winbind auth module to call the ntdomain module if winbind is not
[tprouty/samba.git] / source3 / 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 static struct auth_init_function_entry *backends = NULL;
27
28 BOOL smb_register_auth(const char *name, auth_init_function init, int version)
29 {
30         struct auth_init_function_entry *entry = backends;
31
32         if(version != AUTH_INTERFACE_VERSION)
33                 return False;
34
35         DEBUG(5,("Attempting to register auth backend %s\n", name));
36
37         while(entry) {
38                 if (strequal(name, entry->name)) {
39                         DEBUG(0,("There already is an auth backend registered with the name %s!\n", name));
40                         return False;
41                 }
42                 entry = entry->next;
43         }
44         
45         entry = smb_xmalloc(sizeof(struct auth_init_function_entry));
46         entry->name = smb_xstrdup(name);
47         entry->init = init;
48
49         DLIST_ADD(backends, entry);
50         DEBUG(5,("Successfully added auth backend '%s'\n", name));
51         return True;
52 }
53
54 static struct auth_init_function_entry *auth_find_backend_entry(const char *name)
55 {
56         struct auth_init_function_entry *entry = backends;
57
58         while(entry) {
59                 if (strequal(entry->name, name)) return entry;
60                 entry = entry->next;
61         }
62         
63         return NULL;
64 }
65
66 /****************************************************************************
67  Try to get a challenge out of the various authentication modules.
68  Returns a const char of length 8 bytes.
69 ****************************************************************************/
70
71 static const uint8 *get_ntlm_challenge(struct auth_context *auth_context) 
72 {
73         DATA_BLOB challenge = data_blob(NULL, 0);
74         const char *challenge_set_by = NULL;
75         auth_methods *auth_method;
76         TALLOC_CTX *mem_ctx;
77
78         if (auth_context->challenge.length) {
79                 DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n", 
80                           auth_context->challenge_set_by));
81                 return auth_context->challenge.data;
82         }
83
84         for (auth_method = auth_context->auth_method_list; auth_method; auth_method = auth_method->next) {
85                 if (auth_method->get_chal == NULL) {
86                         DEBUG(5, ("auth_get_challenge: module %s did not want to specify a challenge\n", auth_method->name));
87                         continue;
88                 }
89
90                 DEBUG(5, ("auth_get_challenge: getting challenge from module %s\n", auth_method->name));
91                 if (challenge_set_by != NULL) {
92                         DEBUG(1, ("auth_get_challenge: CONFIGURATION ERROR: authentication method %s has already specified a challenge.  Challenge by %s ignored.\n", 
93                                   challenge_set_by, auth_method->name));
94                         continue;
95                 }
96
97                 mem_ctx = talloc_init("auth_get_challenge for module %s", auth_method->name);
98                 if (!mem_ctx) {
99                         smb_panic("talloc_init() failed!");
100                 }
101                 
102                 challenge = auth_method->get_chal(auth_context, &auth_method->private_data, mem_ctx);
103                 if (!challenge.length) {
104                         DEBUG(3, ("auth_get_challenge: getting challenge from authentication method %s FAILED.\n", 
105                                   auth_method->name));
106                 } else {
107                         DEBUG(5, ("auth_get_challenge: sucessfully got challenge from module %s\n", auth_method->name));
108                         auth_context->challenge = challenge;
109                         challenge_set_by = auth_method->name;
110                         auth_context->challenge_set_method = auth_method;
111                 }
112                 talloc_destroy(mem_ctx);
113         }
114         
115         if (!challenge_set_by) {
116                 uchar chal[8];
117                 
118                 generate_random_buffer(chal, sizeof(chal), False);
119                 auth_context->challenge = data_blob_talloc(auth_context->mem_ctx, 
120                                                            chal, sizeof(chal));
121                 
122                 challenge_set_by = "random";
123         } 
124         
125         DEBUG(5, ("auth_context challenge created by %s\n", challenge_set_by));
126         DEBUG(5, ("challenge is: \n"));
127         dump_data(5, auth_context->challenge.data, auth_context->challenge.length);
128         
129         SMB_ASSERT(auth_context->challenge.length == 8);
130
131         auth_context->challenge_set_by=challenge_set_by;
132
133         return auth_context->challenge.data;
134 }
135
136
137 /**
138  * Check user is in correct domain (if required)
139  *
140  * @param user Only used to fill in the debug message
141  * 
142  * @param domain The domain to be verified
143  *
144  * @return True if the user can connect with that domain, 
145  *         False otherwise.
146 **/
147
148 static BOOL check_domain_match(const char *user, const char *domain) 
149 {
150         /*
151          * If we aren't serving to trusted domains, we must make sure that
152          * the validation request comes from an account in the same domain
153          * as the Samba server
154          */
155
156         if (!lp_allow_trusted_domains() &&
157             !(strequal("", domain) || 
158               strequal(lp_workgroup(), domain) || 
159               is_myname(domain))) {
160                 DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
161                 return False;
162         } else {
163                 return True;
164         }
165 }
166
167 /**
168  * Check a user's Plaintext, LM or NTLM password.
169  *
170  * Check a user's password, as given in the user_info struct and return various
171  * interesting details in the server_info struct.
172  *
173  * This function does NOT need to be in a become_root()/unbecome_root() pair
174  * as it makes the calls itself when needed.
175  *
176  * The return value takes precedence over the contents of the server_info 
177  * struct.  When the return is other than NT_STATUS_OK the contents 
178  * of that structure is undefined.
179  *
180  * @param user_info Contains the user supplied components, including the passwords.
181  *                  Must be created with make_user_info() or one of its wrappers.
182  *
183  * @param auth_context Supplies the challenges and some other data. 
184  *                  Must be created with make_auth_context(), and the challenges should be 
185  *                  filled in, either at creation or by calling the challenge geneation 
186  *                  function auth_get_challenge().  
187  *
188  * @param server_info If successful, contains information about the authentication, 
189  *                    including a SAM_ACCOUNT struct describing the user.
190  *
191  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
192  *
193  **/
194
195 static NTSTATUS check_ntlm_password(const struct auth_context *auth_context,
196                                     const struct auth_usersupplied_info *user_info, 
197                                     struct auth_serversupplied_info **server_info)
198 {
199         
200         NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
201         const char *pdb_username;
202         auth_methods *auth_method;
203         TALLOC_CTX *mem_ctx;
204
205         if (!user_info || !auth_context || !server_info)
206                 return NT_STATUS_LOGON_FAILURE;
207
208         DEBUG(3, ("check_ntlm_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
209                   user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str));
210
211         DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
212                   user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
213
214         if (auth_context->challenge.length != 8) {
215                 DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
216                 return NT_STATUS_LOGON_FAILURE;
217         }
218
219         if (auth_context->challenge_set_by)
220                 DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
221                                         auth_context->challenge_set_by));
222
223         DEBUG(10, ("challenge is: \n"));
224         dump_data(5, auth_context->challenge.data, auth_context->challenge.length);
225
226 #ifdef DEBUG_PASSWORD
227         DEBUG(100, ("user_info has passwords of length %d and %d\n", 
228                     user_info->lm_resp.length, user_info->nt_resp.length));
229         DEBUG(100, ("lm:\n"));
230         dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length);
231         DEBUG(100, ("nt:\n"));
232         dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length);
233 #endif
234
235         /* This needs to be sorted:  If it doesn't match, what should we do? */
236         if (!check_domain_match(user_info->smb_name.str, user_info->domain.str))
237                 return NT_STATUS_LOGON_FAILURE;
238
239         for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {
240                 mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name, 
241                                             user_info->domain.str, user_info->smb_name.str);
242
243                 nt_status = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);
244                 if (NT_STATUS_IS_OK(nt_status)) {
245                         DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] suceeded\n", 
246                                   auth_method->name, user_info->smb_name.str));
247                 } else {
248                         DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", 
249                                   auth_method->name, user_info->smb_name.str, nt_errstr(nt_status)));
250                 }
251
252                 talloc_destroy(mem_ctx);
253
254                 if (NT_STATUS_IS_OK(nt_status))
255                         break;
256         }
257
258         /* This is one of the few places the *relies* (rather than just sets defaults
259            on the value of lp_security().  This needs to change.  A new paramater 
260            perhaps? */
261         if (lp_security() >= SEC_SERVER)
262                 smb_user_control(user_info, *server_info, nt_status);
263
264         if (NT_STATUS_IS_OK(nt_status)) {
265                 pdb_username = pdb_get_username((*server_info)->sam_account);
266                 if (!(*server_info)->guest) {
267                         /* We might not be root if we are an RPC call */
268                         become_root();
269                         nt_status = smb_pam_accountcheck(pdb_username);
270                         unbecome_root();
271                         
272                         if (NT_STATUS_IS_OK(nt_status)) {
273                                 DEBUG(5, ("check_ntlm_password:  PAM Account for user [%s] suceeded\n", 
274                                           pdb_username));
275                         } else {
276                                 DEBUG(3, ("check_ntlm_password:  PAM Account for user [%s] FAILED with error %s\n", 
277                                           pdb_username, nt_errstr(nt_status)));
278                         } 
279                 }
280                 
281                 if (NT_STATUS_IS_OK(nt_status)) {
282                         DEBUG((*server_info)->guest ? 5 : 2, 
283                               ("check_ntlm_password:  %sauthentication for user [%s] -> [%s] -> [%s] suceeded\n", 
284                                (*server_info)->guest ? "guest " : "", 
285                                user_info->smb_name.str, 
286                                user_info->internal_username.str, 
287                                pdb_username));
288                 }
289         }
290
291         if (!NT_STATUS_IS_OK(nt_status)) {
292                 DEBUG(2, ("check_ntlm_password:  Authentication for user [%s] -> [%s] FAILED with error %s\n", 
293                           user_info->smb_name.str, user_info->internal_username.str, 
294                           nt_errstr(nt_status)));
295                 ZERO_STRUCTP(server_info);
296         }
297         return nt_status;
298 }
299
300 /***************************************************************************
301  Clear out a auth_context, and destroy the attached TALLOC_CTX
302 ***************************************************************************/
303
304 static void free_auth_context(struct auth_context **auth_context)
305 {
306         if (*auth_context != NULL)
307                 talloc_destroy((*auth_context)->mem_ctx);
308         *auth_context = NULL;
309 }
310
311 /***************************************************************************
312  Make a auth_info struct
313 ***************************************************************************/
314
315 static NTSTATUS make_auth_context(struct auth_context **auth_context) 
316 {
317         TALLOC_CTX *mem_ctx;
318
319         mem_ctx = talloc_init("authentication context");
320         
321         *auth_context = talloc(mem_ctx, sizeof(**auth_context));
322         if (!*auth_context) {
323                 DEBUG(0,("make_auth_context: talloc failed!\n"));
324                 talloc_destroy(mem_ctx);
325                 return NT_STATUS_NO_MEMORY;
326         }
327         ZERO_STRUCTP(*auth_context);
328
329         (*auth_context)->mem_ctx = mem_ctx;
330         (*auth_context)->check_ntlm_password = check_ntlm_password;
331         (*auth_context)->get_ntlm_challenge = get_ntlm_challenge;
332         (*auth_context)->free = free_auth_context;
333         
334         return NT_STATUS_OK;
335 }
336
337 BOOL load_auth_module(struct auth_context *auth_context, 
338                       const char *module, auth_methods **ret) 
339 {
340         static BOOL initialised_static_modules = False;
341
342         struct auth_init_function_entry *entry;
343         char *module_name = smb_xstrdup(module);
344         char *module_params = NULL;
345         char *p;
346         BOOL good = False;
347
348         /* Initialise static modules if not done so yet */
349         if(!initialised_static_modules) {
350                 static_init_auth;
351                 initialised_static_modules = True;
352         }
353         
354         DEBUG(5,("load_auth_module: Attempting to find an auth method to match %s\n",
355                  module));
356         
357         p = strchr(module_name, ':');
358         if (p) {
359                 *p = 0;
360                 module_params = p+1;
361                 trim_string(module_params, " ", " ");
362         }
363         
364         trim_string(module_name, " ", " ");
365         
366         entry = auth_find_backend_entry(module_name);
367         
368         if(!(entry = auth_find_backend_entry(module_name)) && !smb_probe_module("auth", module_name) && 
369            !(entry = auth_find_backend_entry(module_name))) {
370                 DEBUG(0,("load_auth_module: can't find auth method %s!\n", module_name));
371         } else if (!NT_STATUS_IS_OK(entry->init(auth_context, module_params, ret))) {
372                 DEBUG(0,("load_auth_module: auth method %s did not correctly init\n",
373                          module));
374         } else {
375                 DEBUG(5,("load_auth_module: auth method %s has a valid init\n",
376                          module));
377                 good = True;
378         }
379         SAFE_FREE(module_name);
380         return good;
381 }
382
383 /***************************************************************************
384  Make a auth_info struct for the auth subsystem
385 ***************************************************************************/
386
387 static NTSTATUS make_auth_context_text_list(struct auth_context **auth_context, char **text_list) 
388 {
389         auth_methods *list = NULL;
390         auth_methods *t = NULL;
391         auth_methods *tmp;
392         NTSTATUS nt_status;
393
394         if (!text_list) {
395                 DEBUG(2,("make_auth_context_text_list: No auth method list!?\n"));
396                 return NT_STATUS_UNSUCCESSFUL;
397         }
398         
399         if (!NT_STATUS_IS_OK(nt_status = make_auth_context(auth_context)))
400                 return nt_status;
401
402         for (;*text_list; text_list++) { 
403                 if (load_auth_module(*auth_context, *text_list, &t)) {
404                     DLIST_ADD_END(list, t, tmp);
405                 }
406         }
407         
408         (*auth_context)->auth_method_list = list;
409         
410         return nt_status;
411 }
412
413 /***************************************************************************
414  Make a auth_context struct for the auth subsystem
415 ***************************************************************************/
416
417 NTSTATUS make_auth_context_subsystem(struct auth_context **auth_context) 
418 {
419         char **auth_method_list = NULL; 
420         NTSTATUS nt_status;
421
422         if (lp_auth_methods() && !str_list_copy(&auth_method_list, lp_auth_methods())) {
423                 return NT_STATUS_NO_MEMORY;
424         }
425
426         if (auth_method_list == NULL) {
427                 switch (lp_security()) 
428                 {
429                 case SEC_DOMAIN:
430                         DEBUG(5,("Making default auth method list for security=domain\n"));
431                         auth_method_list = str_list_make("guest sam winbind:ntdomain", NULL);
432                         break;
433                 case SEC_SERVER:
434                         DEBUG(5,("Making default auth method list for security=server\n"));
435                         auth_method_list = str_list_make("guest sam smbserver", NULL);
436                         break;
437                 case SEC_USER:
438                         if (lp_encrypted_passwords()) { 
439                                 DEBUG(5,("Making default auth method list for security=user, encrypt passwords = yes\n"));
440                                 auth_method_list = str_list_make("guest sam", NULL);
441                         } else {
442                                 DEBUG(5,("Making default auth method list for security=user, encrypt passwords = no\n"));
443                                 auth_method_list = str_list_make("guest unix", NULL);
444                         }
445                         break;
446                 case SEC_SHARE:
447                         if (lp_encrypted_passwords()) {
448                                 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = yes\n"));
449                                 auth_method_list = str_list_make("guest sam", NULL);
450                         } else {
451                                 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = no\n"));
452                                 auth_method_list = str_list_make("guest unix", NULL);
453                         }
454                         break;
455                 case SEC_ADS:
456                         DEBUG(5,("Making default auth method list for security=ADS\n"));
457                         auth_method_list = str_list_make("guest sam winbind:ntdomain", NULL);
458                         break;
459                 default:
460                         DEBUG(5,("Unknown auth method!\n"));
461                         return NT_STATUS_UNSUCCESSFUL;
462                 }
463         } else {
464                 DEBUG(5,("Using specified auth order\n"));
465         }
466         
467         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_text_list(auth_context, auth_method_list))) {
468                 str_list_free(&auth_method_list);
469                 return nt_status;
470         }
471         
472         str_list_free(&auth_method_list);
473         return nt_status;
474 }
475
476 /***************************************************************************
477  Make a auth_info struct with a fixed challenge
478 ***************************************************************************/
479
480 NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[8]) 
481 {
482         NTSTATUS nt_status;
483         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(auth_context))) {
484                 return nt_status;
485         }
486         
487         (*auth_context)->challenge = data_blob(chal, 8);
488         (*auth_context)->challenge_set_by = "fixed";
489         return nt_status;
490 }
491
492