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 */
237 struct auth_method_context *method;
239 struct auth_usersupplied_info *user_info_tmp;
240 struct tevent_immediate *im;
242 DEBUG(3,("auth_check_password_send: "
243 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
244 user_info->client.domain_name, user_info->client.account_name,
245 user_info->workstation_name));
247 req = tevent_req_create(mem_ctx, &state,
248 struct auth_check_password_state);
253 state->auth_ctx = auth_ctx;
254 state->user_info = user_info;
255 state->method = NULL;
257 if (!user_info->mapped_state) {
258 nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx),
259 user_info, &user_info_tmp);
260 if (tevent_req_nterror(req, nt_status)) {
261 return tevent_req_post(req, ev);
263 user_info = user_info_tmp;
264 state->user_info = user_info_tmp;
267 DEBUGADD(3,("auth_check_password_send: "
268 "mapped user is: [%s]\\[%s]@[%s]\n",
269 user_info->mapped.domain_name,
270 user_info->mapped.account_name,
271 user_info->workstation_name));
273 nt_status = auth_get_challenge(auth_ctx, chal);
274 if (tevent_req_nterror(req, nt_status)) {
275 DEBUG(0,("auth_check_password_send: "
276 "Invalid challenge (length %u) stored for "
277 "this auth context set_by %s - cannot continue: %s\n",
278 (unsigned)auth_ctx->challenge.data.length,
279 auth_ctx->challenge.set_by,
280 nt_errstr(nt_status)));
281 return tevent_req_post(req, ev);
284 if (auth_ctx->challenge.set_by) {
285 DEBUG(10,("auth_check_password_send: "
286 "auth_context challenge created by %s\n",
287 auth_ctx->challenge.set_by));
290 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
291 dump_data(5, auth_ctx->challenge.data.data,
292 auth_ctx->challenge.data.length);
294 im = tevent_create_immediate(state);
295 if (tevent_req_nomem(im, req)) {
296 return tevent_req_post(req, ev);
299 for (method = auth_ctx->methods; method; method = method->next) {
302 /* check if the module wants to chek the password */
303 result = method->ops->want_check(method, req, user_info);
304 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
305 DEBUG(11,("auth_check_password_send: "
306 "%s had nothing to say\n",
311 state->method = method;
313 if (tevent_req_nterror(req, result)) {
314 return tevent_req_post(req, ev);
317 tevent_schedule_immediate(im,
319 auth_check_password_async_trigger,
325 /* If all the modules say 'not for me', then this is reasonable */
326 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
327 return tevent_req_post(req, ev);
330 static void auth_check_password_async_trigger(struct tevent_context *ev,
331 struct tevent_immediate *im,
334 struct tevent_req *req =
335 talloc_get_type_abort(private_data, struct tevent_req);
336 struct auth_check_password_state *state =
337 tevent_req_data(req, struct auth_check_password_state);
340 status = state->method->ops->check_password(state->method,
343 &state->server_info);
344 if (tevent_req_nterror(req, status)) {
348 tevent_req_done(req);
352 * Check a user's Plaintext, LM or NTLM password.
353 * async receive function
355 * The return value takes precedence over the contents of the server_info
356 * struct. When the return is other than NT_STATUS_OK the contents
357 * of that structure is undefined.
360 * @param req The async request state
362 * @param mem_ctx The parent memory context for the server_info structure
364 * @param server_info If successful, contains information about the authentication,
365 * including a SAM_ACCOUNT struct describing the user.
367 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
371 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
373 struct auth_serversupplied_info **server_info)
375 struct auth_check_password_state *state =
376 tevent_req_data(req, struct auth_check_password_state);
379 if (tevent_req_is_nterror(req, &status)) {
380 DEBUG(2,("auth_check_password_recv: "
381 "%s authentication for user [%s\\%s]"
382 "FAILED with error %s\n",
383 (state->method ? state->method->ops->name : "NO_METHOD"),
384 state->user_info->mapped.domain_name,
385 state->user_info->mapped.account_name,
387 tevent_req_received(req);
391 DEBUG(5,("auth_check_password_recv: "
392 "%s authentication for user [%s\\%s] succeeded\n",
393 state->method->ops->name,
394 state->server_info->domain_name,
395 state->server_info->account_name));
397 *server_info = talloc_move(mem_ctx, &state->server_info);
399 tevent_req_received(req);
403 /***************************************************************************
404 Make a auth_info struct for the auth subsystem
405 - Allow the caller to specify the methods to use, including optionally the SAM to use
406 ***************************************************************************/
407 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
408 struct tevent_context *ev,
409 struct messaging_context *msg,
410 struct loadparm_context *lp_ctx,
411 struct ldb_context *sam_ctx,
412 struct auth_context **auth_ctx)
415 struct auth_context *ctx;
420 DEBUG(0,("auth_context_create: No auth method list!?\n"));
421 return NT_STATUS_INTERNAL_ERROR;
425 DEBUG(0,("auth_context_create: called with out event context\n"));
426 return NT_STATUS_INTERNAL_ERROR;
429 ctx = talloc(mem_ctx, struct auth_context);
430 NT_STATUS_HAVE_NO_MEMORY(ctx);
431 ctx->challenge.set_by = NULL;
432 ctx->challenge.may_be_modified = false;
433 ctx->challenge.data = data_blob(NULL, 0);
437 ctx->lp_ctx = lp_ctx;
440 ctx->sam_ctx = sam_ctx;
442 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx));
445 for (i=0; methods[i] ; i++) {
446 struct auth_method_context *method;
448 method = talloc(ctx, struct auth_method_context);
449 NT_STATUS_HAVE_NO_MEMORY(method);
451 method->ops = auth_backend_byname(methods[i]);
453 DEBUG(1,("auth_context_create: failed to find method=%s\n",
455 return NT_STATUS_INTERNAL_ERROR;
457 method->auth_ctx = ctx;
459 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
463 return NT_STATUS_INTERNAL_ERROR;
466 ctx->check_password = auth_check_password;
467 ctx->get_challenge = auth_get_challenge;
468 ctx->set_challenge = auth_context_set_challenge;
469 ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
470 ctx->get_server_info_principal = auth_get_server_info_principal;
471 ctx->generate_session_info = auth_generate_session_info;
478 static const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
480 const char **auth_methods = NULL;
481 switch (lp_server_role(lp_ctx)) {
482 case ROLE_STANDALONE:
483 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
485 case ROLE_DOMAIN_MEMBER:
486 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
488 case ROLE_DOMAIN_CONTROLLER:
489 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
495 /***************************************************************************
496 Make a auth_info struct for the auth subsystem
497 - Uses default auth_methods, depending on server role and smb.conf settings
498 ***************************************************************************/
499 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
500 struct tevent_context *ev,
501 struct messaging_context *msg,
502 struct loadparm_context *lp_ctx,
503 struct auth_context **auth_ctx)
506 const char **auth_methods;
507 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
509 return NT_STATUS_NO_MEMORY;
512 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
514 return NT_STATUS_INVALID_PARAMETER;
516 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
517 talloc_free(tmp_ctx);
521 /* Create an auth context from an open LDB.
523 This allows us not to re-open the LDB when we need to do a some authentication logic (such as tokenGroups)
526 NTSTATUS auth_context_create_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct auth_context **auth_ctx)
529 const char **auth_methods;
530 struct loadparm_context *lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
531 struct tevent_context *ev = ldb_get_event_context(ldb);
533 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
535 return NT_STATUS_NO_MEMORY;
538 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
540 return NT_STATUS_INVALID_PARAMETER;
542 status = auth_context_create_methods(mem_ctx, auth_methods, ev, NULL, lp_ctx, ldb, auth_ctx);
543 talloc_free(tmp_ctx);
547 /* the list of currently registered AUTH backends */
548 static struct auth_backend {
549 const struct auth_operations *ops;
551 static int num_backends;
554 register a AUTH backend.
556 The 'name' can be later used by other backends to find the operations
557 structure for this backend.
559 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
561 struct auth_operations *new_ops;
563 if (auth_backend_byname(ops->name) != NULL) {
564 /* its already registered! */
565 DEBUG(0,("AUTH backend '%s' already registered\n",
567 return NT_STATUS_OBJECT_NAME_COLLISION;
570 backends = talloc_realloc(talloc_autofree_context(), backends,
571 struct auth_backend, num_backends+1);
572 NT_STATUS_HAVE_NO_MEMORY(backends);
574 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
575 NT_STATUS_HAVE_NO_MEMORY(new_ops);
576 new_ops->name = talloc_strdup(new_ops, ops->name);
577 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
579 backends[num_backends].ops = new_ops;
583 DEBUG(3,("AUTH backend '%s' registered\n",
590 return the operations structure for a named backend of the specified type
592 const struct auth_operations *auth_backend_byname(const char *name)
596 for (i=0;i<num_backends;i++) {
597 if (strcmp(backends[i].ops->name, name) == 0) {
598 return backends[i].ops;
606 return the AUTH interface version, and the size of some critical types
607 This can be used by backends to either detect compilation errors, or provide
608 multiple implementations for different smbd compilation options in one module
610 const struct auth_critical_sizes *auth_interface_version(void)
612 static const struct auth_critical_sizes critical_sizes = {
613 AUTH_INTERFACE_VERSION,
614 sizeof(struct auth_operations),
615 sizeof(struct auth_method_context),
616 sizeof(struct auth_context),
617 sizeof(struct auth_usersupplied_info),
618 sizeof(struct auth_serversupplied_info)
621 return &critical_sizes;
624 _PUBLIC_ NTSTATUS auth_init(void)
626 static bool initialized = false;
627 extern NTSTATUS auth_developer_init(void);
628 extern NTSTATUS auth_winbind_init(void);
629 extern NTSTATUS auth_anonymous_init(void);
630 extern NTSTATUS auth_unix_init(void);
631 extern NTSTATUS auth_sam_init(void);
632 extern NTSTATUS auth_server_init(void);
634 init_module_fn static_init[] = { STATIC_auth_MODULES };
636 if (initialized) return NT_STATUS_OK;
639 run_init_functions(static_init);