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"
36 static NTSTATUS auth_generate_session_info_wrapper(TALLOC_CTX *mem_ctx,
37 struct auth4_context *auth_context,
38 void *server_returned_info,
39 uint32_t session_info_flags,
40 struct auth_session_info **session_info);
42 /***************************************************************************
44 ***************************************************************************/
45 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth4_context *auth_ctx, const uint8_t chal[8], const char *set_by)
47 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
48 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
50 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
51 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
56 /***************************************************************************
58 ***************************************************************************/
59 _PUBLIC_ bool auth_challenge_may_be_modified(struct auth4_context *auth_ctx)
61 return auth_ctx->challenge.may_be_modified;
64 /****************************************************************************
65 Try to get a challenge out of the various authentication modules.
66 Returns a const char of length 8 bytes.
67 ****************************************************************************/
68 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth4_context *auth_ctx, uint8_t chal[8])
71 struct auth_method_context *method;
73 if (auth_ctx->challenge.data.length == 8) {
74 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
75 auth_ctx->challenge.set_by));
76 memcpy(chal, auth_ctx->challenge.data.data, 8);
80 for (method = auth_ctx->methods; method; method = method->next) {
81 nt_status = method->ops->get_challenge(method, auth_ctx, chal);
82 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
86 NT_STATUS_NOT_OK_RETURN(nt_status);
88 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
89 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
90 auth_ctx->challenge.set_by = method->ops->name;
95 if (!auth_ctx->challenge.set_by) {
96 generate_random_buffer(chal, 8);
98 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
99 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
100 auth_ctx->challenge.set_by = "random";
102 auth_ctx->challenge.may_be_modified = true;
105 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
106 auth_ctx->challenge.set_by));
111 /****************************************************************************
112 Used in the gensec_gssapi and gensec_krb5 server-side code, where the
113 PAC isn't available, and for tokenGroups in the DSDB stack.
115 Supply either a principal or a DN
116 ****************************************************************************/
117 static NTSTATUS auth_generate_session_info_principal(struct auth4_context *auth_ctx,
119 const char *principal,
120 struct ldb_dn *user_dn,
121 uint32_t session_info_flags,
122 struct auth_session_info **session_info)
125 struct auth_method_context *method;
126 struct auth_user_info_dc *user_info_dc;
128 for (method = auth_ctx->methods; method; method = method->next) {
129 if (!method->ops->get_user_info_dc_principal) {
133 nt_status = method->ops->get_user_info_dc_principal(mem_ctx, auth_ctx, principal, user_dn, &user_info_dc);
134 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
137 if (!NT_STATUS_IS_OK(nt_status)) {
141 nt_status = auth_generate_session_info_wrapper(mem_ctx, auth_ctx,
143 session_info_flags, session_info);
144 talloc_free(user_info_dc);
149 return NT_STATUS_NOT_IMPLEMENTED;
153 * Check a user's Plaintext, LM or NTLM password.
156 * Check a user's password, as given in the user_info struct and return various
157 * interesting details in the user_info_dc struct.
159 * The return value takes precedence over the contents of the user_info_dc
160 * struct. When the return is other than NT_STATUS_OK the contents
161 * of that structure is undefined.
163 * @param auth_ctx Supplies the challenges and some other data.
164 * Must be created with auth_context_create(), and the challenges should be
165 * filled in, either at creation or by calling the challenge geneation
166 * function auth_get_challenge().
168 * @param user_info Contains the user supplied components, including the passwords.
170 * @param mem_ctx The parent memory context for the user_info_dc structure
172 * @param user_info_dc If successful, contains information about the authentication,
173 * including a SAM_ACCOUNT struct describing the user.
175 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
179 _PUBLIC_ NTSTATUS auth_check_password(struct auth4_context *auth_ctx,
181 const struct auth_usersupplied_info *user_info,
182 struct auth_user_info_dc **user_info_dc)
184 struct tevent_req *subreq;
185 struct tevent_context *ev;
189 /*TODO: create a new event context here! */
190 ev = auth_ctx->event_ctx;
192 subreq = auth_check_password_send(mem_ctx,
196 if (subreq == NULL) {
197 return NT_STATUS_NO_MEMORY;
200 ok = tevent_req_poll(subreq, ev);
202 return NT_STATUS_INTERNAL_ERROR;
205 status = auth_check_password_recv(subreq, mem_ctx, user_info_dc);
211 _PUBLIC_ NTSTATUS auth_check_password_wrapper(struct auth4_context *auth_ctx,
213 const struct auth_usersupplied_info *user_info,
214 void **server_returned_info,
215 DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
217 struct auth_user_info_dc *user_info_dc;
218 NTSTATUS status = auth_check_password(auth_ctx, mem_ctx, user_info, &user_info_dc);
220 if (NT_STATUS_IS_OK(status)) {
221 *server_returned_info = user_info_dc;
223 if (user_session_key) {
224 DEBUG(10, ("Got NT session key of length %u\n",
225 (unsigned)user_info_dc->user_session_key.length));
226 *user_session_key = user_info_dc->user_session_key;
227 talloc_steal(mem_ctx, user_session_key->data);
228 user_info_dc->user_session_key = data_blob_null;
231 if (lm_session_key) {
232 DEBUG(10, ("Got LM session key of length %u\n",
233 (unsigned)user_info_dc->lm_session_key.length));
234 *lm_session_key = user_info_dc->lm_session_key;
235 talloc_steal(mem_ctx, lm_session_key->data);
236 user_info_dc->lm_session_key = data_blob_null;
243 struct auth_check_password_state {
244 struct auth4_context *auth_ctx;
245 const struct auth_usersupplied_info *user_info;
246 struct auth_user_info_dc *user_info_dc;
247 struct auth_method_context *method;
250 static void auth_check_password_async_trigger(struct tevent_context *ev,
251 struct tevent_immediate *im,
254 * Check a user's Plaintext, LM or NTLM password.
257 * Check a user's password, as given in the user_info struct and return various
258 * interesting details in the user_info_dc struct.
260 * The return value takes precedence over the contents of the user_info_dc
261 * struct. When the return is other than NT_STATUS_OK the contents
262 * of that structure is undefined.
264 * @param mem_ctx The memory context the request should operate on
266 * @param ev The tevent context the request should operate on
268 * @param auth_ctx Supplies the challenges and some other data.
269 * Must be created with make_auth_context(), and the challenges should be
270 * filled in, either at creation or by calling the challenge geneation
271 * function auth_get_challenge().
273 * @param user_info Contains the user supplied components, including the passwords.
275 * @return The request handle or NULL on no memory error.
279 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
280 struct tevent_context *ev,
281 struct auth4_context *auth_ctx,
282 const struct auth_usersupplied_info *user_info)
284 struct tevent_req *req;
285 struct auth_check_password_state *state;
286 /* if all the modules say 'not for me' this is reasonable */
289 struct auth_usersupplied_info *user_info_tmp;
290 struct tevent_immediate *im;
292 DEBUG(3,("auth_check_password_send: "
293 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
294 user_info->client.domain_name, user_info->client.account_name,
295 user_info->workstation_name));
297 req = tevent_req_create(mem_ctx, &state,
298 struct auth_check_password_state);
303 state->auth_ctx = auth_ctx;
304 state->user_info = user_info;
306 if (!user_info->mapped_state) {
307 nt_status = map_user_info(auth_ctx->sam_ctx, req, lpcfg_workgroup(auth_ctx->lp_ctx),
308 user_info, &user_info_tmp);
309 if (tevent_req_nterror(req, nt_status)) {
310 return tevent_req_post(req, ev);
312 user_info = user_info_tmp;
313 state->user_info = user_info_tmp;
316 DEBUGADD(3,("auth_check_password_send: "
317 "mapped user is: [%s]\\[%s]@[%s]\n",
318 user_info->mapped.domain_name,
319 user_info->mapped.account_name,
320 user_info->workstation_name));
322 nt_status = auth_get_challenge(auth_ctx, chal);
323 if (tevent_req_nterror(req, nt_status)) {
324 DEBUG(0,("auth_check_password_send: "
325 "Invalid challenge (length %u) stored for "
326 "this auth context set_by %s - cannot continue: %s\n",
327 (unsigned)auth_ctx->challenge.data.length,
328 auth_ctx->challenge.set_by,
329 nt_errstr(nt_status)));
330 return tevent_req_post(req, ev);
333 if (auth_ctx->challenge.set_by) {
334 DEBUG(10,("auth_check_password_send: "
335 "auth_context challenge created by %s\n",
336 auth_ctx->challenge.set_by));
339 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
340 dump_data(5, auth_ctx->challenge.data.data,
341 auth_ctx->challenge.data.length);
343 im = tevent_create_immediate(state);
344 if (tevent_req_nomem(im, req)) {
345 return tevent_req_post(req, ev);
348 tevent_schedule_immediate(im,
350 auth_check_password_async_trigger,
355 static void auth_check_password_async_trigger(struct tevent_context *ev,
356 struct tevent_immediate *im,
359 struct tevent_req *req =
360 talloc_get_type_abort(private_data, struct tevent_req);
361 struct auth_check_password_state *state =
362 tevent_req_data(req, struct auth_check_password_state);
364 struct auth_method_context *method;
366 status = NT_STATUS_OK;
368 for (method=state->auth_ctx->methods; method; method = method->next) {
370 /* we fill in state->method here so debug messages in
371 the callers know which method failed */
372 state->method = method;
374 /* check if the module wants to check the password */
375 status = method->ops->want_check(method, req, state->user_info);
376 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
377 DEBUG(11,("auth_check_password_send: "
378 "%s had nothing to say\n",
383 if (tevent_req_nterror(req, status)) {
387 status = method->ops->check_password(method,
390 &state->user_info_dc);
391 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
392 /* the backend has handled the request */
397 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
398 /* don't expose the NT_STATUS_NOT_IMPLEMENTED
400 status = NT_STATUS_NO_SUCH_USER;
403 if (tevent_req_nterror(req, status)) {
407 tevent_req_done(req);
411 * Check a user's Plaintext, LM or NTLM password.
412 * async receive function
414 * The return value takes precedence over the contents of the user_info_dc
415 * struct. When the return is other than NT_STATUS_OK the contents
416 * of that structure is undefined.
419 * @param req The async request state
421 * @param mem_ctx The parent memory context for the user_info_dc structure
423 * @param user_info_dc If successful, contains information about the authentication,
424 * including a SAM_ACCOUNT struct describing the user.
426 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
430 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
432 struct auth_user_info_dc **user_info_dc)
434 struct auth_check_password_state *state =
435 tevent_req_data(req, struct auth_check_password_state);
438 if (tevent_req_is_nterror(req, &status)) {
439 DEBUG(2,("auth_check_password_recv: "
440 "%s authentication for user [%s\\%s] "
441 "FAILED with error %s\n",
442 (state->method ? state->method->ops->name : "NO_METHOD"),
443 state->user_info->mapped.domain_name,
444 state->user_info->mapped.account_name,
446 tevent_req_received(req);
450 DEBUG(5,("auth_check_password_recv: "
451 "%s authentication for user [%s\\%s] succeeded\n",
452 state->method->ops->name,
453 state->user_info_dc->info->domain_name,
454 state->user_info_dc->info->account_name));
456 *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
458 tevent_req_received(req);
462 /* Wrapper because we don't want to expose all callers to needing to
463 * know that session_info is generated from the main ldb, and because
464 * we need to break a depenency loop between the DCE/RPC layer and the
465 * generation of unix tokens via IRPC */
466 static NTSTATUS auth_generate_session_info_wrapper(TALLOC_CTX *mem_ctx,
467 struct auth4_context *auth_context,
468 void *server_returned_info,
469 uint32_t session_info_flags,
470 struct auth_session_info **session_info)
472 struct auth_user_info_dc *user_info_dc = talloc_get_type_abort(server_returned_info, struct auth_user_info_dc);
473 NTSTATUS status = auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
474 auth_context->sam_ctx, user_info_dc,
475 session_info_flags, session_info);
476 if (!NT_STATUS_IS_OK(status)) {
480 if ((session_info_flags & AUTH_SESSION_INFO_UNIX_TOKEN)
481 && NT_STATUS_IS_OK(status)) {
482 struct wbc_context *wbc_ctx = wbc_init(auth_context,
483 auth_context->msg_ctx,
484 auth_context->event_ctx);
486 TALLOC_FREE(*session_info);
487 DEBUG(1, ("Cannot contact winbind to provide unix token\n"));
488 return NT_STATUS_INVALID_SERVER_STATE;
490 status = auth_session_info_fill_unix(wbc_ctx, auth_context->lp_ctx,
492 if (!NT_STATUS_IS_OK(status)) {
493 TALLOC_FREE(*session_info);
495 TALLOC_FREE(wbc_ctx);
500 /* Wrapper because we don't want to expose all callers to needing to
501 * know anything about the PAC or auth subsystem internal structures
502 * before we output a struct auth session_info */
503 static NTSTATUS auth_generate_session_info_pac(struct auth4_context *auth_ctx,
505 struct smb_krb5_context *smb_krb5_context,
507 const char *principal_name,
508 const struct tsocket_address *remote_address,
509 uint32_t session_info_flags,
510 struct auth_session_info **session_info)
513 struct auth_user_info_dc *user_info_dc;
517 return auth_generate_session_info_principal(auth_ctx, mem_ctx, principal_name,
518 NULL, session_info_flags, session_info);
521 tmp_ctx = talloc_named(mem_ctx, 0, "gensec_gssapi_session_info context");
522 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
524 status = kerberos_pac_blob_to_user_info_dc(tmp_ctx,
526 smb_krb5_context->krb5_context,
527 &user_info_dc, NULL, NULL);
528 if (!NT_STATUS_IS_OK(status)) {
529 talloc_free(tmp_ctx);
533 if (user_info_dc->info->authenticated) {
534 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
537 status = auth_generate_session_info_wrapper(mem_ctx, auth_ctx,
539 session_info_flags, session_info);
540 talloc_free(tmp_ctx);
544 /***************************************************************************
545 Make a auth_info struct for the auth subsystem
546 - Allow the caller to specify the methods to use, including optionally the SAM to use
547 ***************************************************************************/
548 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
549 struct tevent_context *ev,
550 struct imessaging_context *msg,
551 struct loadparm_context *lp_ctx,
552 struct ldb_context *sam_ctx,
553 struct auth4_context **auth_ctx)
556 struct auth4_context *ctx;
561 DEBUG(0,("auth_context_create: called with out event context\n"));
562 return NT_STATUS_INTERNAL_ERROR;
565 ctx = talloc_zero(mem_ctx, struct auth4_context);
566 NT_STATUS_HAVE_NO_MEMORY(ctx);
567 ctx->challenge.set_by = NULL;
568 ctx->challenge.may_be_modified = false;
569 ctx->challenge.data = data_blob(NULL, 0);
573 ctx->lp_ctx = lp_ctx;
576 ctx->sam_ctx = sam_ctx;
578 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
581 for (i=0; methods && methods[i] ; i++) {
582 struct auth_method_context *method;
584 method = talloc(ctx, struct auth_method_context);
585 NT_STATUS_HAVE_NO_MEMORY(method);
587 method->ops = auth_backend_byname(methods[i]);
589 DEBUG(1,("auth_context_create: failed to find method=%s\n",
591 return NT_STATUS_INTERNAL_ERROR;
593 method->auth_ctx = ctx;
595 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
598 ctx->check_password = auth_check_password_wrapper;
599 ctx->get_challenge = auth_get_challenge;
600 ctx->set_challenge = auth_context_set_challenge;
601 ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
602 ctx->generate_session_info = auth_generate_session_info_wrapper;
603 ctx->generate_session_info_pac = auth_generate_session_info_pac;
610 const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
612 char **auth_methods = NULL;
614 switch (lpcfg_server_role(lp_ctx)) {
615 case ROLE_STANDALONE:
616 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
618 case ROLE_DOMAIN_MEMBER:
619 auth_methods = str_list_make(mem_ctx, "anonymous sam winbind", NULL);
621 case ROLE_DOMAIN_BDC:
622 case ROLE_DOMAIN_PDC:
623 auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain winbind", NULL);
626 return (const char **) auth_methods;
629 /***************************************************************************
630 Make a auth_info struct for the auth subsystem
631 - Uses default auth_methods, depending on server role and smb.conf settings
632 ***************************************************************************/
633 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
634 struct tevent_context *ev,
635 struct imessaging_context *msg,
636 struct loadparm_context *lp_ctx,
637 struct auth4_context **auth_ctx)
640 const char **auth_methods;
641 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
643 return NT_STATUS_NO_MEMORY;
646 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
648 return NT_STATUS_INVALID_PARAMETER;
650 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
651 talloc_free(tmp_ctx);
655 /* the list of currently registered AUTH backends */
656 static struct auth_backend {
657 const struct auth_operations *ops;
659 static int num_backends;
662 register a AUTH backend.
664 The 'name' can be later used by other backends to find the operations
665 structure for this backend.
667 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
669 struct auth_operations *new_ops;
671 if (auth_backend_byname(ops->name) != NULL) {
672 /* its already registered! */
673 DEBUG(0,("AUTH backend '%s' already registered\n",
675 return NT_STATUS_OBJECT_NAME_COLLISION;
678 backends = talloc_realloc(talloc_autofree_context(), backends,
679 struct auth_backend, num_backends+1);
680 NT_STATUS_HAVE_NO_MEMORY(backends);
682 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
683 NT_STATUS_HAVE_NO_MEMORY(new_ops);
684 new_ops->name = talloc_strdup(new_ops, ops->name);
685 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
687 backends[num_backends].ops = new_ops;
691 DEBUG(3,("AUTH backend '%s' registered\n",
698 return the operations structure for a named backend of the specified type
700 const struct auth_operations *auth_backend_byname(const char *name)
704 for (i=0;i<num_backends;i++) {
705 if (strcmp(backends[i].ops->name, name) == 0) {
706 return backends[i].ops;
714 return the AUTH interface version, and the size of some critical types
715 This can be used by backends to either detect compilation errors, or provide
716 multiple implementations for different smbd compilation options in one module
718 const struct auth_critical_sizes *auth_interface_version(void)
720 static const struct auth_critical_sizes critical_sizes = {
721 AUTH4_INTERFACE_VERSION,
722 sizeof(struct auth_operations),
723 sizeof(struct auth_method_context),
724 sizeof(struct auth4_context),
725 sizeof(struct auth_usersupplied_info),
726 sizeof(struct auth_user_info_dc)
729 return &critical_sizes;
732 _PUBLIC_ NTSTATUS auth4_init(void)
734 static bool initialized = false;
735 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
736 STATIC_auth4_MODULES_PROTO;
737 init_module_fn static_init[] = { STATIC_auth4_MODULES };
739 if (initialized) return NT_STATUS_OK;
742 run_init_functions(static_init);