r19507: Merge my DSO fixes branch. Building Samba's libraries as shared libraries
[samba.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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "lib/util/dlinklist.h"
24 #include "auth/auth.h"
25 #include "lib/events/events.h"
26 #include "build.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 ***************************************************************************/
352 NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods, 
353                              struct event_context *ev,
354                              struct messaging_context *msg,
355                              struct auth_context **auth_ctx)
356 {
357         int i;
358         struct auth_context *ctx;
359
360         if (!methods) {
361                 DEBUG(0,("auth_context_create: No auth method list!?\n"));
362                 return NT_STATUS_INTERNAL_ERROR;
363         }
364
365         if (!ev) {
366                 DEBUG(0,("auth_context_create: called with out event context\n"));
367                 return NT_STATUS_INTERNAL_ERROR;
368         }
369
370         if (!msg) {
371                 DEBUG(0,("auth_context_create: called with out messaging context\n"));
372                 return NT_STATUS_INTERNAL_ERROR;
373         }
374
375         ctx = talloc(mem_ctx, struct auth_context);
376         NT_STATUS_HAVE_NO_MEMORY(ctx);
377         ctx->challenge.set_by           = NULL;
378         ctx->challenge.may_be_modified  = False;
379         ctx->challenge.data             = data_blob(NULL, 0);
380         ctx->methods                    = NULL;
381         ctx->event_ctx                  = ev;
382         ctx->msg_ctx                    = msg;
383
384         for (i=0; methods[i] ; i++) {
385                 struct auth_method_context *method;
386
387                 method = talloc(ctx, struct auth_method_context);
388                 NT_STATUS_HAVE_NO_MEMORY(method);
389
390                 method->ops = auth_backend_byname(methods[i]);
391                 if (!method->ops) {
392                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
393                                 methods[i]));
394                         return NT_STATUS_INTERNAL_ERROR;
395                 }
396                 method->auth_ctx        = ctx;
397                 method->depth           = i;
398                 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
399         }
400
401         if (!ctx->methods) {
402                 return NT_STATUS_INTERNAL_ERROR;
403         }
404
405         *auth_ctx = ctx;
406
407         return NT_STATUS_OK;
408 }
409
410 /* the list of currently registered AUTH backends */
411 static struct auth_backend {
412         const struct auth_operations *ops;
413 } *backends = NULL;
414 static int num_backends;
415
416 /*
417   register a AUTH backend. 
418
419   The 'name' can be later used by other backends to find the operations
420   structure for this backend.
421 */
422 NTSTATUS auth_register(const void *_ops)
423 {
424         const struct auth_operations *ops = _ops;
425         struct auth_operations *new_ops;
426         
427         if (auth_backend_byname(ops->name) != NULL) {
428                 /* its already registered! */
429                 DEBUG(0,("AUTH backend '%s' already registered\n", 
430                          ops->name));
431                 return NT_STATUS_OBJECT_NAME_COLLISION;
432         }
433
434         backends = realloc_p(backends, struct auth_backend, num_backends+1);
435         if (!backends) {
436                 return NT_STATUS_NO_MEMORY;
437         }
438
439         new_ops = smb_xmemdup(ops, sizeof(*ops));
440         new_ops->name = smb_xstrdup(ops->name);
441
442         backends[num_backends].ops = new_ops;
443
444         num_backends++;
445
446         DEBUG(3,("AUTH backend '%s' registered\n", 
447                  ops->name));
448
449         return NT_STATUS_OK;
450 }
451
452 /*
453   return the operations structure for a named backend of the specified type
454 */
455 const struct auth_operations *auth_backend_byname(const char *name)
456 {
457         int i;
458
459         for (i=0;i<num_backends;i++) {
460                 if (strcmp(backends[i].ops->name, name) == 0) {
461                         return backends[i].ops;
462                 }
463         }
464
465         return NULL;
466 }
467
468 /*
469   return the AUTH interface version, and the size of some critical types
470   This can be used by backends to either detect compilation errors, or provide
471   multiple implementations for different smbd compilation options in one module
472 */
473 const struct auth_critical_sizes *auth_interface_version(void)
474 {
475         static const struct auth_critical_sizes critical_sizes = {
476                 AUTH_INTERFACE_VERSION,
477                 sizeof(struct auth_operations),
478                 sizeof(struct auth_method_context),
479                 sizeof(struct auth_context),
480                 sizeof(struct auth_usersupplied_info),
481                 sizeof(struct auth_serversupplied_info)
482         };
483
484         return &critical_sizes;
485 }
486
487 NTSTATUS auth_init(void)
488 {
489         static BOOL initialized = False;
490
491         init_module_fn static_init[] = STATIC_auth_MODULES;
492         init_module_fn *shared_init;
493         
494         if (initialized) return NT_STATUS_OK;
495         initialized = True;
496         
497         shared_init = load_samba_modules(NULL, "auth");
498
499         run_init_functions(static_init);
500         run_init_functions(shared_init);
501
502         talloc_free(shared_init);
503         
504         return NT_STATUS_OK;    
505 }
506
507 NTSTATUS server_service_auth_init(void)
508 {
509         return auth_init();
510 }