This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[ira/wip.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 /***************************************************************************
338  Make a auth_info struct for the auth subsystem
339 ***************************************************************************/
340
341 static NTSTATUS make_auth_context_text_list(struct auth_context **auth_context, char **text_list) 
342 {
343         auth_methods *list = NULL;
344         auth_methods *t = NULL;
345         auth_methods *tmp;
346         NTSTATUS nt_status;
347         static BOOL initialised_static_modules = False;
348
349         if (!text_list) {
350                 DEBUG(2,("make_auth_context_text_list: No auth method list!?\n"));
351                 return NT_STATUS_UNSUCCESSFUL;
352         }
353         
354         if (!NT_STATUS_IS_OK(nt_status = make_auth_context(auth_context)))
355                 return nt_status;
356
357         /* Initialise static modules if not done so yet */
358         if(!initialised_static_modules) {
359                 static_init_auth;
360                 initialised_static_modules = True;
361         }
362         
363         for (;*text_list; text_list++) { 
364                         struct auth_init_function_entry *entry;
365                         char *module_name = smb_xstrdup(*text_list);
366                         char *module_params = NULL;
367                         char *p;
368
369                         DEBUG(5,("make_auth_context_text_list: Attempting to find an auth method to match %s\n",
370                                  *text_list));
371
372                         p = strchr(module_name, ':');
373                         if (p) {
374                                 *p = 0;
375                                 module_params = p+1;
376                                 trim_string(module_params, " ", " ");
377                         }
378
379                         trim_string(module_name, " ", " ");
380
381                         entry = auth_find_backend_entry(module_name);
382
383                         if(!(entry = auth_find_backend_entry(module_name)) && !smb_probe_module("auth", module_name) && 
384                            !(entry = auth_find_backend_entry(module_name))) {
385                                 DEBUG(0,("make_auth_context_text_list: can't find auth method %s!\n", module_name));
386                         } else if (!NT_STATUS_IS_OK(entry->init(*auth_context, module_params, &t))) {
387                                 DEBUG(0,("make_auth_context_text_list: auth method %s did not correctly init\n",
388                                                         *text_list));
389                         } else {
390                                 DEBUG(5,("make_auth_context_text_list: auth method %s has a valid init\n",
391                                                         *text_list));
392                                 DLIST_ADD_END(list, t, tmp);
393                         }
394                         SAFE_FREE(module_name);
395         }
396         
397         (*auth_context)->auth_method_list = list;
398         
399         return nt_status;
400 }
401
402 /***************************************************************************
403  Make a auth_context struct for the auth subsystem
404 ***************************************************************************/
405
406 NTSTATUS make_auth_context_subsystem(struct auth_context **auth_context) 
407 {
408         char **auth_method_list = NULL; 
409         NTSTATUS nt_status;
410
411         if (lp_auth_methods() && !str_list_copy(&auth_method_list, lp_auth_methods())) {
412                 return NT_STATUS_NO_MEMORY;
413         }
414
415         if (auth_method_list == NULL) {
416                 switch (lp_security()) 
417                 {
418                 case SEC_DOMAIN:
419                         DEBUG(5,("Making default auth method list for security=domain\n"));
420                         auth_method_list = str_list_make("guest sam winbind ntdomain", NULL);
421                         break;
422                 case SEC_SERVER:
423                         DEBUG(5,("Making default auth method list for security=server\n"));
424                         auth_method_list = str_list_make("guest sam smbserver", NULL);
425                         break;
426                 case SEC_USER:
427                         if (lp_encrypted_passwords()) { 
428                                 DEBUG(5,("Making default auth method list for security=user, encrypt passwords = yes\n"));
429                                 auth_method_list = str_list_make("guest sam", NULL);
430                         } else {
431                                 DEBUG(5,("Making default auth method list for security=user, encrypt passwords = no\n"));
432                                 auth_method_list = str_list_make("guest unix", NULL);
433                         }
434                         break;
435                 case SEC_SHARE:
436                         if (lp_encrypted_passwords()) {
437                                 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = yes\n"));
438                                 auth_method_list = str_list_make("guest sam", NULL);
439                         } else {
440                                 DEBUG(5,("Making default auth method list for security=share, encrypt passwords = no\n"));
441                                 auth_method_list = str_list_make("guest unix", NULL);
442                         }
443                         break;
444                 case SEC_ADS:
445                         DEBUG(5,("Making default auth method list for security=ADS\n"));
446                         auth_method_list = str_list_make("guest sam winbind ntdomain", NULL);
447                         break;
448                 default:
449                         DEBUG(5,("Unknown auth method!\n"));
450                         return NT_STATUS_UNSUCCESSFUL;
451                 }
452         } else {
453                 DEBUG(5,("Using specified auth order\n"));
454         }
455         
456         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_text_list(auth_context, auth_method_list))) {
457                 str_list_free(&auth_method_list);
458                 return nt_status;
459         }
460         
461         str_list_free(&auth_method_list);
462         return nt_status;
463 }
464
465 /***************************************************************************
466  Make a auth_info struct with a fixed challenge
467 ***************************************************************************/
468
469 NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[8]) 
470 {
471         NTSTATUS nt_status;
472         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(auth_context))) {
473                 return nt_status;
474         }
475         
476         (*auth_context)->challenge = data_blob(chal, 8);
477         (*auth_context)->challenge_set_by = "fixed";
478         return nt_status;
479 }
480
481