Merge branch 'master' of git://git.samba.org/samba
[ira/wip.git] / source4 / auth / ntlm / 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 <tevent.h>
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "../lib/util/dlinklist.h"
25 #include "auth/auth.h"
26 #include "auth/ntlm/auth_proto.h"
27 #include "param/param.h"
28
29 /***************************************************************************
30  Set a fixed challenge
31 ***************************************************************************/
32 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) 
33 {
34         auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
35         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
36
37         auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
38         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
39
40         return NT_STATUS_OK;
41 }
42
43 /***************************************************************************
44  Set a fixed challenge
45 ***************************************************************************/
46 _PUBLIC_ bool auth_challenge_may_be_modified(struct auth_context *auth_ctx)
47 {
48         return auth_ctx->challenge.may_be_modified;
49 }
50
51 /****************************************************************************
52  Try to get a challenge out of the various authentication modules.
53  Returns a const char of length 8 bytes.
54 ****************************************************************************/
55 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, uint8_t chal[8])
56 {
57         NTSTATUS nt_status;
58         struct auth_method_context *method;
59
60         if (auth_ctx->challenge.data.length == 8) {
61                 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", 
62                           auth_ctx->challenge.set_by));
63                 memcpy(chal, auth_ctx->challenge.data.data, 8);
64                 return NT_STATUS_OK;
65         }
66
67         for (method = auth_ctx->methods; method; method = method->next) {
68                 nt_status = method->ops->get_challenge(method, auth_ctx, chal);
69                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
70                         continue;
71                 }
72
73                 NT_STATUS_NOT_OK_RETURN(nt_status);
74
75                 auth_ctx->challenge.data        = data_blob_talloc(auth_ctx, chal, 8);
76                 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
77                 auth_ctx->challenge.set_by      = method->ops->name;
78
79                 break;
80         }
81
82         if (!auth_ctx->challenge.set_by) {
83                 generate_random_buffer(chal, 8);
84
85                 auth_ctx->challenge.data                = data_blob_talloc(auth_ctx, chal, 8);
86                 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
87                 auth_ctx->challenge.set_by              = "random";
88
89                 auth_ctx->challenge.may_be_modified     = true;
90         }
91
92         DEBUG(10,("auth_get_challenge: challenge set by %s\n",
93                  auth_ctx->challenge.set_by));
94
95         return NT_STATUS_OK;
96 }
97
98 /****************************************************************************
99  Try to get a challenge out of the various authentication modules.
100  Returns a const char of length 8 bytes.
101 ****************************************************************************/
102 _PUBLIC_ NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx, 
103                                                   struct auth_context *auth_ctx,
104                                                   const char *principal,
105                                                   struct auth_serversupplied_info **server_info)
106 {
107         NTSTATUS nt_status;
108         struct auth_method_context *method;
109
110         for (method = auth_ctx->methods; method; method = method->next) {
111                 if (!method->ops->get_server_info_principal) {
112                         continue;
113                 }
114
115                 nt_status = method->ops->get_server_info_principal(mem_ctx, auth_ctx, principal, server_info);
116                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
117                         continue;
118                 }
119
120                 NT_STATUS_NOT_OK_RETURN(nt_status);
121
122                 break;
123         }
124
125         return NT_STATUS_OK;
126 }
127
128 /**
129  * Check a user's Plaintext, LM or NTLM password.
130  * (sync version)
131  *
132  * Check a user's password, as given in the user_info struct and return various
133  * interesting details in the server_info struct.
134  *
135  * The return value takes precedence over the contents of the server_info 
136  * struct.  When the return is other than NT_STATUS_OK the contents 
137  * of that structure is undefined.
138  *
139  * @param auth_ctx Supplies the challenges and some other data. 
140  *                  Must be created with auth_context_create(), and the challenges should be 
141  *                  filled in, either at creation or by calling the challenge geneation 
142  *                  function auth_get_challenge().  
143  *
144  * @param user_info Contains the user supplied components, including the passwords.
145  *
146  * @param mem_ctx The parent memory context for the server_info structure
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 _PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
156                              TALLOC_CTX *mem_ctx,
157                              const struct auth_usersupplied_info *user_info, 
158                              struct auth_serversupplied_info **server_info)
159 {
160         struct tevent_req *subreq;
161         struct tevent_context *ev;
162         bool ok;
163         NTSTATUS status;
164
165         /*TODO: create a new event context here! */
166         ev = auth_ctx->event_ctx;
167
168         subreq = auth_check_password_send(mem_ctx,
169                                           ev,
170                                           auth_ctx,
171                                           user_info);
172         if (subreq == NULL) {
173                 return NT_STATUS_NO_MEMORY;
174         }
175
176         ok = tevent_req_poll(subreq, ev);
177         if (!ok) {
178                 return NT_STATUS_INTERNAL_ERROR;
179         }
180
181         status = auth_check_password_recv(subreq, mem_ctx, server_info);
182         TALLOC_FREE(subreq);
183
184         return status;
185 }
186
187 struct auth_check_password_state {
188         struct auth_context *auth_ctx;
189         const struct auth_usersupplied_info *user_info;
190         struct auth_serversupplied_info *server_info;
191         struct auth_method_context *method;
192 };
193
194 static void auth_check_password_async_trigger(struct tevent_context *ev,
195                                               struct tevent_immediate *im,
196                                               void *private_data);
197 /**
198  * Check a user's Plaintext, LM or NTLM password.
199  * async send hook
200  *
201  * Check a user's password, as given in the user_info struct and return various
202  * interesting details in the server_info struct.
203  *
204  * The return value takes precedence over the contents of the server_info 
205  * struct.  When the return is other than NT_STATUS_OK the contents 
206  * of that structure is undefined.
207  *
208  * @param mem_ctx The memory context the request should operate on
209  *
210  * @param ev The tevent context the request should operate on
211  *
212  * @param auth_ctx Supplies the challenges and some other data. 
213  *                  Must be created with make_auth_context(), and the challenges should be 
214  *                  filled in, either at creation or by calling the challenge geneation 
215  *                  function auth_get_challenge().  
216  *
217  * @param user_info Contains the user supplied components, including the passwords.
218  *
219  * @return The request handle or NULL on no memory error.
220  *
221  **/
222
223 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
224                                 struct tevent_context *ev,
225                                 struct auth_context *auth_ctx,
226                                 const struct auth_usersupplied_info *user_info)
227 {
228         struct tevent_req *req;
229         struct auth_check_password_state *state;
230         /* if all the modules say 'not for me' this is reasonable */
231         NTSTATUS nt_status;
232         struct auth_method_context *method;
233         uint8_t chal[8];
234         struct auth_usersupplied_info *user_info_tmp;
235         struct tevent_immediate *im;
236
237         DEBUG(3,("auth_check_password_send: "
238                  "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
239                  user_info->client.domain_name, user_info->client.account_name,
240                  user_info->workstation_name));
241
242         req = tevent_req_create(mem_ctx, &state,
243                                 struct auth_check_password_state);
244         if (req == NULL) {
245                 return NULL;
246         }
247
248         state->auth_ctx         = auth_ctx;
249         state->user_info        = user_info;
250         state->method           = NULL;
251
252         if (!user_info->mapped_state) {
253                 nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx),
254                                           user_info, &user_info_tmp);
255                 if (tevent_req_nterror(req, nt_status)) {
256                         return tevent_req_post(req, ev);
257                 }
258                 user_info = user_info_tmp;
259                 state->user_info = user_info_tmp;
260         }
261
262         DEBUGADD(3,("auth_check_password_send: "
263                     "mapped user is: [%s]\\[%s]@[%s]\n",
264                     user_info->mapped.domain_name,
265                     user_info->mapped.account_name,
266                     user_info->workstation_name));
267
268         nt_status = auth_get_challenge(auth_ctx, chal);
269         if (tevent_req_nterror(req, nt_status)) {
270                 DEBUG(0,("auth_check_password_send: "
271                          "Invalid challenge (length %u) stored for "
272                          "this auth context set_by %s - cannot continue: %s\n",
273                         (unsigned)auth_ctx->challenge.data.length,
274                         auth_ctx->challenge.set_by,
275                         nt_errstr(nt_status)));
276                 return tevent_req_post(req, ev);
277         }
278
279         if (auth_ctx->challenge.set_by) {
280                 DEBUG(10,("auth_check_password_send: "
281                           "auth_context challenge created by %s\n",
282                           auth_ctx->challenge.set_by));
283         }
284
285         DEBUG(10, ("auth_check_password_send: challenge is: \n"));
286         dump_data(5, auth_ctx->challenge.data.data,
287                   auth_ctx->challenge.data.length);
288
289         im = tevent_create_immediate(state);
290         if (tevent_req_nomem(im, req)) {
291                 return tevent_req_post(req, ev);
292         }
293
294         for (method = auth_ctx->methods; method; method = method->next) {
295                 NTSTATUS result;
296
297                 /* check if the module wants to chek the password */
298                 result = method->ops->want_check(method, req, user_info);
299                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
300                         DEBUG(11,("auth_check_password_send: "
301                                   "%s had nothing to say\n",
302                                   method->ops->name));
303                         continue;
304                 }
305
306                 state->method = method;
307
308                 if (tevent_req_nterror(req, result)) {
309                         return tevent_req_post(req, ev);
310                 }
311
312                 tevent_schedule_immediate(im,
313                                           auth_ctx->event_ctx,
314                                           auth_check_password_async_trigger,
315                                           req);
316
317                 return req;
318         }
319
320         /* If all the modules say 'not for me', then this is reasonable */
321         tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
322         return tevent_req_post(req, ev);
323 }
324
325 static void auth_check_password_async_trigger(struct tevent_context *ev,
326                                               struct tevent_immediate *im,
327                                               void *private_data)
328 {
329         struct tevent_req *req =
330                 talloc_get_type_abort(private_data, struct tevent_req);
331         struct auth_check_password_state *state =
332                 tevent_req_data(req, struct auth_check_password_state);
333         NTSTATUS status;
334
335         status = state->method->ops->check_password(state->method,
336                                                     state,
337                                                     state->user_info,
338                                                     &state->server_info);
339         if (tevent_req_nterror(req, status)) {
340                 return;
341         }
342
343         tevent_req_done(req);
344 }
345
346 /**
347  * Check a user's Plaintext, LM or NTLM password.
348  * async receive function
349  *
350  * The return value takes precedence over the contents of the server_info 
351  * struct.  When the return is other than NT_STATUS_OK the contents 
352  * of that structure is undefined.
353  *
354  *
355  * @param req The async request state
356  *
357  * @param mem_ctx The parent memory context for the server_info structure
358  *
359  * @param server_info If successful, contains information about the authentication, 
360  *                    including a SAM_ACCOUNT struct describing the user.
361  *
362  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
363  *
364  **/
365
366 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
367                                   TALLOC_CTX *mem_ctx,
368                                   struct auth_serversupplied_info **server_info)
369 {
370         struct auth_check_password_state *state =
371                 tevent_req_data(req, struct auth_check_password_state);
372         NTSTATUS status;
373
374         if (tevent_req_is_nterror(req, &status)) {
375                 DEBUG(2,("auth_check_password_recv: "
376                          "%s authentication for user [%s\\%s]"
377                          "FAILED with error %s\n",
378                          (state->method ? state->method->ops->name : "NO_METHOD"),
379                          state->user_info->mapped.domain_name,
380                          state->user_info->mapped.account_name,
381                          nt_errstr(status)));
382                 tevent_req_received(req);
383                 return status;
384         }
385
386         DEBUG(5,("auth_check_password_recv: "
387                  "%s authentication for user [%s\\%s] succeeded\n",
388                  state->method->ops->name,
389                  state->server_info->domain_name,
390                  state->server_info->account_name));
391
392         *server_info = talloc_move(mem_ctx, &state->server_info);
393
394         tevent_req_received(req);
395         return NT_STATUS_OK;
396 }
397
398 /***************************************************************************
399  Make a auth_info struct for the auth subsystem
400  - Allow the caller to specify the methods to use
401 ***************************************************************************/
402 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, 
403                                      struct tevent_context *ev,
404                                      struct messaging_context *msg,
405                                      struct loadparm_context *lp_ctx,
406                                      struct auth_context **auth_ctx)
407 {
408         int i;
409         struct auth_context *ctx;
410
411         auth_init();
412
413         if (!methods) {
414                 DEBUG(0,("auth_context_create: No auth method list!?\n"));
415                 return NT_STATUS_INTERNAL_ERROR;
416         }
417
418         if (!ev) {
419                 DEBUG(0,("auth_context_create: called with out event context\n"));
420                 return NT_STATUS_INTERNAL_ERROR;
421         }
422
423         if (!msg) {
424                 DEBUG(0,("auth_context_create: called with out messaging context\n"));
425                 return NT_STATUS_INTERNAL_ERROR;
426         }
427
428         ctx = talloc(mem_ctx, struct auth_context);
429         NT_STATUS_HAVE_NO_MEMORY(ctx);
430         ctx->challenge.set_by           = NULL;
431         ctx->challenge.may_be_modified  = false;
432         ctx->challenge.data             = data_blob(NULL, 0);
433         ctx->methods                    = NULL;
434         ctx->event_ctx                  = ev;
435         ctx->msg_ctx                    = msg;
436         ctx->lp_ctx                     = lp_ctx;
437
438         for (i=0; methods[i] ; i++) {
439                 struct auth_method_context *method;
440
441                 method = talloc(ctx, struct auth_method_context);
442                 NT_STATUS_HAVE_NO_MEMORY(method);
443
444                 method->ops = auth_backend_byname(methods[i]);
445                 if (!method->ops) {
446                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
447                                 methods[i]));
448                         return NT_STATUS_INTERNAL_ERROR;
449                 }
450                 method->auth_ctx        = ctx;
451                 method->depth           = i;
452                 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
453         }
454
455         if (!ctx->methods) {
456                 return NT_STATUS_INTERNAL_ERROR;
457         }
458
459         ctx->check_password = auth_check_password;
460         ctx->get_challenge = auth_get_challenge;
461         ctx->set_challenge = auth_context_set_challenge;
462         ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
463         ctx->get_server_info_principal = auth_get_server_info_principal;
464
465         *auth_ctx = ctx;
466
467         return NT_STATUS_OK;
468 }
469 /***************************************************************************
470  Make a auth_info struct for the auth subsystem
471  - Uses default auth_methods, depending on server role and smb.conf settings
472 ***************************************************************************/
473 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, 
474                              struct tevent_context *ev,
475                              struct messaging_context *msg,
476                              struct loadparm_context *lp_ctx,
477                              struct auth_context **auth_ctx)
478 {
479         const char **auth_methods = NULL;
480         switch (lp_server_role(lp_ctx)) {
481         case ROLE_STANDALONE:
482                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
483                 break;
484         case ROLE_DOMAIN_MEMBER:
485                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
486                 break;
487         case ROLE_DOMAIN_CONTROLLER:
488                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
489                 break;
490         }
491         return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx);
492 }
493
494
495 /* the list of currently registered AUTH backends */
496 static struct auth_backend {
497         const struct auth_operations *ops;
498 } *backends = NULL;
499 static int num_backends;
500
501 /*
502   register a AUTH backend. 
503
504   The 'name' can be later used by other backends to find the operations
505   structure for this backend.
506 */
507 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
508 {
509         struct auth_operations *new_ops;
510         
511         if (auth_backend_byname(ops->name) != NULL) {
512                 /* its already registered! */
513                 DEBUG(0,("AUTH backend '%s' already registered\n", 
514                          ops->name));
515                 return NT_STATUS_OBJECT_NAME_COLLISION;
516         }
517
518         backends = talloc_realloc(talloc_autofree_context(), backends, 
519                                   struct auth_backend, num_backends+1);
520         NT_STATUS_HAVE_NO_MEMORY(backends);
521
522         new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
523         NT_STATUS_HAVE_NO_MEMORY(new_ops);
524         new_ops->name = talloc_strdup(new_ops, ops->name);
525         NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
526
527         backends[num_backends].ops = new_ops;
528
529         num_backends++;
530
531         DEBUG(3,("AUTH backend '%s' registered\n", 
532                  ops->name));
533
534         return NT_STATUS_OK;
535 }
536
537 /*
538   return the operations structure for a named backend of the specified type
539 */
540 const struct auth_operations *auth_backend_byname(const char *name)
541 {
542         int i;
543
544         for (i=0;i<num_backends;i++) {
545                 if (strcmp(backends[i].ops->name, name) == 0) {
546                         return backends[i].ops;
547                 }
548         }
549
550         return NULL;
551 }
552
553 /*
554   return the AUTH interface version, and the size of some critical types
555   This can be used by backends to either detect compilation errors, or provide
556   multiple implementations for different smbd compilation options in one module
557 */
558 const struct auth_critical_sizes *auth_interface_version(void)
559 {
560         static const struct auth_critical_sizes critical_sizes = {
561                 AUTH_INTERFACE_VERSION,
562                 sizeof(struct auth_operations),
563                 sizeof(struct auth_method_context),
564                 sizeof(struct auth_context),
565                 sizeof(struct auth_usersupplied_info),
566                 sizeof(struct auth_serversupplied_info)
567         };
568
569         return &critical_sizes;
570 }
571
572 _PUBLIC_ NTSTATUS auth_init(void)
573 {
574         static bool initialized = false;
575         extern NTSTATUS auth_developer_init(void);
576         extern NTSTATUS auth_winbind_init(void);
577         extern NTSTATUS auth_anonymous_init(void);
578         extern NTSTATUS auth_unix_init(void);
579         extern NTSTATUS auth_sam_init(void);
580         extern NTSTATUS auth_server_init(void);
581
582         init_module_fn static_init[] = { STATIC_auth_MODULES };
583         
584         if (initialized) return NT_STATUS_OK;
585         initialized = true;
586         
587         run_init_functions(static_init);
588         
589         return NT_STATUS_OK;    
590 }
591
592 NTSTATUS server_service_auth_init(void)
593 {
594         return auth_init();
595 }