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 "lib/events/events.h"
26 #include "param/param.h"
28 /***************************************************************************
30 ***************************************************************************/
31 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 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 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, 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 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 NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
354 struct event_context *ev,
355 struct messaging_context *msg,
356 struct auth_context **auth_ctx)
359 struct auth_context *ctx;
362 DEBUG(0,("auth_context_create: No auth method list!?\n"));
363 return NT_STATUS_INTERNAL_ERROR;
367 DEBUG(0,("auth_context_create: called with out event context\n"));
368 return NT_STATUS_INTERNAL_ERROR;
372 DEBUG(0,("auth_context_create: called with out messaging context\n"));
373 return NT_STATUS_INTERNAL_ERROR;
376 ctx = talloc(mem_ctx, struct auth_context);
377 NT_STATUS_HAVE_NO_MEMORY(ctx);
378 ctx->challenge.set_by = NULL;
379 ctx->challenge.may_be_modified = False;
380 ctx->challenge.data = data_blob(NULL, 0);
385 for (i=0; methods[i] ; i++) {
386 struct auth_method_context *method;
388 method = talloc(ctx, struct auth_method_context);
389 NT_STATUS_HAVE_NO_MEMORY(method);
391 method->ops = auth_backend_byname(methods[i]);
393 DEBUG(1,("auth_context_create: failed to find method=%s\n",
395 return NT_STATUS_INTERNAL_ERROR;
397 method->auth_ctx = ctx;
399 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
403 return NT_STATUS_INTERNAL_ERROR;
410 /***************************************************************************
411 Make a auth_info struct for the auth subsystem
412 - Uses default auth_methods, depending on server role and smb.conf settings
413 ***************************************************************************/
414 NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
415 struct event_context *ev,
416 struct messaging_context *msg,
417 struct auth_context **auth_ctx)
419 const char **auth_methods = NULL;
420 switch (lp_server_role(global_loadparm)) {
421 case ROLE_STANDALONE:
422 auth_methods = lp_parm_string_list(NULL, "auth methods", "standalone", NULL);
424 case ROLE_DOMAIN_MEMBER:
425 auth_methods = lp_parm_string_list(NULL, "auth methods", "member server", NULL);
427 case ROLE_DOMAIN_CONTROLLER:
428 auth_methods = lp_parm_string_list(NULL, "auth methods", "domain controller", NULL);
431 return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, auth_ctx);
435 /* the list of currently registered AUTH backends */
436 static struct auth_backend {
437 const struct auth_operations *ops;
439 static int num_backends;
442 register a AUTH backend.
444 The 'name' can be later used by other backends to find the operations
445 structure for this backend.
447 NTSTATUS auth_register(const struct auth_operations *ops)
449 struct auth_operations *new_ops;
451 if (auth_backend_byname(ops->name) != NULL) {
452 /* its already registered! */
453 DEBUG(0,("AUTH backend '%s' already registered\n",
455 return NT_STATUS_OBJECT_NAME_COLLISION;
458 backends = talloc_realloc(talloc_autofree_context(), backends,
459 struct auth_backend, num_backends+1);
460 NT_STATUS_HAVE_NO_MEMORY(backends);
462 new_ops = talloc_memdup(backends, ops, sizeof(*ops));
463 NT_STATUS_HAVE_NO_MEMORY(new_ops);
464 new_ops->name = talloc_strdup(new_ops, ops->name);
465 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
467 backends[num_backends].ops = new_ops;
471 DEBUG(3,("AUTH backend '%s' registered\n",
478 return the operations structure for a named backend of the specified type
480 const struct auth_operations *auth_backend_byname(const char *name)
484 for (i=0;i<num_backends;i++) {
485 if (strcmp(backends[i].ops->name, name) == 0) {
486 return backends[i].ops;
494 return the AUTH interface version, and the size of some critical types
495 This can be used by backends to either detect compilation errors, or provide
496 multiple implementations for different smbd compilation options in one module
498 const struct auth_critical_sizes *auth_interface_version(void)
500 static const struct auth_critical_sizes critical_sizes = {
501 AUTH_INTERFACE_VERSION,
502 sizeof(struct auth_operations),
503 sizeof(struct auth_method_context),
504 sizeof(struct auth_context),
505 sizeof(struct auth_usersupplied_info),
506 sizeof(struct auth_serversupplied_info)
509 return &critical_sizes;
512 NTSTATUS auth_init(void)
514 static BOOL initialized = False;
516 init_module_fn static_init[] = STATIC_auth_MODULES;
517 init_module_fn *shared_init;
519 if (initialized) return NT_STATUS_OK;
522 shared_init = load_samba_modules(NULL, "auth");
524 run_init_functions(static_init);
525 run_init_functions(shared_init);
527 talloc_free(shared_init);
532 NTSTATUS server_service_auth_init(void)