2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett 2001-2002
5 Copyright (C) Stefan Metzmacher 2005
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.
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.
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/>.
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 #include "libcli/wbclient/wbclient.h"
30 #include "lib/util/samba_modules.h"
31 #include "auth/credentials/credentials.h"
32 #include "system/kerberos.h"
33 #include "auth/kerberos/kerberos.h"
34 #include "auth/kerberos/kerberos_util.h"
35 #include "libds/common/roles.h"
37 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
39 void *server_returned_info,
40 const char *original_user_name,
41 uint32_t session_info_flags,
42 struct auth_session_info **session_info);
44 /***************************************************************************
46 ***************************************************************************/
47 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
49 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
50 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
52 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
53 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
58 /****************************************************************************
59 Try to get a challenge out of the various authentication modules.
60 Returns a const char of length 8 bytes.
61 ****************************************************************************/
62 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth4_context *auth_ctx, uint8_t chal[8])
65 if (auth_ctx->challenge.data.length == 8) {
66 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
67 auth_ctx->challenge.set_by));
68 memcpy(chal, auth_ctx->challenge.data.data, 8);
72 if (!auth_ctx->challenge.set_by) {
73 generate_random_buffer(chal, 8);
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 = "random";
80 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
81 auth_ctx->challenge.set_by));
86 /****************************************************************************
87 Used in the gensec_gssapi and gensec_krb5 server-side code, where the
88 PAC isn't available, and for tokenGroups in the DSDB stack.
90 Supply either a principal or a DN
91 ****************************************************************************/
92 static NTSTATUS auth_generate_session_info_principal(struct auth4_context *auth_ctx,
94 const char *principal,
95 struct ldb_dn *user_dn,
96 uint32_t session_info_flags,
97 struct auth_session_info **session_info)
100 struct auth_method_context *method;
101 struct auth_user_info_dc *user_info_dc;
103 for (method = auth_ctx->methods; method; method = method->next) {
104 if (!method->ops->get_user_info_dc_principal) {
108 nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, &user_info_dc);
109 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
112 if (!NT_STATUS_IS_OK(nt_status)) {
116 nt_status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
118 user_info_dc->info->account_name,
119 session_info_flags, session_info);
120 talloc_free(user_info_dc);
125 return NT_STATUS_NOT_IMPLEMENTED;
129 * Check a user's Plaintext, LM or NTLM password.
132 * Check a user's password, as given in the user_info struct and return various
133 * interesting details in the user_info_dc struct.
135 * The return value takes precedence over the contents of the user_info_dc
136 * struct. When the return is other than NT_STATUS_OK the contents
137 * of that structure is undefined.
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().
144 * @param user_info Contains the user supplied components, including the passwords.
146 * @param mem_ctx The parent memory context for the user_info_dc structure
148 * @param user_info_dc If successful, contains information about the authentication,
149 * including a SAM_ACCOUNT struct describing the user.
151 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
155 _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx,
157 const struct auth_usersupplied_info *user_info,
158 struct auth_user_info_dc **user_info_dc)
160 struct tevent_req *subreq;
161 struct tevent_context *ev;
165 /*TODO: create a new event context here! */
166 ev = auth_ctx->event_ctx;
168 subreq = auth_check_password_send(mem_ctx,
172 if (subreq == NULL) {
173 return NT_STATUS_NO_MEMORY;
176 ok = tevent_req_poll(subreq, ev);
178 return NT_STATUS_INTERNAL_ERROR;
181 status = auth_check_password_recv(subreq, mem_ctx, user_info_dc);
187 static NTSTATUS auth_check_password_wrapper(struct auth4_context *auth_ctx,
189 const struct auth_usersupplied_info *user_info,
190 void **server_returned_info,
191 DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
193 struct auth_user_info_dc *user_info_dc;
196 status = auth_check_password(auth_ctx, mem_ctx, user_info,
198 if (!NT_STATUS_IS_OK(status)) {
202 *server_returned_info = user_info_dc;
204 if (user_session_key) {
205 DEBUG(10, ("Got NT session key of length %u\n",
206 (unsigned)user_info_dc->user_session_key.length));
207 *user_session_key = user_info_dc->user_session_key;
208 talloc_steal(mem_ctx, user_session_key->data);
209 user_info_dc->user_session_key = data_blob_null;
212 if (lm_session_key) {
213 DEBUG(10, ("Got LM session key of length %u\n",
214 (unsigned)user_info_dc->lm_session_key.length));
215 *lm_session_key = user_info_dc->lm_session_key;
216 talloc_steal(mem_ctx, lm_session_key->data);
217 user_info_dc->lm_session_key = data_blob_null;
223 struct auth_check_password_state {
224 struct auth4_context *auth_ctx;
225 const struct auth_usersupplied_info *user_info;
226 struct auth_user_info_dc *user_info_dc;
227 struct auth_method_context *method;
230 static void auth_check_password_async_trigger(struct tevent_context *ev,
231 struct tevent_immediate *im,
234 * Check a user's Plaintext, LM or NTLM password.
237 * Check a user's password, as given in the user_info struct and return various
238 * interesting details in the user_info_dc struct.
240 * The return value takes precedence over the contents of the user_info_dc
241 * struct. When the return is other than NT_STATUS_OK the contents
242 * of that structure is undefined.
244 * @param mem_ctx The memory context the request should operate on
246 * @param ev The tevent context the request should operate on
248 * @param auth_ctx Supplies the challenges and some other data.
249 * Must be created with make_auth_context(), and the challenges should be
250 * filled in, either at creation or by calling the challenge geneation
251 * function auth_get_challenge().
253 * @param user_info Contains the user supplied components, including the passwords.
255 * @return The request handle or NULL on no memory error.
259 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
260 struct tevent_context *ev,
261 struct auth4_context *auth_ctx,
262 const struct auth_usersupplied_info *user_info)
264 struct tevent_req *req;
265 struct auth_check_password_state *state;
266 /* if all the modules say 'not for me' this is reasonable */
269 struct tevent_immediate *im;
271 DEBUG(3,("auth_check_password_send: "
272 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
273 user_info->client.domain_name, user_info->client.account_name,
274 user_info->workstation_name));
276 req = tevent_req_create(mem_ctx, &state,
277 struct auth_check_password_state);
282 state->auth_ctx = auth_ctx;
283 state->user_info = user_info;
285 if (!user_info->mapped_state) {
286 int server_role = lpcfg_server_role(auth_ctx->lp_ctx);
287 struct auth_usersupplied_info *user_info_tmp;
289 nt_status = map_user_info(
290 auth_ctx->sam_ctx, req,
291 server_role == ROLE_ACTIVE_DIRECTORY_DC,
292 lpcfg_workgroup(auth_ctx->lp_ctx),
293 user_info, &user_info_tmp);
295 if (tevent_req_nterror(req, nt_status)) {
296 return tevent_req_post(req, ev);
298 user_info = user_info_tmp;
299 state->user_info = user_info_tmp;
302 DEBUGADD(3,("auth_check_password_send: "
303 "mapped user is: [%s]\\[%s]@[%s]\n",
304 user_info->mapped.domain_name,
305 user_info->mapped.account_name,
306 user_info->workstation_name));
308 nt_status = auth_get_challenge(auth_ctx, chal);
309 if (tevent_req_nterror(req, nt_status)) {
310 DEBUG(0,("auth_check_password_send: "
311 "Invalid challenge (length %u) stored for "
312 "this auth context set_by %s - cannot continue: %s\n",
313 (unsigned)auth_ctx->challenge.data.length,
314 auth_ctx->challenge.set_by,
315 nt_errstr(nt_status)));
316 return tevent_req_post(req, ev);
319 if (auth_ctx->challenge.set_by) {
320 DEBUG(10,("auth_check_password_send: "
321 "auth_context challenge created by %s\n",
322 auth_ctx->challenge.set_by));
325 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
326 dump_data(5, auth_ctx->challenge.data.data,
327 auth_ctx->challenge.data.length);
329 im = tevent_create_immediate(state);
330 if (tevent_req_nomem(im, req)) {
331 return tevent_req_post(req, ev);
334 tevent_schedule_immediate(im,
336 auth_check_password_async_trigger,
341 static void auth_check_password_async_trigger(struct tevent_context *ev,
342 struct tevent_immediate *im,
345 struct tevent_req *req =
346 talloc_get_type_abort(private_data, struct tevent_req);
347 struct auth_check_password_state *state =
348 tevent_req_data(req, struct auth_check_password_state);
350 struct auth_method_context *method;
352 status = NT_STATUS_OK;
354 for (method=state->auth_ctx->methods; method; method = method->next) {
356 if (state->user_info->flags & USER_INFO_LOCAL_SAM_ONLY
357 && !(method->ops->flags & AUTH_METHOD_LOCAL_SAM)) {
361 /* we fill in state->method here so debug messages in
362 the callers know which method failed */
363 state->method = method;
365 /* check if the module wants to check the password */
366 status = method->ops->want_check(method, req, state->user_info);
367 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
368 DEBUG(11,("auth_check_password_send: "
369 "%s had nothing to say\n",
374 if (tevent_req_nterror(req, status)) {
378 status = method->ops->check_password(method,
381 &state->user_info_dc);
382 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
383 /* the backend has handled the request */
388 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
389 if (!(state->user_info->flags & USER_INFO_LOCAL_SAM_ONLY)) {
390 /* don't expose the NT_STATUS_NOT_IMPLEMENTED
391 * internals, except when the caller is only probing
392 * one method, as they may do the fallback
394 status = NT_STATUS_NO_SUCH_USER;
398 if (tevent_req_nterror(req, status)) {
402 tevent_req_done(req);
406 * Check a user's Plaintext, LM or NTLM password.
407 * async receive function
409 * The return value takes precedence over the contents of the user_info_dc
410 * struct. When the return is other than NT_STATUS_OK the contents
411 * of that structure is undefined.
414 * @param req The async request state
416 * @param mem_ctx The parent memory context for the user_info_dc structure
418 * @param user_info_dc If successful, contains information about the authentication,
419 * including a SAM_ACCOUNT struct describing the user.
421 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
425 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
427 struct auth_user_info_dc **user_info_dc)
429 struct auth_check_password_state *state =
430 tevent_req_data(req, struct auth_check_password_state);
433 if (tevent_req_is_nterror(req, &status)) {
434 DEBUG(2,("auth_check_password_recv: "
435 "%s authentication for user [%s\\%s] "
436 "FAILED with error %s\n",
437 (state->method ? state->method->ops->name : "NO_METHOD"),
438 state->user_info->mapped.domain_name,
439 state->user_info->mapped.account_name,
441 tevent_req_received(req);
445 DEBUG(5,("auth_check_password_recv: "
446 "%s authentication for user [%s\\%s] succeeded\n",
447 state->method->ops->name,
448 state->user_info_dc->info->domain_name,
449 state->user_info_dc->info->account_name));
451 *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
453 tevent_req_received(req);
457 /* Wrapper because we don't want to expose all callers to needing to
458 * know that session_info is generated from the main ldb, and because
459 * we need to break a depenency loop between the DCE/RPC layer and the
460 * generation of unix tokens via IRPC */
461 static NTSTATUS auth_generate_session_info_wrapper(struct auth4_context *auth_context,
463 void *server_returned_info,
464 const char *original_user_name,
465 uint32_t session_info_flags,
466 struct auth_session_info **session_info)
469 struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
471 if (user_info_dc->info->authenticated) {
472 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
475 status = auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
476 auth_context->sam_ctx, user_info_dc,
477 session_info_flags, session_info);
478 if (!NT_STATUS_IS_OK(status)) {
482 if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
483 && NT_STATUS_IS_OK(status)) {
484 status = auth_session_info_fill_unix(auth_context->event_ctx,
485 auth_context->lp_ctx,
486 original_user_name, *session_info);
487 if (!NT_STATUS_IS_OK(status)) {
488 TALLOC_FREE(*session_info);
494 /* Wrapper because we don't want to expose all callers to needing to
495 * know anything about the PAC or auth subsystem internal structures
496 * before we output a struct auth session_info */
497 static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
499 struct smb_krb5_context *smb_krb5_context,
501 const char *principal_name,
502 const struct tsocket_address *remote_address,
503 uint32_t session_info_flags,
504 struct auth_session_info **session_info)
507 struct auth_user_info_dc *user_info_dc;
511 return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name,
512 NULL, session_info_flags, session_info);
515 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
516 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
518 status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
520 smb_krb5_context->krb5_context,
521 &user_info_dc, NULL, NULL);
522 if (!NT_STATUS_IS_OK(status)) {
523 talloc_free(tmp_ctx);
527 if (user_info_dc->info->authenticated) {
528 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
531 status = auth_generate_session_info_wrapper(auth_ctx, mem_ctx,
533 user_info_dc->info->account_name,
534 session_info_flags, session_info);
535 talloc_free(tmp_ctx);
539 /***************************************************************************
540 Make a auth_info struct for the auth subsystem
541 - Allow the caller to specify the methods to use, including optionally the SAM to use
542 ***************************************************************************/
543 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char * const *methods,
544 struct tevent_context *ev,
545 struct imessaging_context *msg,
546 struct loadparm_context *lp_ctx,
547 struct ldb_context *sam_ctx,
548 struct auth4_context **auth_ctx)
551 struct auth4_context *ctx;
556 DEBUG(0,("auth_context_create: called with out event context\n"));
557 return NT_STATUS_INTERNAL_ERROR;
560 ctx = talloc_zero(mem_ctx, struct auth4_context);
561 NT_STATUS_HAVE_NO_MEMORY(ctx);
562 ctx->challenge.data = data_blob(NULL, 0);
566 ctx->lp_ctx = lp_ctx;
569 ctx->sam_ctx = sam_ctx;
571 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
574 for (i=0; methods && methods[i] ; i++) {
575 struct auth_method_context *method;
577 method = talloc(ctx, struct auth_method_context);
578 NT_STATUS_HAVE_NO_MEMORY(method);
580 method->ops = auth_backend_byname(methods[i]);
582 DEBUG(1,("auth_context_create: failed to find method=%s\n",
584 return NT_STATUS_INTERNAL_ERROR;
586 method->auth_ctx = ctx;
588 DLIST_ADD_END(ctx->methods, method);
591 ctx->check_ntlm_password = auth_check_password_wrapper;
592 ctx->get_ntlm_challenge = auth_get_challenge;
593 ctx->set_ntlm_challenge = auth_context_set_challenge;
594 ctx->generate_session_info = auth_generate_session_info_wrapper;
595 ctx->generate_session_info_pac = auth_generate_session_info_pac;
602 const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
604 char **auth_methods = NULL;
606 switch (lpcfg_server_role(lp_ctx)) {
607 case ROLE_STANDALONE:
608 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
610 case ROLE_DOMAIN_MEMBER:
611 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind", NULL);
613 case ROLE_DOMAIN_BDC:
614 case ROLE_DOMAIN_PDC:
615 case ROLE_ACTIVE_DIRECTORY_DC:
616 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain winbind", NULL);
619 return discard_const_p(const char *, auth_methods);
622 /***************************************************************************
623 Make a auth_info struct for the auth subsystem
624 - Uses default auth_methods, depending on server role and smb.conf settings
625 ***************************************************************************/
626 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
627 struct tevent_context *ev,
628 struct imessaging_context *msg,
629 struct loadparm_context *lp_ctx,
630 struct auth4_context **auth_ctx)
633 const char **auth_methods;
634 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
636 return NT_STATUS_NO_MEMORY;
639 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
641 return NT_STATUS_INVALID_PARAMETER;
643 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
644 talloc_free(tmp_ctx);
648 _PUBLIC_ NTSTATUS auth_context_create_for_netlogon(TALLOC_CTX *mem_ctx,
649 struct tevent_context *ev,
650 struct imessaging_context *msg,
651 struct loadparm_context *lp_ctx,
652 struct auth4_context **auth_ctx)
654 return auth_context_create(mem_ctx, ev, msg, lp_ctx, auth_ctx);
657 /* the list of currently registered AUTH backends */
658 static struct auth_backend {
659 const struct auth_operations *ops;
661 static int num_backends;
664 register a AUTH backend.
666 The 'name' can be later used by other backends to find the operations
667 structure for this backend.
669 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
671 struct auth_operations *new_ops;
673 if (auth_backend_byname(ops->name) != NULL) {
674 /* its already registered! */
675 DEBUG(0,("AUTH backend '%s' already registered\n",
677 return NT_STATUS_OBJECT_NAME_COLLISION;
680 backends = talloc_realloc(talloc_autofree_context(), backends,
681 struct auth_backend, num_backends+1);
682 NT_STATUS_HAVE_NO_MEMORY(backends);
684 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
685 NT_STATUS_HAVE_NO_MEMORY(new_ops);
686 new_ops->name = talloc_strdup(new_ops, ops->name);
687 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
689 backends[num_backends].ops = new_ops;
693 DEBUG(3,("AUTH backend '%s' registered\n",
700 return the operations structure for a named backend of the specified type
702 const struct auth_operations *auth_backend_byname(const char *name)
706 for (i=0;i<num_backends;i++) {
707 if (strcmp(backends[i].ops->name, name) == 0) {
708 return backends[i].ops;
716 return the AUTH interface version, and the size of some critical types
717 This can be used by backends to either detect compilation errors, or provide
718 multiple implementations for different smbd compilation options in one module
720 const struct auth_critical_sizes *auth_interface_version(void)
722 static const struct auth_critical_sizes critical_sizes = {
723 AUTH4_INTERFACE_VERSION,
724 sizeof(struct auth_operations),
725 sizeof(struct auth_method_context),
726 sizeof(struct auth4_context),
727 sizeof(struct auth_usersupplied_info),
728 sizeof(struct auth_user_info_dc)
731 return &critical_sizes;
734 _PUBLIC_ NTSTATUS auth4_init(void)
736 static bool initialized = false;
737 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
738 STATIC_auth4_MODULES_PROTO;
739 init_module_fn static_init[] = { STATIC_auth4_MODULES };
741 if (initialized) return NT_STATUS_OK;
744 run_init_functions(static_init);