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/auth_proto.h"
25 #include "lib/events/events.h"
27 #include "param/param.h"
29 /***************************************************************************
31 ***************************************************************************/
32 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by)
34 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
35 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
37 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
38 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
43 /***************************************************************************
45 ***************************************************************************/
46 bool auth_challenge_may_be_modified(struct auth_context *auth_ctx)
48 return auth_ctx->challenge.may_be_modified;
51 /****************************************************************************
52 Try to get a challenge out of the various authentication modules.
53 Returns a const char of length 8 bytes.
54 ****************************************************************************/
55 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
58 struct auth_method_context *method;
60 if (auth_ctx->challenge.data.length) {
61 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
62 auth_ctx->challenge.set_by));
63 *_chal = auth_ctx->challenge.data.data;
67 for (method = auth_ctx->methods; method; method = method->next) {
68 DATA_BLOB challenge = data_blob(NULL,0);
70 nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
71 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
75 NT_STATUS_NOT_OK_RETURN(nt_status);
77 if (challenge.length != 8) {
78 DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n",
79 (unsigned)challenge.length, method->ops->name));
80 return NT_STATUS_INTERNAL_ERROR;
83 auth_ctx->challenge.data = challenge;
84 auth_ctx->challenge.set_by = method->ops->name;
89 if (!auth_ctx->challenge.set_by) {
91 generate_random_buffer(chal, 8);
93 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
94 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
95 auth_ctx->challenge.set_by = "random";
97 auth_ctx->challenge.may_be_modified = true;
100 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
101 auth_ctx->challenge.set_by));
103 *_chal = auth_ctx->challenge.data.data;
107 struct auth_check_password_sync_state {
110 struct auth_serversupplied_info *server_info;
113 static void auth_check_password_sync_callback(struct auth_check_password_request *req,
116 struct auth_check_password_sync_state *s = talloc_get_type(private_data,
117 struct auth_check_password_sync_state);
120 s->status = auth_check_password_recv(req, s, &s->server_info);
124 * Check a user's Plaintext, LM or NTLM password.
127 * Check a user's password, as given in the user_info struct and return various
128 * interesting details in the server_info struct.
130 * The return value takes precedence over the contents of the server_info
131 * struct. When the return is other than NT_STATUS_OK the contents
132 * of that structure is undefined.
134 * @param auth_ctx Supplies the challenges and some other data.
135 * Must be created with auth_context_create(), and the challenges should be
136 * filled in, either at creation or by calling the challenge geneation
137 * function auth_get_challenge().
139 * @param user_info Contains the user supplied components, including the passwords.
141 * @param mem_ctx The parent memory context for the server_info structure
143 * @param server_info If successful, contains information about the authentication,
144 * including a SAM_ACCOUNT struct describing the user.
146 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
150 _PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
152 const struct auth_usersupplied_info *user_info,
153 struct auth_serversupplied_info **server_info)
155 struct auth_check_password_sync_state *sync_state;
158 sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state);
159 NT_STATUS_HAVE_NO_MEMORY(sync_state);
161 auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state);
163 while (!sync_state->finished) {
164 event_loop_once(auth_ctx->event_ctx);
167 status = sync_state->status;
169 if (NT_STATUS_IS_OK(status)) {
170 *server_info = talloc_steal(mem_ctx, sync_state->server_info);
173 talloc_free(sync_state);
177 struct auth_check_password_request {
178 struct auth_context *auth_ctx;
179 const struct auth_usersupplied_info *user_info;
180 struct auth_serversupplied_info *server_info;
181 struct auth_method_context *method;
184 void (*fn)(struct auth_check_password_request *req, void *private_data);
189 static void auth_check_password_async_timed_handler(struct event_context *ev, struct timed_event *te,
190 struct timeval t, void *ptr)
192 struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request);
193 req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info);
194 req->callback.fn(req, req->callback.private_data);
198 * Check a user's Plaintext, LM or NTLM password.
201 * Check a user's password, as given in the user_info struct and return various
202 * interesting details in the server_info struct.
204 * The return value takes precedence over the contents of the server_info
205 * struct. When the return is other than NT_STATUS_OK the contents
206 * of that structure is undefined.
208 * @param auth_ctx Supplies the challenges and some other data.
209 * Must be created with make_auth_context(), and the challenges should be
210 * filled in, either at creation or by calling the challenge geneation
211 * function auth_get_challenge().
213 * @param user_info Contains the user supplied components, including the passwords.
215 * @param callback A callback function which will be called when the operation is finished.
216 * The callback function needs to call auth_check_password_recv() to get the return values
218 * @param private_data A private pointer which will ba passed to the callback function
222 _PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx,
223 const struct auth_usersupplied_info *user_info,
224 void (*callback)(struct auth_check_password_request *req, void *private_data),
227 /* if all the modules say 'not for me' this is reasonable */
229 struct auth_method_context *method;
230 const uint8_t *challenge;
231 struct auth_usersupplied_info *user_info_tmp;
232 struct auth_check_password_request *req = NULL;
234 DEBUG(3, ("auth_check_password_send: Checking password for unmapped user [%s]\\[%s]@[%s]\n",
235 user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
237 req = talloc_zero(auth_ctx, struct auth_check_password_request);
239 callback(NULL, private_data);
242 req->auth_ctx = auth_ctx;
243 req->user_info = user_info;
244 req->callback.fn = callback;
245 req->callback.private_data = private_data;
247 if (!user_info->mapped_state) {
248 nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp);
249 if (!NT_STATUS_IS_OK(nt_status)) goto failed;
250 user_info = user_info_tmp;
251 req->user_info = user_info_tmp;
254 DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n",
255 user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
257 nt_status = auth_get_challenge(auth_ctx, &challenge);
258 if (!NT_STATUS_IS_OK(nt_status)) {
259 DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
260 (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
264 if (auth_ctx->challenge.set_by) {
265 DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n",
266 auth_ctx->challenge.set_by));
269 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
270 dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
272 nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
273 for (method = auth_ctx->methods; method; method = method->next) {
275 struct timed_event *te = NULL;
277 /* check if the module wants to chek the password */
278 result = method->ops->want_check(method, req, user_info);
279 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
280 DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name));
285 req->method = method;
287 if (!NT_STATUS_IS_OK(nt_status)) break;
289 te = event_add_timed(auth_ctx->event_ctx, req,
291 auth_check_password_async_timed_handler, req);
293 nt_status = NT_STATUS_NO_MEMORY;
300 req->status = nt_status;
301 req->callback.fn(req, req->callback.private_data);
305 * Check a user's Plaintext, LM or NTLM password.
306 * async receive function
308 * The return value takes precedence over the contents of the server_info
309 * struct. When the return is other than NT_STATUS_OK the contents
310 * of that structure is undefined.
313 * @param req The async auth_check_password state, passes to the callers callback function
315 * @param mem_ctx The parent memory context for the server_info structure
317 * @param server_info If successful, contains information about the authentication,
318 * including a SAM_ACCOUNT struct describing the user.
320 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
324 _PUBLIC_ NTSTATUS auth_check_password_recv(struct auth_check_password_request *req,
326 struct auth_serversupplied_info **server_info)
330 NT_STATUS_HAVE_NO_MEMORY(req);
332 if (NT_STATUS_IS_OK(req->status)) {
333 DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n",
334 req->method->ops->name, req->server_info->domain_name, req->server_info->account_name));
336 *server_info = talloc_steal(mem_ctx, req->server_info);
338 DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n",
339 (req->method ? req->method->ops->name : "NO_METHOD"),
340 req->user_info->mapped.domain_name,
341 req->user_info->mapped.account_name,
342 nt_errstr(req->status)));
345 status = req->status;
350 /***************************************************************************
351 Make a auth_info struct for the auth subsystem
352 - Allow the caller to specify the methods to use
353 ***************************************************************************/
354 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
355 struct event_context *ev,
356 struct messaging_context *msg,
357 struct loadparm_context *lp_ctx,
358 struct auth_context **auth_ctx)
361 struct auth_context *ctx;
364 DEBUG(0,("auth_context_create: No auth method list!?\n"));
365 return NT_STATUS_INTERNAL_ERROR;
369 DEBUG(0,("auth_context_create: called with out event context\n"));
370 return NT_STATUS_INTERNAL_ERROR;
374 DEBUG(0,("auth_context_create: called with out messaging context\n"));
375 return NT_STATUS_INTERNAL_ERROR;
378 ctx = talloc(mem_ctx, struct auth_context);
379 NT_STATUS_HAVE_NO_MEMORY(ctx);
380 ctx->challenge.set_by = NULL;
381 ctx->challenge.may_be_modified = false;
382 ctx->challenge.data = data_blob(NULL, 0);
386 ctx->lp_ctx = lp_ctx;
388 for (i=0; methods[i] ; i++) {
389 struct auth_method_context *method;
391 method = talloc(ctx, struct auth_method_context);
392 NT_STATUS_HAVE_NO_MEMORY(method);
394 method->ops = auth_backend_byname(methods[i]);
396 DEBUG(1,("auth_context_create: failed to find method=%s\n",
398 return NT_STATUS_INTERNAL_ERROR;
400 method->auth_ctx = ctx;
402 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
406 return NT_STATUS_INTERNAL_ERROR;
413 /***************************************************************************
414 Make a auth_info struct for the auth subsystem
415 - Uses default auth_methods, depending on server role and smb.conf settings
416 ***************************************************************************/
417 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
418 struct event_context *ev,
419 struct messaging_context *msg,
420 struct loadparm_context *lp_ctx,
421 struct auth_context **auth_ctx)
423 const char **auth_methods = NULL;
424 switch (lp_server_role(lp_ctx)) {
425 case ROLE_STANDALONE:
426 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
428 case ROLE_DOMAIN_MEMBER:
429 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
431 case ROLE_DOMAIN_CONTROLLER:
432 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
435 return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx);
439 /* the list of currently registered AUTH backends */
440 static struct auth_backend {
441 const struct auth_operations *ops;
443 static int num_backends;
446 register a AUTH backend.
448 The 'name' can be later used by other backends to find the operations
449 structure for this backend.
451 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
453 struct auth_operations *new_ops;
455 if (auth_backend_byname(ops->name) != NULL) {
456 /* its already registered! */
457 DEBUG(0,("AUTH backend '%s' already registered\n",
459 return NT_STATUS_OBJECT_NAME_COLLISION;
462 backends = talloc_realloc(talloc_autofree_context(), backends,
463 struct auth_backend, num_backends+1);
464 NT_STATUS_HAVE_NO_MEMORY(backends);
466 new_ops = talloc_memdup(backends, ops, sizeof(*ops));
467 NT_STATUS_HAVE_NO_MEMORY(new_ops);
468 new_ops->name = talloc_strdup(new_ops, ops->name);
469 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
471 backends[num_backends].ops = new_ops;
475 DEBUG(3,("AUTH backend '%s' registered\n",
482 return the operations structure for a named backend of the specified type
484 const struct auth_operations *auth_backend_byname(const char *name)
488 for (i=0;i<num_backends;i++) {
489 if (strcmp(backends[i].ops->name, name) == 0) {
490 return backends[i].ops;
498 return the AUTH interface version, and the size of some critical types
499 This can be used by backends to either detect compilation errors, or provide
500 multiple implementations for different smbd compilation options in one module
502 const struct auth_critical_sizes *auth_interface_version(void)
504 static const struct auth_critical_sizes critical_sizes = {
505 AUTH_INTERFACE_VERSION,
506 sizeof(struct auth_operations),
507 sizeof(struct auth_method_context),
508 sizeof(struct auth_context),
509 sizeof(struct auth_usersupplied_info),
510 sizeof(struct auth_serversupplied_info)
513 return &critical_sizes;
516 _PUBLIC_ NTSTATUS auth_init(void)
518 static bool initialized = false;
519 extern NTSTATUS auth_developer_init(void);
520 extern NTSTATUS auth_winbind_init(void);
521 extern NTSTATUS auth_anonymous_init(void);
522 extern NTSTATUS auth_unix_init(void);
523 extern NTSTATUS auth_sam_init(void);
524 extern NTSTATUS auth_server_init(void);
526 init_module_fn static_init[] = { STATIC_auth_MODULES };
528 if (initialized) return NT_STATUS_OK;
531 run_init_functions(static_init);
536 NTSTATUS server_service_auth_init(void)