r25035: Fix some more warnings, use service pointer rather than service number in...
[bbaumbach/samba-autobuild/.git] / source4 / 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, 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 auth_context **auth_ctx)
357 {
358         int i;
359         struct auth_context *ctx;
360
361         if (!methods) {
362                 DEBUG(0,("auth_context_create: No auth method list!?\n"));
363                 return NT_STATUS_INTERNAL_ERROR;
364         }
365
366         if (!ev) {
367                 DEBUG(0,("auth_context_create: called with out event context\n"));
368                 return NT_STATUS_INTERNAL_ERROR;
369         }
370
371         if (!msg) {
372                 DEBUG(0,("auth_context_create: called with out messaging context\n"));
373                 return NT_STATUS_INTERNAL_ERROR;
374         }
375
376         ctx = talloc(mem_ctx, struct auth_context);
377         NT_STATUS_HAVE_NO_MEMORY(ctx);
378         ctx->challenge.set_by           = NULL;
379         ctx->challenge.may_be_modified  = False;
380         ctx->challenge.data             = data_blob(NULL, 0);
381         ctx->methods                    = NULL;
382         ctx->event_ctx                  = ev;
383         ctx->msg_ctx                    = msg;
384
385         for (i=0; methods[i] ; i++) {
386                 struct auth_method_context *method;
387
388                 method = talloc(ctx, struct auth_method_context);
389                 NT_STATUS_HAVE_NO_MEMORY(method);
390
391                 method->ops = auth_backend_byname(methods[i]);
392                 if (!method->ops) {
393                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
394                                 methods[i]));
395                         return NT_STATUS_INTERNAL_ERROR;
396                 }
397                 method->auth_ctx        = ctx;
398                 method->depth           = i;
399                 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
400         }
401
402         if (!ctx->methods) {
403                 return NT_STATUS_INTERNAL_ERROR;
404         }
405
406         *auth_ctx = ctx;
407
408         return NT_STATUS_OK;
409 }
410 /***************************************************************************
411  Make a auth_info struct for the auth subsystem
412  - Uses default auth_methods, depending on server role and smb.conf settings
413 ***************************************************************************/
414 NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, 
415                              struct event_context *ev,
416                              struct messaging_context *msg,
417                              struct auth_context **auth_ctx)
418 {
419         const char **auth_methods = NULL;
420         switch (lp_server_role()) {
421         case ROLE_STANDALONE:
422                 auth_methods = lp_parm_string_list(NULL, "auth methods", "standalone", NULL);
423                 break;
424         case ROLE_DOMAIN_MEMBER:
425                 auth_methods = lp_parm_string_list(NULL, "auth methods", "member server", NULL);
426                 break;
427         case ROLE_DOMAIN_CONTROLLER:
428                 auth_methods = lp_parm_string_list(NULL, "auth methods", "domain controller", NULL);
429                 break;
430         }
431         return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, auth_ctx);
432 }
433
434
435 /* the list of currently registered AUTH backends */
436 static struct auth_backend {
437         const struct auth_operations *ops;
438 } *backends = NULL;
439 static int num_backends;
440
441 /*
442   register a AUTH backend. 
443
444   The 'name' can be later used by other backends to find the operations
445   structure for this backend.
446 */
447 NTSTATUS auth_register(const struct auth_operations *ops)
448 {
449         struct auth_operations *new_ops;
450         
451         if (auth_backend_byname(ops->name) != NULL) {
452                 /* its already registered! */
453                 DEBUG(0,("AUTH backend '%s' already registered\n", 
454                          ops->name));
455                 return NT_STATUS_OBJECT_NAME_COLLISION;
456         }
457
458         backends = realloc_p(backends, struct auth_backend, num_backends+1);
459         if (!backends) {
460                 return NT_STATUS_NO_MEMORY;
461         }
462
463         new_ops = smb_xmemdup(ops, sizeof(*ops));
464         new_ops->name = smb_xstrdup(ops->name);
465
466         backends[num_backends].ops = new_ops;
467
468         num_backends++;
469
470         DEBUG(3,("AUTH backend '%s' registered\n", 
471                  ops->name));
472
473         return NT_STATUS_OK;
474 }
475
476 /*
477   return the operations structure for a named backend of the specified type
478 */
479 const struct auth_operations *auth_backend_byname(const char *name)
480 {
481         int i;
482
483         for (i=0;i<num_backends;i++) {
484                 if (strcmp(backends[i].ops->name, name) == 0) {
485                         return backends[i].ops;
486                 }
487         }
488
489         return NULL;
490 }
491
492 /*
493   return the AUTH interface version, and the size of some critical types
494   This can be used by backends to either detect compilation errors, or provide
495   multiple implementations for different smbd compilation options in one module
496 */
497 const struct auth_critical_sizes *auth_interface_version(void)
498 {
499         static const struct auth_critical_sizes critical_sizes = {
500                 AUTH_INTERFACE_VERSION,
501                 sizeof(struct auth_operations),
502                 sizeof(struct auth_method_context),
503                 sizeof(struct auth_context),
504                 sizeof(struct auth_usersupplied_info),
505                 sizeof(struct auth_serversupplied_info)
506         };
507
508         return &critical_sizes;
509 }
510
511 NTSTATUS auth_init(void)
512 {
513         static BOOL initialized = False;
514
515         init_module_fn static_init[] = STATIC_auth_MODULES;
516         init_module_fn *shared_init;
517         
518         if (initialized) return NT_STATUS_OK;
519         initialized = True;
520         
521         shared_init = load_samba_modules(NULL, "auth");
522
523         run_init_functions(static_init);
524         run_init_functions(shared_init);
525
526         talloc_free(shared_init);
527         
528         return NT_STATUS_OK;    
529 }
530
531 NTSTATUS server_service_auth_init(void)
532 {
533         return auth_init();
534 }