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"
31 /***************************************************************************
33 ***************************************************************************/
34 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by)
36 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
37 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
39 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
40 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
45 /***************************************************************************
47 ***************************************************************************/
48 _PUBLIC_ bool auth_challenge_may_be_modified(struct auth_context *auth_ctx)
50 return auth_ctx->challenge.may_be_modified;
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])
60 struct auth_method_context *method;
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);
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)) {
75 NT_STATUS_NOT_OK_RETURN(nt_status);
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;
84 if (!auth_ctx->challenge.set_by) {
85 generate_random_buffer(chal, 8);
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";
91 auth_ctx->challenge.may_be_modified = true;
94 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
95 auth_ctx->challenge.set_by));
100 /****************************************************************************
101 Used in the gensec_gssapi and gensec_krb5 server-side code, where the
102 PAC isn't available, and for tokenGroups in the DSDB stack.
104 Supply either a principal or a DN
105 ****************************************************************************/
106 _PUBLIC_ NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx,
107 struct auth_context *auth_ctx,
108 const char *principal,
109 struct ldb_dn *user_dn,
110 struct auth_serversupplied_info **server_info)
113 struct auth_method_context *method;
115 for (method = auth_ctx->methods; method; method = method->next) {
116 if (!method->ops->get_server_info_principal) {
120 nt_status = method->ops->get_server_info_principal(mem_ctx, auth_ctx, principal, user_dn, server_info);
121 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
125 NT_STATUS_NOT_OK_RETURN(nt_status);
134 * Check a user's Plaintext, LM or NTLM password.
137 * Check a user's password, as given in the user_info struct and return various
138 * interesting details in the server_info struct.
140 * The return value takes precedence over the contents of the server_info
141 * struct. When the return is other than NT_STATUS_OK the contents
142 * of that structure is undefined.
144 * @param auth_ctx Supplies the challenges and some other data.
145 * Must be created with auth_context_create(), and the challenges should be
146 * filled in, either at creation or by calling the challenge geneation
147 * function auth_get_challenge().
149 * @param user_info Contains the user supplied components, including the passwords.
151 * @param mem_ctx The parent memory context for the server_info structure
153 * @param server_info If successful, contains information about the authentication,
154 * including a SAM_ACCOUNT struct describing the user.
156 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
160 _PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
162 const struct auth_usersupplied_info *user_info,
163 struct auth_serversupplied_info **server_info)
165 struct tevent_req *subreq;
166 struct tevent_context *ev;
170 /*TODO: create a new event context here! */
171 ev = auth_ctx->event_ctx;
173 subreq = auth_check_password_send(mem_ctx,
177 if (subreq == NULL) {
178 return NT_STATUS_NO_MEMORY;
181 ok = tevent_req_poll(subreq, ev);
183 return NT_STATUS_INTERNAL_ERROR;
186 status = auth_check_password_recv(subreq, mem_ctx, server_info);
192 struct auth_check_password_state {
193 struct auth_context *auth_ctx;
194 const struct auth_usersupplied_info *user_info;
195 struct auth_serversupplied_info *server_info;
196 struct auth_method_context *method;
199 static void auth_check_password_async_trigger(struct tevent_context *ev,
200 struct tevent_immediate *im,
203 * Check a user's Plaintext, LM or NTLM password.
206 * Check a user's password, as given in the user_info struct and return various
207 * interesting details in the server_info struct.
209 * The return value takes precedence over the contents of the server_info
210 * struct. When the return is other than NT_STATUS_OK the contents
211 * of that structure is undefined.
213 * @param mem_ctx The memory context the request should operate on
215 * @param ev The tevent context the request should operate on
217 * @param auth_ctx Supplies the challenges and some other data.
218 * Must be created with make_auth_context(), and the challenges should be
219 * filled in, either at creation or by calling the challenge geneation
220 * function auth_get_challenge().
222 * @param user_info Contains the user supplied components, including the passwords.
224 * @return The request handle or NULL on no memory error.
228 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
229 struct tevent_context *ev,
230 struct auth_context *auth_ctx,
231 const struct auth_usersupplied_info *user_info)
233 struct tevent_req *req;
234 struct auth_check_password_state *state;
235 /* if all the modules say 'not for me' this is reasonable */
238 struct auth_usersupplied_info *user_info_tmp;
239 struct tevent_immediate *im;
241 DEBUG(3,("auth_check_password_send: "
242 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
243 user_info->client.domain_name, user_info->client.account_name,
244 user_info->workstation_name));
246 req = tevent_req_create(mem_ctx, &state,
247 struct auth_check_password_state);
252 state->auth_ctx = auth_ctx;
253 state->user_info = user_info;
255 if (!user_info->mapped_state) {
256 nt_status = map_user_info(req, lpcfg_workgroup(auth_ctx->lp_ctx),
257 user_info, &user_info_tmp);
258 if (tevent_req_nterror(req, nt_status)) {
259 return tevent_req_post(req, ev);
261 user_info = user_info_tmp;
262 state->user_info = user_info_tmp;
265 DEBUGADD(3,("auth_check_password_send: "
266 "mapped user is: [%s]\\[%s]@[%s]\n",
267 user_info->mapped.domain_name,
268 user_info->mapped.account_name,
269 user_info->workstation_name));
271 nt_status = auth_get_challenge(auth_ctx, chal);
272 if (tevent_req_nterror(req, nt_status)) {
273 DEBUG(0,("auth_check_password_send: "
274 "Invalid challenge (length %u) stored for "
275 "this auth context set_by %s - cannot continue: %s\n",
276 (unsigned)auth_ctx->challenge.data.length,
277 auth_ctx->challenge.set_by,
278 nt_errstr(nt_status)));
279 return tevent_req_post(req, ev);
282 if (auth_ctx->challenge.set_by) {
283 DEBUG(10,("auth_check_password_send: "
284 "auth_context challenge created by %s\n",
285 auth_ctx->challenge.set_by));
288 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
289 dump_data(5, auth_ctx->challenge.data.data,
290 auth_ctx->challenge.data.length);
292 im = tevent_create_immediate(state);
293 if (tevent_req_nomem(im, req)) {
294 return tevent_req_post(req, ev);
297 tevent_schedule_immediate(im,
299 auth_check_password_async_trigger,
304 static void auth_check_password_async_trigger(struct tevent_context *ev,
305 struct tevent_immediate *im,
308 struct tevent_req *req =
309 talloc_get_type_abort(private_data, struct tevent_req);
310 struct auth_check_password_state *state =
311 tevent_req_data(req, struct auth_check_password_state);
313 struct auth_method_context *method;
315 status = NT_STATUS_OK;
317 for (method=state->auth_ctx->methods; method; method = method->next) {
319 /* we fill in state->method here so debug messages in
320 the callers know which method failed */
321 state->method = method;
323 /* check if the module wants to check the password */
324 status = method->ops->want_check(method, req, state->user_info);
325 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
326 DEBUG(11,("auth_check_password_send: "
327 "%s had nothing to say\n",
332 if (tevent_req_nterror(req, status)) {
336 status = method->ops->check_password(method,
339 &state->server_info);
340 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
341 /* the backend has handled the request */
346 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
347 /* don't expose the NT_STATUS_NOT_IMPLEMENTED
349 status = NT_STATUS_NO_SUCH_USER;
352 if (tevent_req_nterror(req, status)) {
356 tevent_req_done(req);
360 * Check a user's Plaintext, LM or NTLM password.
361 * async receive function
363 * The return value takes precedence over the contents of the server_info
364 * struct. When the return is other than NT_STATUS_OK the contents
365 * of that structure is undefined.
368 * @param req The async request state
370 * @param mem_ctx The parent memory context for the server_info structure
372 * @param server_info If successful, contains information about the authentication,
373 * including a SAM_ACCOUNT struct describing the user.
375 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
379 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
381 struct auth_serversupplied_info **server_info)
383 struct auth_check_password_state *state =
384 tevent_req_data(req, struct auth_check_password_state);
387 if (tevent_req_is_nterror(req, &status)) {
388 DEBUG(2,("auth_check_password_recv: "
389 "%s authentication for user [%s\\%s] "
390 "FAILED with error %s\n",
391 (state->method ? state->method->ops->name : "NO_METHOD"),
392 state->user_info->mapped.domain_name,
393 state->user_info->mapped.account_name,
395 tevent_req_received(req);
399 DEBUG(5,("auth_check_password_recv: "
400 "%s authentication for user [%s\\%s] succeeded\n",
401 state->method->ops->name,
402 state->server_info->domain_name,
403 state->server_info->account_name));
405 *server_info = talloc_move(mem_ctx, &state->server_info);
407 tevent_req_received(req);
411 /* Wrapper because we don't want to expose all callers to needing to
412 * know that session_info is generated from the main ldb */
413 static NTSTATUS auth_generate_session_info_wrapper(TALLOC_CTX *mem_ctx,
414 struct auth_context *auth_context,
415 struct auth_serversupplied_info *server_info,
416 uint32_t session_info_flags,
417 struct auth_session_info **session_info)
419 return auth_generate_session_info(mem_ctx, auth_context->lp_ctx,
420 auth_context->sam_ctx, server_info,
421 session_info_flags, session_info);
424 /***************************************************************************
425 Make a auth_info struct for the auth subsystem
426 - Allow the caller to specify the methods to use, including optionally the SAM to use
427 ***************************************************************************/
428 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
429 struct tevent_context *ev,
430 struct messaging_context *msg,
431 struct loadparm_context *lp_ctx,
432 struct ldb_context *sam_ctx,
433 struct auth_context **auth_ctx)
436 struct auth_context *ctx;
441 DEBUG(0,("auth_context_create: No auth method list!?\n"));
442 return NT_STATUS_INTERNAL_ERROR;
446 DEBUG(0,("auth_context_create: called with out event context\n"));
447 return NT_STATUS_INTERNAL_ERROR;
450 ctx = talloc(mem_ctx, struct auth_context);
451 NT_STATUS_HAVE_NO_MEMORY(ctx);
452 ctx->challenge.set_by = NULL;
453 ctx->challenge.may_be_modified = false;
454 ctx->challenge.data = data_blob(NULL, 0);
458 ctx->lp_ctx = lp_ctx;
461 ctx->sam_ctx = sam_ctx;
463 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx), 0);
466 for (i=0; methods[i] ; i++) {
467 struct auth_method_context *method;
469 method = talloc(ctx, struct auth_method_context);
470 NT_STATUS_HAVE_NO_MEMORY(method);
472 method->ops = auth_backend_byname(methods[i]);
474 DEBUG(1,("auth_context_create: failed to find method=%s\n",
476 return NT_STATUS_INTERNAL_ERROR;
478 method->auth_ctx = ctx;
480 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
484 return NT_STATUS_INTERNAL_ERROR;
487 ctx->check_password = auth_check_password;
488 ctx->get_challenge = auth_get_challenge;
489 ctx->set_challenge = auth_context_set_challenge;
490 ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
491 ctx->get_server_info_principal = auth_get_server_info_principal;
492 ctx->generate_session_info = auth_generate_session_info_wrapper;
499 static const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
501 const char **auth_methods = NULL;
502 switch (lpcfg_server_role(lp_ctx)) {
503 case ROLE_STANDALONE:
504 auth_methods = lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
506 case ROLE_DOMAIN_MEMBER:
507 auth_methods = lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
509 case ROLE_DOMAIN_CONTROLLER:
510 auth_methods = lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
516 /***************************************************************************
517 Make a auth_info struct for the auth subsystem
518 - Uses default auth_methods, depending on server role and smb.conf settings
519 ***************************************************************************/
520 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
521 struct tevent_context *ev,
522 struct messaging_context *msg,
523 struct loadparm_context *lp_ctx,
524 struct auth_context **auth_ctx)
527 const char **auth_methods;
528 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
530 return NT_STATUS_NO_MEMORY;
533 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
535 return NT_STATUS_INVALID_PARAMETER;
537 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
538 talloc_free(tmp_ctx);
542 /* Create an auth context from an open LDB.
544 This allows us not to re-open the LDB when we need to do a some authentication logic (such as tokenGroups)
547 NTSTATUS auth_context_create_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct auth_context **auth_ctx)
550 const char **auth_methods;
551 struct loadparm_context *lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
552 struct tevent_context *ev = ldb_get_event_context(ldb);
554 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
556 return NT_STATUS_NO_MEMORY;
559 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
561 return NT_STATUS_INVALID_PARAMETER;
563 status = auth_context_create_methods(mem_ctx, auth_methods, ev, NULL, lp_ctx, ldb, auth_ctx);
564 talloc_free(tmp_ctx);
568 /* the list of currently registered AUTH backends */
569 static struct auth_backend {
570 const struct auth_operations *ops;
572 static int num_backends;
575 register a AUTH backend.
577 The 'name' can be later used by other backends to find the operations
578 structure for this backend.
580 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
582 struct auth_operations *new_ops;
584 if (auth_backend_byname(ops->name) != NULL) {
585 /* its already registered! */
586 DEBUG(0,("AUTH backend '%s' already registered\n",
588 return NT_STATUS_OBJECT_NAME_COLLISION;
591 backends = talloc_realloc(talloc_autofree_context(), backends,
592 struct auth_backend, num_backends+1);
593 NT_STATUS_HAVE_NO_MEMORY(backends);
595 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
596 NT_STATUS_HAVE_NO_MEMORY(new_ops);
597 new_ops->name = talloc_strdup(new_ops, ops->name);
598 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
600 backends[num_backends].ops = new_ops;
604 DEBUG(3,("AUTH backend '%s' registered\n",
611 return the operations structure for a named backend of the specified type
613 const struct auth_operations *auth_backend_byname(const char *name)
617 for (i=0;i<num_backends;i++) {
618 if (strcmp(backends[i].ops->name, name) == 0) {
619 return backends[i].ops;
627 return the AUTH interface version, and the size of some critical types
628 This can be used by backends to either detect compilation errors, or provide
629 multiple implementations for different smbd compilation options in one module
631 const struct auth_critical_sizes *auth_interface_version(void)
633 static const struct auth_critical_sizes critical_sizes = {
634 AUTH_INTERFACE_VERSION,
635 sizeof(struct auth_operations),
636 sizeof(struct auth_method_context),
637 sizeof(struct auth_context),
638 sizeof(struct auth_usersupplied_info),
639 sizeof(struct auth_serversupplied_info)
642 return &critical_sizes;
645 _PUBLIC_ NTSTATUS auth_init(void)
647 static bool initialized = false;
648 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
649 STATIC_auth_MODULES_PROTO;
650 init_module_fn static_init[] = { STATIC_auth_MODULES };
652 if (initialized) return NT_STATUS_OK;
655 run_init_functions(static_init);