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;
430 DEBUG(0,("auth_context_create: called with out messaging context\n"));
431 return NT_STATUS_INTERNAL_ERROR;
434 ctx = talloc(mem_ctx, struct auth_context);
435 NT_STATUS_HAVE_NO_MEMORY(ctx);
436 ctx->challenge.set_by = NULL;
437 ctx->challenge.may_be_modified = false;
438 ctx->challenge.data = data_blob(NULL, 0);
442 ctx->lp_ctx = lp_ctx;
445 ctx->sam_ctx = sam_ctx;
447 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx));
450 for (i=0; methods[i] ; i++) {
451 struct auth_method_context *method;
453 method = talloc(ctx, struct auth_method_context);
454 NT_STATUS_HAVE_NO_MEMORY(method);
456 method->ops = auth_backend_byname(methods[i]);
458 DEBUG(1,("auth_context_create: failed to find method=%s\n",
460 return NT_STATUS_INTERNAL_ERROR;
462 method->auth_ctx = ctx;
464 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
468 return NT_STATUS_INTERNAL_ERROR;
471 ctx->check_password = auth_check_password;
472 ctx->get_challenge = auth_get_challenge;
473 ctx->set_challenge = auth_context_set_challenge;
474 ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
475 ctx->get_server_info_principal = auth_get_server_info_principal;
476 ctx->generate_session_info = auth_generate_session_info;
483 static const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
485 const char **auth_methods = NULL;
486 switch (lp_server_role(lp_ctx)) {
487 case ROLE_STANDALONE:
488 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
490 case ROLE_DOMAIN_MEMBER:
491 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
493 case ROLE_DOMAIN_CONTROLLER:
494 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
500 /***************************************************************************
501 Make a auth_info struct for the auth subsystem
502 - Uses default auth_methods, depending on server role and smb.conf settings
503 ***************************************************************************/
504 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
505 struct tevent_context *ev,
506 struct messaging_context *msg,
507 struct loadparm_context *lp_ctx,
508 struct auth_context **auth_ctx)
511 const char **auth_methods;
512 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
514 return NT_STATUS_NO_MEMORY;
517 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
519 return NT_STATUS_INVALID_PARAMETER;
521 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
522 talloc_free(tmp_ctx);
526 /* Create an auth context from an open LDB.
528 This allows us not to re-open the LDB when we need to do a some authentication logic (such as tokenGroups)
531 NTSTATUS auth_context_create_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct auth_context **auth_ctx)
534 const char **auth_methods;
535 struct loadparm_context *lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
536 struct tevent_context *ev = ldb_get_event_context(ldb);
538 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
540 return NT_STATUS_NO_MEMORY;
543 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
545 return NT_STATUS_INVALID_PARAMETER;
547 status = auth_context_create_methods(mem_ctx, auth_methods, ev, NULL, lp_ctx, ldb, auth_ctx);
548 talloc_free(tmp_ctx);
552 /* the list of currently registered AUTH backends */
553 static struct auth_backend {
554 const struct auth_operations *ops;
556 static int num_backends;
559 register a AUTH backend.
561 The 'name' can be later used by other backends to find the operations
562 structure for this backend.
564 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
566 struct auth_operations *new_ops;
568 if (auth_backend_byname(ops->name) != NULL) {
569 /* its already registered! */
570 DEBUG(0,("AUTH backend '%s' already registered\n",
572 return NT_STATUS_OBJECT_NAME_COLLISION;
575 backends = talloc_realloc(talloc_autofree_context(), backends,
576 struct auth_backend, num_backends+1);
577 NT_STATUS_HAVE_NO_MEMORY(backends);
579 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
580 NT_STATUS_HAVE_NO_MEMORY(new_ops);
581 new_ops->name = talloc_strdup(new_ops, ops->name);
582 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
584 backends[num_backends].ops = new_ops;
588 DEBUG(3,("AUTH backend '%s' registered\n",
595 return the operations structure for a named backend of the specified type
597 const struct auth_operations *auth_backend_byname(const char *name)
601 for (i=0;i<num_backends;i++) {
602 if (strcmp(backends[i].ops->name, name) == 0) {
603 return backends[i].ops;
611 return the AUTH interface version, and the size of some critical types
612 This can be used by backends to either detect compilation errors, or provide
613 multiple implementations for different smbd compilation options in one module
615 const struct auth_critical_sizes *auth_interface_version(void)
617 static const struct auth_critical_sizes critical_sizes = {
618 AUTH_INTERFACE_VERSION,
619 sizeof(struct auth_operations),
620 sizeof(struct auth_method_context),
621 sizeof(struct auth_context),
622 sizeof(struct auth_usersupplied_info),
623 sizeof(struct auth_serversupplied_info)
626 return &critical_sizes;
629 _PUBLIC_ NTSTATUS auth_init(void)
631 static bool initialized = false;
632 extern NTSTATUS auth_developer_init(void);
633 extern NTSTATUS auth_winbind_init(void);
634 extern NTSTATUS auth_anonymous_init(void);
635 extern NTSTATUS auth_unix_init(void);
636 extern NTSTATUS auth_sam_init(void);
637 extern NTSTATUS auth_server_init(void);
639 init_module_fn static_init[] = { STATIC_auth_MODULES };
641 if (initialized) return NT_STATUS_OK;
644 run_init_functions(static_init);