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/>.
22 #include "../lib/util/dlinklist.h"
23 #include "auth/auth.h"
24 #include "auth/ntlm/auth_proto.h"
25 #include "lib/events/events.h"
26 #include "param/param.h"
28 /***************************************************************************
30 ***************************************************************************/
31 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by)
33 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
34 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
36 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
37 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
42 /***************************************************************************
44 ***************************************************************************/
45 bool auth_challenge_may_be_modified(struct auth_context *auth_ctx)
47 return auth_ctx->challenge.may_be_modified;
50 /****************************************************************************
51 Try to get a challenge out of the various authentication modules.
52 Returns a const char of length 8 bytes.
53 ****************************************************************************/
54 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
57 struct auth_method_context *method;
59 if (auth_ctx->challenge.data.length) {
60 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
61 auth_ctx->challenge.set_by));
62 *_chal = auth_ctx->challenge.data.data;
66 for (method = auth_ctx->methods; method; method = method->next) {
67 DATA_BLOB challenge = data_blob(NULL,0);
69 nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
70 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
74 NT_STATUS_NOT_OK_RETURN(nt_status);
76 if (challenge.length != 8) {
77 DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n",
78 (unsigned)challenge.length, method->ops->name));
79 return NT_STATUS_INTERNAL_ERROR;
82 auth_ctx->challenge.data = challenge;
83 auth_ctx->challenge.set_by = method->ops->name;
88 if (!auth_ctx->challenge.set_by) {
90 generate_random_buffer(chal, 8);
92 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
93 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
94 auth_ctx->challenge.set_by = "random";
96 auth_ctx->challenge.may_be_modified = true;
99 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
100 auth_ctx->challenge.set_by));
102 *_chal = auth_ctx->challenge.data.data;
106 struct auth_check_password_sync_state {
109 struct auth_serversupplied_info *server_info;
112 static void auth_check_password_sync_callback(struct auth_check_password_request *req,
115 struct auth_check_password_sync_state *s = talloc_get_type(private_data,
116 struct auth_check_password_sync_state);
119 s->status = auth_check_password_recv(req, s, &s->server_info);
123 * Check a user's Plaintext, LM or NTLM password.
126 * Check a user's password, as given in the user_info struct and return various
127 * interesting details in the server_info struct.
129 * The return value takes precedence over the contents of the server_info
130 * struct. When the return is other than NT_STATUS_OK the contents
131 * of that structure is undefined.
133 * @param auth_ctx Supplies the challenges and some other data.
134 * Must be created with auth_context_create(), and the challenges should be
135 * filled in, either at creation or by calling the challenge geneation
136 * function auth_get_challenge().
138 * @param user_info Contains the user supplied components, including the passwords.
140 * @param mem_ctx The parent memory context for the server_info structure
142 * @param server_info If successful, contains information about the authentication,
143 * including a SAM_ACCOUNT struct describing the user.
145 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
149 _PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
151 const struct auth_usersupplied_info *user_info,
152 struct auth_serversupplied_info **server_info)
154 struct auth_check_password_sync_state *sync_state;
157 sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state);
158 NT_STATUS_HAVE_NO_MEMORY(sync_state);
160 auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state);
162 while (!sync_state->finished) {
163 event_loop_once(auth_ctx->event_ctx);
166 status = sync_state->status;
168 if (NT_STATUS_IS_OK(status)) {
169 *server_info = talloc_steal(mem_ctx, sync_state->server_info);
172 talloc_free(sync_state);
176 struct auth_check_password_request {
177 struct auth_context *auth_ctx;
178 const struct auth_usersupplied_info *user_info;
179 struct auth_serversupplied_info *server_info;
180 struct auth_method_context *method;
183 void (*fn)(struct auth_check_password_request *req, void *private_data);
188 static void auth_check_password_async_timed_handler(struct event_context *ev, struct timed_event *te,
189 struct timeval t, void *ptr)
191 struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request);
192 req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info);
193 req->callback.fn(req, req->callback.private_data);
197 * Check a user's Plaintext, LM or NTLM password.
200 * Check a user's password, as given in the user_info struct and return various
201 * interesting details in the server_info struct.
203 * The return value takes precedence over the contents of the server_info
204 * struct. When the return is other than NT_STATUS_OK the contents
205 * of that structure is undefined.
207 * @param auth_ctx Supplies the challenges and some other data.
208 * Must be created with make_auth_context(), and the challenges should be
209 * filled in, either at creation or by calling the challenge geneation
210 * function auth_get_challenge().
212 * @param user_info Contains the user supplied components, including the passwords.
214 * @param callback A callback function which will be called when the operation is finished.
215 * The callback function needs to call auth_check_password_recv() to get the return values
217 * @param private_data A private pointer which will ba passed to the callback function
221 _PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx,
222 const struct auth_usersupplied_info *user_info,
223 void (*callback)(struct auth_check_password_request *req, void *private_data),
226 /* if all the modules say 'not for me' this is reasonable */
228 struct auth_method_context *method;
229 const uint8_t *challenge;
230 struct auth_usersupplied_info *user_info_tmp;
231 struct auth_check_password_request *req = NULL;
233 DEBUG(3, ("auth_check_password_send: Checking password for unmapped user [%s]\\[%s]@[%s]\n",
234 user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
236 req = talloc_zero(auth_ctx, struct auth_check_password_request);
238 callback(NULL, private_data);
241 req->auth_ctx = auth_ctx;
242 req->user_info = user_info;
243 req->callback.fn = callback;
244 req->callback.private_data = private_data;
246 if (!user_info->mapped_state) {
247 nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp);
248 if (!NT_STATUS_IS_OK(nt_status)) goto failed;
249 user_info = user_info_tmp;
250 req->user_info = user_info_tmp;
253 DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n",
254 user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
256 nt_status = auth_get_challenge(auth_ctx, &challenge);
257 if (!NT_STATUS_IS_OK(nt_status)) {
258 DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
259 (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
263 if (auth_ctx->challenge.set_by) {
264 DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n",
265 auth_ctx->challenge.set_by));
268 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
269 dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
271 nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
272 for (method = auth_ctx->methods; method; method = method->next) {
274 struct timed_event *te = NULL;
276 /* check if the module wants to chek the password */
277 result = method->ops->want_check(method, req, user_info);
278 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
279 DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name));
284 req->method = method;
286 if (!NT_STATUS_IS_OK(nt_status)) break;
288 te = event_add_timed(auth_ctx->event_ctx, req,
290 auth_check_password_async_timed_handler, req);
292 nt_status = NT_STATUS_NO_MEMORY;
299 req->status = nt_status;
300 req->callback.fn(req, req->callback.private_data);
304 * Check a user's Plaintext, LM or NTLM password.
305 * async receive function
307 * The return value takes precedence over the contents of the server_info
308 * struct. When the return is other than NT_STATUS_OK the contents
309 * of that structure is undefined.
312 * @param req The async auth_check_password state, passes to the callers callback function
314 * @param mem_ctx The parent memory context for the server_info structure
316 * @param server_info If successful, contains information about the authentication,
317 * including a SAM_ACCOUNT struct describing the user.
319 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
323 _PUBLIC_ NTSTATUS auth_check_password_recv(struct auth_check_password_request *req,
325 struct auth_serversupplied_info **server_info)
329 NT_STATUS_HAVE_NO_MEMORY(req);
331 if (NT_STATUS_IS_OK(req->status)) {
332 DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n",
333 req->method->ops->name, req->server_info->domain_name, req->server_info->account_name));
335 *server_info = talloc_steal(mem_ctx, req->server_info);
337 DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n",
338 (req->method ? req->method->ops->name : "NO_METHOD"),
339 req->user_info->mapped.domain_name,
340 req->user_info->mapped.account_name,
341 nt_errstr(req->status)));
344 status = req->status;
349 /***************************************************************************
350 Make a auth_info struct for the auth subsystem
351 - Allow the caller to specify the methods to use
352 ***************************************************************************/
353 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
354 struct event_context *ev,
355 struct messaging_context *msg,
356 struct loadparm_context *lp_ctx,
357 struct auth_context **auth_ctx)
360 struct auth_context *ctx;
363 DEBUG(0,("auth_context_create: No auth method list!?\n"));
364 return NT_STATUS_INTERNAL_ERROR;
368 DEBUG(0,("auth_context_create: called with out event context\n"));
369 return NT_STATUS_INTERNAL_ERROR;
373 DEBUG(0,("auth_context_create: called with out messaging context\n"));
374 return NT_STATUS_INTERNAL_ERROR;
377 ctx = talloc(mem_ctx, struct auth_context);
378 NT_STATUS_HAVE_NO_MEMORY(ctx);
379 ctx->challenge.set_by = NULL;
380 ctx->challenge.may_be_modified = false;
381 ctx->challenge.data = data_blob(NULL, 0);
385 ctx->lp_ctx = lp_ctx;
387 for (i=0; methods[i] ; i++) {
388 struct auth_method_context *method;
390 method = talloc(ctx, struct auth_method_context);
391 NT_STATUS_HAVE_NO_MEMORY(method);
393 method->ops = auth_backend_byname(methods[i]);
395 DEBUG(1,("auth_context_create: failed to find method=%s\n",
397 return NT_STATUS_INTERNAL_ERROR;
399 method->auth_ctx = ctx;
401 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
405 return NT_STATUS_INTERNAL_ERROR;
412 /***************************************************************************
413 Make a auth_info struct for the auth subsystem
414 - Uses default auth_methods, depending on server role and smb.conf settings
415 ***************************************************************************/
416 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
417 struct event_context *ev,
418 struct messaging_context *msg,
419 struct loadparm_context *lp_ctx,
420 struct auth_context **auth_ctx)
422 const char **auth_methods = NULL;
423 switch (lp_server_role(lp_ctx)) {
424 case ROLE_STANDALONE:
425 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
427 case ROLE_DOMAIN_MEMBER:
428 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
430 case ROLE_DOMAIN_CONTROLLER:
431 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
434 return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx);
438 /* the list of currently registered AUTH backends */
439 static struct auth_backend {
440 const struct auth_operations *ops;
442 static int num_backends;
445 register a AUTH backend.
447 The 'name' can be later used by other backends to find the operations
448 structure for this backend.
450 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
452 struct auth_operations *new_ops;
454 if (auth_backend_byname(ops->name) != NULL) {
455 /* its already registered! */
456 DEBUG(0,("AUTH backend '%s' already registered\n",
458 return NT_STATUS_OBJECT_NAME_COLLISION;
461 backends = talloc_realloc(talloc_autofree_context(), backends,
462 struct auth_backend, num_backends+1);
463 NT_STATUS_HAVE_NO_MEMORY(backends);
465 new_ops = talloc_memdup(backends, ops, sizeof(*ops));
466 NT_STATUS_HAVE_NO_MEMORY(new_ops);
467 new_ops->name = talloc_strdup(new_ops, ops->name);
468 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
470 backends[num_backends].ops = new_ops;
474 DEBUG(3,("AUTH backend '%s' registered\n",
481 return the operations structure for a named backend of the specified type
483 const struct auth_operations *auth_backend_byname(const char *name)
487 for (i=0;i<num_backends;i++) {
488 if (strcmp(backends[i].ops->name, name) == 0) {
489 return backends[i].ops;
497 return the AUTH interface version, and the size of some critical types
498 This can be used by backends to either detect compilation errors, or provide
499 multiple implementations for different smbd compilation options in one module
501 const struct auth_critical_sizes *auth_interface_version(void)
503 static const struct auth_critical_sizes critical_sizes = {
504 AUTH_INTERFACE_VERSION,
505 sizeof(struct auth_operations),
506 sizeof(struct auth_method_context),
507 sizeof(struct auth_context),
508 sizeof(struct auth_usersupplied_info),
509 sizeof(struct auth_serversupplied_info)
512 return &critical_sizes;
515 _PUBLIC_ NTSTATUS auth_init(void)
517 static bool initialized = false;
518 extern NTSTATUS auth_developer_init(void);
519 extern NTSTATUS auth_winbind_init(void);
520 extern NTSTATUS auth_anonymous_init(void);
521 extern NTSTATUS auth_unix_init(void);
522 extern NTSTATUS auth_sam_init(void);
523 extern NTSTATUS auth_server_init(void);
525 init_module_fn static_init[] = { STATIC_auth_MODULES };
527 if (initialized) return NT_STATUS_OK;
530 run_init_functions(static_init);
535 NTSTATUS server_service_auth_init(void)