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"
27 /***************************************************************************
29 ***************************************************************************/
30 NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by)
32 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
33 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
35 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
36 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
41 /***************************************************************************
43 ***************************************************************************/
44 BOOL auth_challenge_may_be_modified(struct auth_context *auth_ctx)
46 return auth_ctx->challenge.may_be_modified;
49 /****************************************************************************
50 Try to get a challenge out of the various authentication modules.
51 Returns a const char of length 8 bytes.
52 ****************************************************************************/
53 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
56 struct auth_method_context *method;
58 if (auth_ctx->challenge.data.length) {
59 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
60 auth_ctx->challenge.set_by));
61 *_chal = auth_ctx->challenge.data.data;
65 for (method = auth_ctx->methods; method; method = method->next) {
66 DATA_BLOB challenge = data_blob(NULL,0);
68 nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
69 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
73 NT_STATUS_NOT_OK_RETURN(nt_status);
75 if (challenge.length != 8) {
76 DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n",
77 (unsigned)challenge.length, method->ops->name));
78 return NT_STATUS_INTERNAL_ERROR;
81 auth_ctx->challenge.data = challenge;
82 auth_ctx->challenge.set_by = method->ops->name;
87 if (!auth_ctx->challenge.set_by) {
89 generate_random_buffer(chal, 8);
91 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
92 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
93 auth_ctx->challenge.set_by = "random";
95 auth_ctx->challenge.may_be_modified = True;
98 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
99 auth_ctx->challenge.set_by));
101 *_chal = auth_ctx->challenge.data.data;
105 struct auth_check_password_sync_state {
108 struct auth_serversupplied_info *server_info;
111 static void auth_check_password_sync_callback(struct auth_check_password_request *req,
114 struct auth_check_password_sync_state *s = talloc_get_type(private_data,
115 struct auth_check_password_sync_state);
118 s->status = auth_check_password_recv(req, s, &s->server_info);
122 * Check a user's Plaintext, LM or NTLM password.
125 * Check a user's password, as given in the user_info struct and return various
126 * interesting details in the server_info struct.
128 * The return value takes precedence over the contents of the server_info
129 * struct. When the return is other than NT_STATUS_OK the contents
130 * of that structure is undefined.
132 * @param auth_ctx Supplies the challenges and some other data.
133 * Must be created with auth_context_create(), and the challenges should be
134 * filled in, either at creation or by calling the challenge geneation
135 * function auth_get_challenge().
137 * @param user_info Contains the user supplied components, including the passwords.
139 * @param mem_ctx The parent memory context for the server_info structure
141 * @param server_info If successful, contains information about the authentication,
142 * including a SAM_ACCOUNT struct describing the user.
144 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
148 NTSTATUS auth_check_password(struct auth_context *auth_ctx,
150 const struct auth_usersupplied_info *user_info,
151 struct auth_serversupplied_info **server_info)
153 struct auth_check_password_sync_state *sync_state;
156 sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state);
157 NT_STATUS_HAVE_NO_MEMORY(sync_state);
159 auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state);
161 while (!sync_state->finished) {
162 event_loop_once(auth_ctx->event_ctx);
165 status = sync_state->status;
167 if (NT_STATUS_IS_OK(status)) {
168 *server_info = talloc_steal(mem_ctx, sync_state->server_info);
171 talloc_free(sync_state);
175 struct auth_check_password_request {
176 struct auth_context *auth_ctx;
177 const struct auth_usersupplied_info *user_info;
178 struct auth_serversupplied_info *server_info;
179 struct auth_method_context *method;
182 void (*fn)(struct auth_check_password_request *req, void *private_data);
187 static void auth_check_password_async_timed_handler(struct event_context *ev, struct timed_event *te,
188 struct timeval t, void *ptr)
190 struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request);
191 req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info);
192 req->callback.fn(req, req->callback.private_data);
196 * Check a user's Plaintext, LM or NTLM password.
199 * Check a user's password, as given in the user_info struct and return various
200 * interesting details in the server_info struct.
202 * The return value takes precedence over the contents of the server_info
203 * struct. When the return is other than NT_STATUS_OK the contents
204 * of that structure is undefined.
206 * @param auth_ctx Supplies the challenges and some other data.
207 * Must be created with make_auth_context(), and the challenges should be
208 * filled in, either at creation or by calling the challenge geneation
209 * function auth_get_challenge().
211 * @param user_info Contains the user supplied components, including the passwords.
213 * @param callback A callback function which will be called when the operation is finished.
214 * The callback function needs to call auth_check_password_recv() to get the return values
216 * @param private_data A private pointer which will ba passed to the callback function
220 void auth_check_password_send(struct auth_context *auth_ctx,
221 const struct auth_usersupplied_info *user_info,
222 void (*callback)(struct auth_check_password_request *req, void *private_data),
225 /* if all the modules say 'not for me' this is reasonable */
227 struct auth_method_context *method;
228 const uint8_t *challenge;
229 struct auth_usersupplied_info *user_info_tmp;
230 struct auth_check_password_request *req = NULL;
232 DEBUG(3, ("auth_check_password_send: Checking password for unmapped user [%s]\\[%s]@[%s]\n",
233 user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
235 req = talloc_zero(auth_ctx, struct auth_check_password_request);
237 callback(NULL, private_data);
240 req->auth_ctx = auth_ctx;
241 req->user_info = user_info;
242 req->callback.fn = callback;
243 req->callback.private_data = private_data;
245 if (!user_info->mapped_state) {
246 nt_status = map_user_info(req, user_info, &user_info_tmp);
247 if (!NT_STATUS_IS_OK(nt_status)) goto failed;
248 user_info = user_info_tmp;
249 req->user_info = user_info_tmp;
252 DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n",
253 user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
255 nt_status = auth_get_challenge(auth_ctx, &challenge);
256 if (!NT_STATUS_IS_OK(nt_status)) {
257 DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
258 (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
262 if (auth_ctx->challenge.set_by) {
263 DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n",
264 auth_ctx->challenge.set_by));
267 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
268 dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
270 nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
271 for (method = auth_ctx->methods; method; method = method->next) {
273 struct timed_event *te = NULL;
275 /* check if the module wants to chek the password */
276 result = method->ops->want_check(method, req, user_info);
277 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
278 DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name));
283 req->method = method;
285 if (!NT_STATUS_IS_OK(nt_status)) break;
287 te = event_add_timed(auth_ctx->event_ctx, req,
289 auth_check_password_async_timed_handler, req);
291 nt_status = NT_STATUS_NO_MEMORY;
298 req->status = nt_status;
299 req->callback.fn(req, req->callback.private_data);
303 * Check a user's Plaintext, LM or NTLM password.
304 * async receive function
306 * The return value takes precedence over the contents of the server_info
307 * struct. When the return is other than NT_STATUS_OK the contents
308 * of that structure is undefined.
311 * @param req The async auth_check_password state, passes to the callers callback function
313 * @param mem_ctx The parent memory context for the server_info structure
315 * @param server_info If successful, contains information about the authentication,
316 * including a SAM_ACCOUNT struct describing the user.
318 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
322 NTSTATUS auth_check_password_recv(struct auth_check_password_request *req,
324 struct auth_serversupplied_info **server_info)
328 NT_STATUS_HAVE_NO_MEMORY(req);
330 if (NT_STATUS_IS_OK(req->status)) {
331 DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n",
332 req->method->ops->name, req->server_info->domain_name, req->server_info->account_name));
334 *server_info = talloc_steal(mem_ctx, req->server_info);
336 DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n",
337 (req->method ? req->method->ops->name : "NO_METHOD"),
338 req->user_info->mapped.domain_name,
339 req->user_info->mapped.account_name,
340 nt_errstr(req->status)));
343 status = req->status;
348 /***************************************************************************
349 Make a auth_info struct for the auth subsystem
350 - Allow the caller to specify the methods to use
351 ***************************************************************************/
352 NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
353 struct event_context *ev,
354 struct messaging_context *msg,
355 struct auth_context **auth_ctx)
358 struct auth_context *ctx;
361 DEBUG(0,("auth_context_create: No auth method list!?\n"));
362 return NT_STATUS_INTERNAL_ERROR;
366 DEBUG(0,("auth_context_create: called with out event context\n"));
367 return NT_STATUS_INTERNAL_ERROR;
371 DEBUG(0,("auth_context_create: called with out messaging context\n"));
372 return NT_STATUS_INTERNAL_ERROR;
375 ctx = talloc(mem_ctx, struct auth_context);
376 NT_STATUS_HAVE_NO_MEMORY(ctx);
377 ctx->challenge.set_by = NULL;
378 ctx->challenge.may_be_modified = False;
379 ctx->challenge.data = data_blob(NULL, 0);
384 for (i=0; methods[i] ; i++) {
385 struct auth_method_context *method;
387 method = talloc(ctx, struct auth_method_context);
388 NT_STATUS_HAVE_NO_MEMORY(method);
390 method->ops = auth_backend_byname(methods[i]);
392 DEBUG(1,("auth_context_create: failed to find method=%s\n",
394 return NT_STATUS_INTERNAL_ERROR;
396 method->auth_ctx = ctx;
398 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
402 return NT_STATUS_INTERNAL_ERROR;
409 /***************************************************************************
410 Make a auth_info struct for the auth subsystem
411 - Uses default auth_methods, depending on server role and smb.conf settings
412 ***************************************************************************/
413 NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
414 struct event_context *ev,
415 struct messaging_context *msg,
416 struct auth_context **auth_ctx)
418 const char **auth_methods = NULL;
419 switch (lp_server_role()) {
420 case ROLE_STANDALONE:
421 auth_methods = lp_parm_string_list(-1, "auth methods", "standalone", NULL);
423 case ROLE_DOMAIN_MEMBER:
424 auth_methods = lp_parm_string_list(-1, "auth methods", "member server", NULL);
426 case ROLE_DOMAIN_CONTROLLER:
427 auth_methods = lp_parm_string_list(-1, "auth methods", "domain controller", NULL);
430 return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, auth_ctx);
434 /* the list of currently registered AUTH backends */
435 static struct auth_backend {
436 const struct auth_operations *ops;
438 static int num_backends;
441 register a AUTH backend.
443 The 'name' can be later used by other backends to find the operations
444 structure for this backend.
446 NTSTATUS auth_register(const void *_ops)
448 const struct auth_operations *ops = _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 = realloc_p(backends, struct auth_backend, num_backends+1);
460 return NT_STATUS_NO_MEMORY;
463 new_ops = smb_xmemdup(ops, sizeof(*ops));
464 new_ops->name = smb_xstrdup(ops->name);
466 backends[num_backends].ops = new_ops;
470 DEBUG(3,("AUTH backend '%s' registered\n",
477 return the operations structure for a named backend of the specified type
479 const struct auth_operations *auth_backend_byname(const char *name)
483 for (i=0;i<num_backends;i++) {
484 if (strcmp(backends[i].ops->name, name) == 0) {
485 return backends[i].ops;
493 return the AUTH interface version, and the size of some critical types
494 This can be used by backends to either detect compilation errors, or provide
495 multiple implementations for different smbd compilation options in one module
497 const struct auth_critical_sizes *auth_interface_version(void)
499 static const struct auth_critical_sizes critical_sizes = {
500 AUTH_INTERFACE_VERSION,
501 sizeof(struct auth_operations),
502 sizeof(struct auth_method_context),
503 sizeof(struct auth_context),
504 sizeof(struct auth_usersupplied_info),
505 sizeof(struct auth_serversupplied_info)
508 return &critical_sizes;
511 NTSTATUS auth_init(void)
513 static BOOL initialized = False;
515 init_module_fn static_init[] = STATIC_auth_MODULES;
516 init_module_fn *shared_init;
518 if (initialized) return NT_STATUS_OK;
521 shared_init = load_samba_modules(NULL, "auth");
523 run_init_functions(static_init);
524 run_init_functions(shared_init);
526 talloc_free(shared_init);
531 NTSTATUS server_service_auth_init(void)