r890: convert samba4 to use [u]int8_t instead of [u]int8
[jelmer/samba4-debian.git] / source / 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_t *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  * The return value takes precedence over the contents of the server_info 
137  * struct.  When the return is other than NT_STATUS_OK the contents 
138  * of that structure is undefined.
139  *
140  * @param user_info Contains the user supplied components, including the passwords.
141  *                  Must be created with make_user_info() or one of its wrappers.
142  *
143  * @param auth_context Supplies the challenges and some other data. 
144  *                  Must be created with make_auth_context(), and the challenges should be 
145  *                  filled in, either at creation or by calling the challenge geneation 
146  *                  function auth_get_challenge().  
147  *
148  * @param server_info If successful, contains information about the authentication, 
149  *                    including a SAM_ACCOUNT struct describing the user.
150  *
151  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
152  *
153  **/
154
155 static NTSTATUS check_ntlm_password(const struct auth_context *auth_context,
156                                     const struct auth_usersupplied_info *user_info, 
157                                     struct auth_serversupplied_info **server_info)
158 {
159         /* if all the modules say 'not for me' this is reasonable */
160         NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
161         auth_methods *auth_method;
162         TALLOC_CTX *mem_ctx;
163
164         if (!user_info || !auth_context || !server_info)
165                 return NT_STATUS_LOGON_FAILURE;
166
167         DEBUG(3, ("check_ntlm_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
168                   user_info->client_domain.str, user_info->smb_name.str, user_info->wksta_name.str));
169
170         DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
171                   user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
172
173         if (auth_context->challenge.length != 8) {
174                 DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
175                 return NT_STATUS_LOGON_FAILURE;
176         }
177
178         if (auth_context->challenge_set_by)
179                 DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
180                                         auth_context->challenge_set_by));
181
182         DEBUG(10, ("challenge is: \n"));
183         dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
184
185 #ifdef DEBUG_PASSWORD
186         DEBUG(100, ("user_info has passwords of length %d and %d\n", 
187                     user_info->lm_resp.length, user_info->nt_resp.length));
188         DEBUG(100, ("lm:\n"));
189         dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length);
190         DEBUG(100, ("nt:\n"));
191         dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length);
192 #endif
193
194         /* This needs to be sorted:  If it doesn't match, what should we do? */
195         if (!check_domain_match(user_info->smb_name.str, user_info->domain.str))
196                 return NT_STATUS_LOGON_FAILURE;
197
198         for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {
199                 NTSTATUS result;
200                 
201                 mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name, 
202                                             user_info->domain.str, user_info->smb_name.str);
203
204                 result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);
205
206                 /* check if the module did anything */
207                 if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) {
208                         DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name));
209                         talloc_destroy(mem_ctx);
210                         continue;
211                 }
212
213                 nt_status = result;
214
215                 if (NT_STATUS_IS_OK(nt_status)) {
216                         DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", 
217                                   auth_method->name, user_info->smb_name.str));
218                 } else {
219                         DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", 
220                                   auth_method->name, user_info->smb_name.str, nt_errstr(nt_status)));
221                 }
222
223                 talloc_destroy(mem_ctx);
224
225                 if ( NT_STATUS_IS_OK(nt_status))
226                 {
227                                 break;                  
228                 }
229         }
230
231         if (NT_STATUS_IS_OK(nt_status)) {
232                 if (NT_STATUS_IS_OK(nt_status)) {
233                         DEBUG((*server_info)->guest ? 5 : 2, 
234                               ("check_ntlm_password:  %sauthentication for user [%s] -> [%s] succeeded\n", 
235                                (*server_info)->guest ? "guest " : "", 
236                                user_info->smb_name.str, 
237                                user_info->internal_username.str));
238                 }
239         }
240
241         if (!NT_STATUS_IS_OK(nt_status)) {
242                 DEBUG(2, ("check_ntlm_password:  Authentication for user [%s] -> [%s] FAILED with error %s\n", 
243                           user_info->smb_name.str, user_info->internal_username.str, 
244                           nt_errstr(nt_status)));
245                 ZERO_STRUCTP(server_info);
246         }
247         return nt_status;
248 }
249
250 /***************************************************************************
251  Clear out a auth_context, and destroy the attached TALLOC_CTX
252 ***************************************************************************/
253
254 static void free_auth_context(struct auth_context **auth_context)
255 {
256         auth_methods *auth_method;
257
258         if (*auth_context) {
259                 /* Free private data of context's authentication methods */
260                 for (auth_method = (*auth_context)->auth_method_list; auth_method; auth_method = auth_method->next) {
261                         if (auth_method->free_private_data) {
262                                 auth_method->free_private_data (&auth_method->private_data);
263                                 auth_method->private_data = NULL;
264                         }
265                 }
266
267                 talloc_destroy((*auth_context)->mem_ctx);
268                 *auth_context = NULL;
269         }
270 }
271
272 /***************************************************************************
273  Make a auth_info struct
274 ***************************************************************************/
275
276 static NTSTATUS make_auth_context(struct auth_context **auth_context) 
277 {
278         TALLOC_CTX *mem_ctx;
279
280         mem_ctx = talloc_init("authentication context");
281         
282         *auth_context = talloc(mem_ctx, sizeof(**auth_context));
283         if (!*auth_context) {
284                 DEBUG(0,("make_auth_context: talloc failed!\n"));
285                 talloc_destroy(mem_ctx);
286                 return NT_STATUS_NO_MEMORY;
287         }
288         ZERO_STRUCTP(*auth_context);
289
290         (*auth_context)->mem_ctx = mem_ctx;
291         (*auth_context)->check_ntlm_password = check_ntlm_password;
292         (*auth_context)->get_ntlm_challenge = get_ntlm_challenge;
293         (*auth_context)->free = free_auth_context;
294         
295         return NT_STATUS_OK;
296 }
297
298 /***************************************************************************
299  Make a auth_info struct for the auth subsystem
300 ***************************************************************************/
301
302 static NTSTATUS make_auth_context_text_list(struct auth_context **auth_context, char **text_list) 
303 {
304         auth_methods *list = NULL;
305         auth_methods *t = NULL;
306         int i;
307         NTSTATUS nt_status;
308
309         if (!text_list) {
310                 DEBUG(2,("make_auth_context_text_list: No auth method list!?\n"));
311                 return NT_STATUS_UNSUCCESSFUL;
312         }
313         
314         if (!NT_STATUS_IS_OK(nt_status = make_auth_context(auth_context)))
315                 return nt_status;
316         
317         for (;*text_list; text_list++) {
318                 char *module_name = smb_xstrdup(*text_list);
319                 char *module_params = NULL;
320                 char *p;
321                 const struct auth_operations *ops;
322
323                 DEBUG(5,("make_auth_context_text_list: Attempting to find an auth method to match %s\n",
324                                         *text_list));
325
326                 p = strchr(module_name, ':');
327                 if (p) {
328                         *p = 0;
329                         module_params = p+1;
330                         trim_string(module_params, " ", " ");
331                 }
332
333                 trim_string(module_name, " ", " ");
334
335                 ops = auth_backend_byname(module_name);
336                 if (!ops) {
337                         DEBUG(5,("make_auth_context_text_list: Found auth method %s (at pos %d)\n", *text_list, i));
338                         SAFE_FREE(module_name);
339                         break;
340                 }
341
342                 if (NT_STATUS_IS_OK(ops->init(*auth_context, module_params, &t))) {
343                         DEBUG(5,("make_auth_context_text_list: auth method %s has a valid init\n",
344                                                 *text_list));
345                         DLIST_ADD_END(list, t, auth_methods *);
346                 } else {
347                         DEBUG(0,("make_auth_context_text_list: auth method %s did not correctly init\n",
348                                                 *text_list));
349                 }
350                 SAFE_FREE(module_name);
351         }
352         
353         (*auth_context)->auth_method_list = list;
354         
355         return nt_status;
356 }
357
358 /***************************************************************************
359  Make a auth_context struct for the auth subsystem
360 ***************************************************************************/
361
362 NTSTATUS make_auth_context_subsystem(struct auth_context **auth_context) 
363 {
364         char **auth_method_list = NULL; 
365         NTSTATUS nt_status;
366
367         if (lp_auth_methods() && !str_list_copy(&auth_method_list, lp_auth_methods())) {
368                 return NT_STATUS_NO_MEMORY;
369         }
370
371         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_text_list(auth_context, auth_method_list))) {
372                 str_list_free(&auth_method_list);
373                 return nt_status;
374         }
375         
376         str_list_free(&auth_method_list);
377         return nt_status;
378 }
379
380 /***************************************************************************
381  Make a auth_info struct with a fixed challenge
382 ***************************************************************************/
383
384 NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[8]) 
385 {
386         NTSTATUS nt_status;
387         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(auth_context))) {
388                 return nt_status;
389         }
390         
391         (*auth_context)->challenge = data_blob_talloc((*auth_context)->mem_ctx, chal, 8);
392         (*auth_context)->challenge_set_by = "fixed";
393         return nt_status;
394 }
395
396 /* the list of currently registered AUTH backends */
397 static struct {
398         const struct auth_operations *ops;
399 } *backends = NULL;
400 static int num_backends;
401
402 /*
403   register a AUTH backend. 
404
405   The 'name' can be later used by other backends to find the operations
406   structure for this backend.
407 */
408 static NTSTATUS auth_register(void *_ops)
409 {
410         const struct auth_operations *ops = _ops;
411         struct auth_operations *new_ops;
412         
413         if (auth_backend_byname(ops->name) != NULL) {
414                 /* its already registered! */
415                 DEBUG(0,("AUTH backend '%s' already registered\n", 
416                          ops->name));
417                 return NT_STATUS_OBJECT_NAME_COLLISION;
418         }
419
420         backends = Realloc(backends, sizeof(backends[0]) * (num_backends+1));
421         if (!backends) {
422                 smb_panic("out of memory in auth_register");
423         }
424
425         new_ops = smb_xmemdup(ops, sizeof(*ops));
426         new_ops->name = smb_xstrdup(ops->name);
427
428         backends[num_backends].ops = new_ops;
429
430         num_backends++;
431
432         DEBUG(3,("AUTH backend '%s' registered\n", 
433                  ops->name));
434
435         return NT_STATUS_OK;
436 }
437
438 /*
439   return the operations structure for a named backend of the specified type
440 */
441 const struct auth_operations *auth_backend_byname(const char *name)
442 {
443         int i;
444
445         for (i=0;i<num_backends;i++) {
446                 if (strcmp(backends[i].ops->name, name) == 0) {
447                         return backends[i].ops;
448                 }
449         }
450
451         return NULL;
452 }
453
454 /*
455   return the AUTH interface version, and the size of some critical types
456   This can be used by backends to either detect compilation errors, or provide
457   multiple implementations for different smbd compilation options in one module
458 */
459 const struct auth_critical_sizes *auth_interface_version(void)
460 {
461         static const struct auth_critical_sizes critical_sizes = {
462                 AUTH_INTERFACE_VERSION,
463                 sizeof(struct auth_operations),
464                 sizeof(struct auth_methods),
465                 sizeof(struct auth_context),
466                 sizeof(struct auth_ntlmssp_state),
467                 sizeof(struct auth_usersupplied_info),
468                 sizeof(struct auth_serversupplied_info),
469                 sizeof(struct auth_str),
470         };
471
472         return &critical_sizes;
473 }
474
475 /*
476   initialise the AUTH subsystem
477 */
478 BOOL auth_init(void)
479 {
480         NTSTATUS status;
481
482         status = register_subsystem("auth", auth_register); 
483         if (!NT_STATUS_IS_OK(status)) {
484                 return False;
485         }
486
487         /* FIXME: Perhaps panic if a basic backend, such as SAM, fails to initialise? */
488         static_init_auth;
489
490         DEBUG(3,("AUTH subsystem version %d initialised\n", AUTH_INTERFACE_VERSION));
491         return True;
492 }