r26233: Pass loadparm context when creating krb5 contexts.
[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    Copyright (C) Stefan Metzmacher       2005
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "lib/util/dlinklist.h"
23 #include "auth/auth.h"
24 #include "lib/events/events.h"
25 #include "build.h"
26 #include "param/param.h"
27
28 /***************************************************************************
29  Set a fixed challenge
30 ***************************************************************************/
31 NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) 
32 {
33         auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
34         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
35
36         auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
37         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
38
39         return NT_STATUS_OK;
40 }
41
42 /***************************************************************************
43  Set a fixed challenge
44 ***************************************************************************/
45 bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) 
46 {
47         return auth_ctx->challenge.may_be_modified;
48 }
49
50 /****************************************************************************
51  Try to get a challenge out of the various authentication modules.
52  Returns a const char of length 8 bytes.
53 ****************************************************************************/
54 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
55 {
56         NTSTATUS nt_status;
57         struct auth_method_context *method;
58
59         if (auth_ctx->challenge.data.length) {
60                 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", 
61                           auth_ctx->challenge.set_by));
62                 *_chal = auth_ctx->challenge.data.data;
63                 return NT_STATUS_OK;
64         }
65
66         for (method = auth_ctx->methods; method; method = method->next) {
67                 DATA_BLOB challenge = data_blob(NULL,0);
68
69                 nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
70                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
71                         continue;
72                 }
73
74                 NT_STATUS_NOT_OK_RETURN(nt_status);
75
76                 if (challenge.length != 8) {
77                         DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n",
78                                 (unsigned)challenge.length, method->ops->name));
79                         return NT_STATUS_INTERNAL_ERROR;
80                 }
81
82                 auth_ctx->challenge.data        = challenge;
83                 auth_ctx->challenge.set_by      = method->ops->name;
84
85                 break;
86         }
87
88         if (!auth_ctx->challenge.set_by) {
89                 uint8_t chal[8];
90                 generate_random_buffer(chal, 8);
91
92                 auth_ctx->challenge.data                = data_blob_talloc(auth_ctx, chal, 8);
93                 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
94                 auth_ctx->challenge.set_by              = "random";
95
96                 auth_ctx->challenge.may_be_modified     = true;
97         }
98
99         DEBUG(10,("auth_get_challenge: challenge set by %s\n",
100                  auth_ctx->challenge.set_by));
101
102         *_chal = auth_ctx->challenge.data.data;
103         return NT_STATUS_OK;
104 }
105
106 struct auth_check_password_sync_state {
107         bool finished;
108         NTSTATUS status;
109         struct auth_serversupplied_info *server_info;
110 };
111
112 static void auth_check_password_sync_callback(struct auth_check_password_request *req,
113                                               void *private_data)
114 {
115         struct auth_check_password_sync_state *s = talloc_get_type(private_data,
116                                                    struct auth_check_password_sync_state);
117
118         s->finished = true;
119         s->status = auth_check_password_recv(req, s, &s->server_info);
120 }
121
122 /**
123  * Check a user's Plaintext, LM or NTLM password.
124  * (sync version)
125  *
126  * Check a user's password, as given in the user_info struct and return various
127  * interesting details in the server_info struct.
128  *
129  * The return value takes precedence over the contents of the server_info 
130  * struct.  When the return is other than NT_STATUS_OK the contents 
131  * of that structure is undefined.
132  *
133  * @param auth_ctx Supplies the challenges and some other data. 
134  *                  Must be created with auth_context_create(), and the challenges should be 
135  *                  filled in, either at creation or by calling the challenge geneation 
136  *                  function auth_get_challenge().  
137  *
138  * @param user_info Contains the user supplied components, including the passwords.
139  *
140  * @param mem_ctx The parent memory context for the server_info structure
141  *
142  * @param server_info If successful, contains information about the authentication, 
143  *                    including a SAM_ACCOUNT struct describing the user.
144  *
145  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
146  *
147  **/
148
149 NTSTATUS auth_check_password(struct auth_context *auth_ctx,
150                              TALLOC_CTX *mem_ctx,
151                              const struct auth_usersupplied_info *user_info, 
152                              struct auth_serversupplied_info **server_info)
153 {
154         struct auth_check_password_sync_state *sync_state;
155         NTSTATUS status;
156
157         sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state);
158         NT_STATUS_HAVE_NO_MEMORY(sync_state);
159
160         auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state);
161
162         while (!sync_state->finished) {
163                 event_loop_once(auth_ctx->event_ctx);
164         }
165
166         status = sync_state->status;
167
168         if (NT_STATUS_IS_OK(status)) {
169                 *server_info = talloc_steal(mem_ctx, sync_state->server_info);
170         }
171
172         talloc_free(sync_state);
173         return status;
174 }
175
176 struct auth_check_password_request {
177         struct auth_context *auth_ctx;
178         const struct auth_usersupplied_info *user_info;
179         struct auth_serversupplied_info *server_info;
180         struct auth_method_context *method;
181         NTSTATUS status;
182         struct {
183                 void (*fn)(struct auth_check_password_request *req, void *private_data);
184                 void *private_data;
185         } callback;
186 };
187
188 static void auth_check_password_async_timed_handler(struct event_context *ev, struct timed_event *te,
189                                                     struct timeval t, void *ptr)
190 {
191         struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request);
192         req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info);
193         req->callback.fn(req, req->callback.private_data);
194 }
195
196 /**
197  * Check a user's Plaintext, LM or NTLM password.
198  * async send hook
199  *
200  * Check a user's password, as given in the user_info struct and return various
201  * interesting details in the server_info struct.
202  *
203  * The return value takes precedence over the contents of the server_info 
204  * struct.  When the return is other than NT_STATUS_OK the contents 
205  * of that structure is undefined.
206  *
207  * @param auth_ctx Supplies the challenges and some other data. 
208  *                  Must be created with make_auth_context(), and the challenges should be 
209  *                  filled in, either at creation or by calling the challenge geneation 
210  *                  function auth_get_challenge().  
211  *
212  * @param user_info Contains the user supplied components, including the passwords.
213  *
214  * @param callback A callback function which will be called when the operation is finished.
215  *                 The callback function needs to call auth_check_password_recv() to get the return values
216  *
217  * @param private_data A private pointer which will ba passed to the callback function
218  *
219  **/
220
221 void auth_check_password_send(struct auth_context *auth_ctx,
222                               const struct auth_usersupplied_info *user_info,
223                               void (*callback)(struct auth_check_password_request *req, void *private_data),
224                               void *private_data)
225 {
226         /* if all the modules say 'not for me' this is reasonable */
227         NTSTATUS nt_status;
228         struct auth_method_context *method;
229         const uint8_t *challenge;
230         struct auth_usersupplied_info *user_info_tmp;
231         struct auth_check_password_request *req = NULL;
232
233         DEBUG(3,   ("auth_check_password_send:  Checking password for unmapped user [%s]\\[%s]@[%s]\n", 
234                     user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
235
236         req = talloc_zero(auth_ctx, struct auth_check_password_request);
237         if (!req) {
238                 callback(NULL, private_data);
239                 return;
240         }
241         req->auth_ctx                   = auth_ctx;
242         req->user_info                  = user_info;
243         req->callback.fn                = callback;
244         req->callback.private_data      = private_data;
245
246         if (!user_info->mapped_state) {
247                 nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp);
248                 if (!NT_STATUS_IS_OK(nt_status)) goto failed;
249                 user_info = user_info_tmp;
250                 req->user_info  = user_info_tmp;
251         }
252
253         DEBUGADD(3,("auth_check_password_send:  mapped user is: [%s]\\[%s]@[%s]\n", 
254                     user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
255
256         nt_status = auth_get_challenge(auth_ctx, &challenge);
257         if (!NT_STATUS_IS_OK(nt_status)) {
258                 DEBUG(0, ("auth_check_password_send:  Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
259                         (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
260                 goto failed;
261         }
262
263         if (auth_ctx->challenge.set_by) {
264                 DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n",
265                                         auth_ctx->challenge.set_by));
266         }
267
268         DEBUG(10, ("auth_check_password_send: challenge is: \n"));
269         dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
270
271         nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
272         for (method = auth_ctx->methods; method; method = method->next) {
273                 NTSTATUS result;
274                 struct timed_event *te = NULL;
275
276                 /* check if the module wants to chek the password */
277                 result = method->ops->want_check(method, req, user_info);
278                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
279                         DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name));
280                         continue;
281                 }
282
283                 nt_status = result;
284                 req->method     = method;
285
286                 if (!NT_STATUS_IS_OK(nt_status)) break;
287
288                 te = event_add_timed(auth_ctx->event_ctx, req,
289                                      timeval_zero(),
290                                      auth_check_password_async_timed_handler, req);
291                 if (!te) {
292                         nt_status = NT_STATUS_NO_MEMORY;
293                         goto failed;
294                 }
295                 return;
296         }
297
298 failed:
299         req->status = nt_status;
300         req->callback.fn(req, req->callback.private_data);
301 }
302
303 /**
304  * Check a user's Plaintext, LM or NTLM password.
305  * async receive function
306  *
307  * The return value takes precedence over the contents of the server_info 
308  * struct.  When the return is other than NT_STATUS_OK the contents 
309  * of that structure is undefined.
310  *
311  *
312  * @param req The async auth_check_password state, passes to the callers callback function
313  *
314  * @param mem_ctx The parent memory context for the server_info structure
315  *
316  * @param server_info If successful, contains information about the authentication, 
317  *                    including a SAM_ACCOUNT struct describing the user.
318  *
319  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
320  *
321  **/
322
323 NTSTATUS auth_check_password_recv(struct auth_check_password_request *req,
324                                   TALLOC_CTX *mem_ctx,
325                                   struct auth_serversupplied_info **server_info)
326 {
327         NTSTATUS status;
328
329         NT_STATUS_HAVE_NO_MEMORY(req);
330
331         if (NT_STATUS_IS_OK(req->status)) {
332                 DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n",
333                          req->method->ops->name, req->server_info->domain_name, req->server_info->account_name));
334
335                 *server_info = talloc_steal(mem_ctx, req->server_info);
336         } else {
337                 DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n", 
338                          (req->method ? req->method->ops->name : "NO_METHOD"),
339                          req->user_info->mapped.domain_name,
340                          req->user_info->mapped.account_name, 
341                          nt_errstr(req->status)));
342         }
343
344         status = req->status;
345         talloc_free(req);
346         return status;
347 }
348
349 /***************************************************************************
350  Make a auth_info struct for the auth subsystem
351  - Allow the caller to specify the methods to use
352 ***************************************************************************/
353 NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, 
354                                      struct event_context *ev,
355                                      struct messaging_context *msg,
356                                      struct loadparm_context *lp_ctx,
357                                      struct auth_context **auth_ctx)
358 {
359         int i;
360         struct auth_context *ctx;
361
362         if (!methods) {
363                 DEBUG(0,("auth_context_create: No auth method list!?\n"));
364                 return NT_STATUS_INTERNAL_ERROR;
365         }
366
367         if (!ev) {
368                 DEBUG(0,("auth_context_create: called with out event context\n"));
369                 return NT_STATUS_INTERNAL_ERROR;
370         }
371
372         if (!msg) {
373                 DEBUG(0,("auth_context_create: called with out messaging context\n"));
374                 return NT_STATUS_INTERNAL_ERROR;
375         }
376
377         ctx = talloc(mem_ctx, struct auth_context);
378         NT_STATUS_HAVE_NO_MEMORY(ctx);
379         ctx->challenge.set_by           = NULL;
380         ctx->challenge.may_be_modified  = false;
381         ctx->challenge.data             = data_blob(NULL, 0);
382         ctx->methods                    = NULL;
383         ctx->event_ctx                  = ev;
384         ctx->msg_ctx                    = msg;
385         ctx->lp_ctx                     = lp_ctx;
386
387         for (i=0; methods[i] ; i++) {
388                 struct auth_method_context *method;
389
390                 method = talloc(ctx, struct auth_method_context);
391                 NT_STATUS_HAVE_NO_MEMORY(method);
392
393                 method->ops = auth_backend_byname(methods[i]);
394                 if (!method->ops) {
395                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
396                                 methods[i]));
397                         return NT_STATUS_INTERNAL_ERROR;
398                 }
399                 method->auth_ctx        = ctx;
400                 method->depth           = i;
401                 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
402         }
403
404         if (!ctx->methods) {
405                 return NT_STATUS_INTERNAL_ERROR;
406         }
407
408         *auth_ctx = ctx;
409
410         return NT_STATUS_OK;
411 }
412 /***************************************************************************
413  Make a auth_info struct for the auth subsystem
414  - Uses default auth_methods, depending on server role and smb.conf settings
415 ***************************************************************************/
416 NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, 
417                              struct event_context *ev,
418                              struct messaging_context *msg,
419                              struct loadparm_context *lp_ctx,
420                              struct auth_context **auth_ctx)
421 {
422         const char **auth_methods = NULL;
423         switch (lp_server_role(lp_ctx)) {
424         case ROLE_STANDALONE:
425                 auth_methods = lp_parm_string_list(lp_ctx, NULL, "auth methods", "standalone", NULL);
426                 break;
427         case ROLE_DOMAIN_MEMBER:
428                 auth_methods = lp_parm_string_list(lp_ctx, NULL, "auth methods", "member server", NULL);
429                 break;
430         case ROLE_DOMAIN_CONTROLLER:
431                 auth_methods = lp_parm_string_list(lp_ctx, NULL, "auth methods", "domain controller", NULL);
432                 break;
433         }
434         return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx);
435 }
436
437
438 /* the list of currently registered AUTH backends */
439 static struct auth_backend {
440         const struct auth_operations *ops;
441 } *backends = NULL;
442 static int num_backends;
443
444 /*
445   register a AUTH backend. 
446
447   The 'name' can be later used by other backends to find the operations
448   structure for this backend.
449 */
450 NTSTATUS auth_register(const struct auth_operations *ops)
451 {
452         struct auth_operations *new_ops;
453         
454         if (auth_backend_byname(ops->name) != NULL) {
455                 /* its already registered! */
456                 DEBUG(0,("AUTH backend '%s' already registered\n", 
457                          ops->name));
458                 return NT_STATUS_OBJECT_NAME_COLLISION;
459         }
460
461         backends = talloc_realloc(talloc_autofree_context(), backends, 
462                                   struct auth_backend, num_backends+1);
463         NT_STATUS_HAVE_NO_MEMORY(backends);
464
465         new_ops = talloc_memdup(backends, ops, sizeof(*ops));
466         NT_STATUS_HAVE_NO_MEMORY(new_ops);
467         new_ops->name = talloc_strdup(new_ops, ops->name);
468         NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
469
470         backends[num_backends].ops = new_ops;
471
472         num_backends++;
473
474         DEBUG(3,("AUTH backend '%s' registered\n", 
475                  ops->name));
476
477         return NT_STATUS_OK;
478 }
479
480 /*
481   return the operations structure for a named backend of the specified type
482 */
483 const struct auth_operations *auth_backend_byname(const char *name)
484 {
485         int i;
486
487         for (i=0;i<num_backends;i++) {
488                 if (strcmp(backends[i].ops->name, name) == 0) {
489                         return backends[i].ops;
490                 }
491         }
492
493         return NULL;
494 }
495
496 /*
497   return the AUTH interface version, and the size of some critical types
498   This can be used by backends to either detect compilation errors, or provide
499   multiple implementations for different smbd compilation options in one module
500 */
501 const struct auth_critical_sizes *auth_interface_version(void)
502 {
503         static const struct auth_critical_sizes critical_sizes = {
504                 AUTH_INTERFACE_VERSION,
505                 sizeof(struct auth_operations),
506                 sizeof(struct auth_method_context),
507                 sizeof(struct auth_context),
508                 sizeof(struct auth_usersupplied_info),
509                 sizeof(struct auth_serversupplied_info)
510         };
511
512         return &critical_sizes;
513 }
514
515 NTSTATUS auth_init(struct loadparm_context *lp_ctx)
516 {
517         static bool initialized = false;
518
519         init_module_fn static_init[] = STATIC_auth_MODULES;
520         init_module_fn *shared_init;
521         
522         if (initialized) return NT_STATUS_OK;
523         initialized = true;
524         
525         shared_init = load_samba_modules(NULL, lp_ctx, "auth");
526
527         run_init_functions(static_init);
528         run_init_functions(shared_init);
529
530         talloc_free(shared_init);
531         
532         return NT_STATUS_OK;    
533 }
534
535 NTSTATUS server_service_auth_init(void)
536 {
537         return auth_init(global_loadparm);
538 }