source: trunk/server/source4/auth/ntlm/auth.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

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