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 /***************************************************************************
412 Make a auth_info struct for the auth subsystem
413 - Allow the caller to specify the methods to use, including optionally the SAM to use
414 ***************************************************************************/
415 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
416 struct tevent_context *ev,
417 struct messaging_context *msg,
418 struct loadparm_context *lp_ctx,
419 struct ldb_context *sam_ctx,
420 struct auth_context **auth_ctx)
423 struct auth_context *ctx;
428 DEBUG(0,("auth_context_create: No auth method list!?\n"));
429 return NT_STATUS_INTERNAL_ERROR;
433 DEBUG(0,("auth_context_create: called with out event context\n"));
434 return NT_STATUS_INTERNAL_ERROR;
437 ctx = talloc(mem_ctx, struct auth_context);
438 NT_STATUS_HAVE_NO_MEMORY(ctx);
439 ctx->challenge.set_by = NULL;
440 ctx->challenge.may_be_modified = false;
441 ctx->challenge.data = data_blob(NULL, 0);
445 ctx->lp_ctx = lp_ctx;
448 ctx->sam_ctx = sam_ctx;
450 ctx->sam_ctx = samdb_connect(ctx, ctx->event_ctx, ctx->lp_ctx, system_session(ctx->lp_ctx));
453 for (i=0; methods[i] ; i++) {
454 struct auth_method_context *method;
456 method = talloc(ctx, struct auth_method_context);
457 NT_STATUS_HAVE_NO_MEMORY(method);
459 method->ops = auth_backend_byname(methods[i]);
461 DEBUG(1,("auth_context_create: failed to find method=%s\n",
463 return NT_STATUS_INTERNAL_ERROR;
465 method->auth_ctx = ctx;
467 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
471 return NT_STATUS_INTERNAL_ERROR;
474 ctx->check_password = auth_check_password;
475 ctx->get_challenge = auth_get_challenge;
476 ctx->set_challenge = auth_context_set_challenge;
477 ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
478 ctx->get_server_info_principal = auth_get_server_info_principal;
479 ctx->generate_session_info = auth_generate_session_info;
486 static const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
488 const char **auth_methods = NULL;
489 switch (lpcfg_server_role(lp_ctx)) {
490 case ROLE_STANDALONE:
491 auth_methods = lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
493 case ROLE_DOMAIN_MEMBER:
494 auth_methods = lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
496 case ROLE_DOMAIN_CONTROLLER:
497 auth_methods = lpcfg_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
503 /***************************************************************************
504 Make a auth_info struct for the auth subsystem
505 - Uses default auth_methods, depending on server role and smb.conf settings
506 ***************************************************************************/
507 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
508 struct tevent_context *ev,
509 struct messaging_context *msg,
510 struct loadparm_context *lp_ctx,
511 struct auth_context **auth_ctx)
514 const char **auth_methods;
515 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
517 return NT_STATUS_NO_MEMORY;
520 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
522 return NT_STATUS_INVALID_PARAMETER;
524 status = auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, NULL, auth_ctx);
525 talloc_free(tmp_ctx);
529 /* Create an auth context from an open LDB.
531 This allows us not to re-open the LDB when we need to do a some authentication logic (such as tokenGroups)
534 NTSTATUS auth_context_create_from_ldb(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, struct auth_context **auth_ctx)
537 const char **auth_methods;
538 struct loadparm_context *lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
539 struct tevent_context *ev = ldb_get_event_context(ldb);
541 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
543 return NT_STATUS_NO_MEMORY;
546 auth_methods = auth_methods_from_lp(tmp_ctx, lp_ctx);
548 return NT_STATUS_INVALID_PARAMETER;
550 status = auth_context_create_methods(mem_ctx, auth_methods, ev, NULL, lp_ctx, ldb, auth_ctx);
551 talloc_free(tmp_ctx);
555 /* the list of currently registered AUTH backends */
556 static struct auth_backend {
557 const struct auth_operations *ops;
559 static int num_backends;
562 register a AUTH backend.
564 The 'name' can be later used by other backends to find the operations
565 structure for this backend.
567 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
569 struct auth_operations *new_ops;
571 if (auth_backend_byname(ops->name) != NULL) {
572 /* its already registered! */
573 DEBUG(0,("AUTH backend '%s' already registered\n",
575 return NT_STATUS_OBJECT_NAME_COLLISION;
578 backends = talloc_realloc(talloc_autofree_context(), backends,
579 struct auth_backend, num_backends+1);
580 NT_STATUS_HAVE_NO_MEMORY(backends);
582 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
583 NT_STATUS_HAVE_NO_MEMORY(new_ops);
584 new_ops->name = talloc_strdup(new_ops, ops->name);
585 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
587 backends[num_backends].ops = new_ops;
591 DEBUG(3,("AUTH backend '%s' registered\n",
598 return the operations structure for a named backend of the specified type
600 const struct auth_operations *auth_backend_byname(const char *name)
604 for (i=0;i<num_backends;i++) {
605 if (strcmp(backends[i].ops->name, name) == 0) {
606 return backends[i].ops;
614 return the AUTH interface version, and the size of some critical types
615 This can be used by backends to either detect compilation errors, or provide
616 multiple implementations for different smbd compilation options in one module
618 const struct auth_critical_sizes *auth_interface_version(void)
620 static const struct auth_critical_sizes critical_sizes = {
621 AUTH_INTERFACE_VERSION,
622 sizeof(struct auth_operations),
623 sizeof(struct auth_method_context),
624 sizeof(struct auth_context),
625 sizeof(struct auth_usersupplied_info),
626 sizeof(struct auth_serversupplied_info)
629 return &critical_sizes;
632 _PUBLIC_ NTSTATUS auth_init(void)
634 static bool initialized = false;
635 extern NTSTATUS auth_developer_init(void);
636 extern NTSTATUS auth_winbind_init(void);
637 extern NTSTATUS auth_anonymous_init(void);
638 extern NTSTATUS auth_unix_init(void);
639 extern NTSTATUS auth_sam_init(void);
640 extern NTSTATUS auth_server_init(void);
642 init_module_fn static_init[] = { STATIC_auth_MODULES };
644 if (initialized) return NT_STATUS_OK;
647 run_init_functions(static_init);