s4:torture/rpc/samba3rpc.c: make use of dcerpc_binding_handle stubs
[Samba/nascimento.git] / source4 / auth / ntlm / auth.c
blobd5df387d8065e897fcafa5656005ee4fba7f2eb4
1 /*
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/>.
21 #include "includes.h"
22 #include <tevent.h>
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"
29 /***************************************************************************
30 Set a fixed challenge
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);
40 return NT_STATUS_OK;
43 /***************************************************************************
44 Set a fixed challenge
45 ***************************************************************************/
46 _PUBLIC_ 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, uint8_t chal[8])
57 NTSTATUS nt_status;
58 struct auth_method_context *method;
60 if (auth_ctx->challenge.data.length == 8) {
61 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
62 auth_ctx->challenge.set_by));
63 memcpy(chal, auth_ctx->challenge.data.data, 8);
64 return NT_STATUS_OK;
67 for (method = auth_ctx->methods; method; method = method->next) {
68 nt_status = method->ops->get_challenge(method, auth_ctx, chal);
69 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
70 continue;
73 NT_STATUS_NOT_OK_RETURN(nt_status);
75 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
76 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
77 auth_ctx->challenge.set_by = method->ops->name;
79 break;
82 if (!auth_ctx->challenge.set_by) {
83 generate_random_buffer(chal, 8);
85 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
86 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
87 auth_ctx->challenge.set_by = "random";
89 auth_ctx->challenge.may_be_modified = true;
92 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
93 auth_ctx->challenge.set_by));
95 return NT_STATUS_OK;
98 /****************************************************************************
99 Try to get a challenge out of the various authentication modules.
100 Returns a const char of length 8 bytes.
101 ****************************************************************************/
102 _PUBLIC_ NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx,
103 struct auth_context *auth_ctx,
104 const char *principal,
105 struct auth_serversupplied_info **server_info)
107 NTSTATUS nt_status;
108 struct auth_method_context *method;
110 for (method = auth_ctx->methods; method; method = method->next) {
111 if (!method->ops->get_server_info_principal) {
112 continue;
115 nt_status = method->ops->get_server_info_principal(mem_ctx, auth_ctx, principal, server_info);
116 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
117 continue;
120 NT_STATUS_NOT_OK_RETURN(nt_status);
122 break;
125 return NT_STATUS_OK;
129 * Check a user's Plaintext, LM or NTLM password.
130 * (sync version)
132 * Check a user's password, as given in the user_info struct and return various
133 * interesting details in the server_info struct.
135 * The return value takes precedence over the contents of the server_info
136 * struct. When the return is other than NT_STATUS_OK the contents
137 * of that structure is undefined.
139 * @param auth_ctx Supplies the challenges and some other data.
140 * Must be created with auth_context_create(), and the challenges should be
141 * filled in, either at creation or by calling the challenge geneation
142 * function auth_get_challenge().
144 * @param user_info Contains the user supplied components, including the passwords.
146 * @param mem_ctx The parent memory context for the server_info structure
148 * @param server_info If successful, contains information about the authentication,
149 * including a SAM_ACCOUNT struct describing the user.
151 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
155 _PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
156 TALLOC_CTX *mem_ctx,
157 const struct auth_usersupplied_info *user_info,
158 struct auth_serversupplied_info **server_info)
160 struct tevent_req *subreq;
161 struct tevent_context *ev;
162 bool ok;
163 NTSTATUS status;
165 /*TODO: create a new event context here! */
166 ev = auth_ctx->event_ctx;
168 subreq = auth_check_password_send(mem_ctx,
170 auth_ctx,
171 user_info);
172 if (subreq == NULL) {
173 return NT_STATUS_NO_MEMORY;
176 ok = tevent_req_poll(subreq, ev);
177 if (!ok) {
178 return NT_STATUS_INTERNAL_ERROR;
181 status = auth_check_password_recv(subreq, mem_ctx, server_info);
182 TALLOC_FREE(subreq);
184 return status;
187 struct auth_check_password_state {
188 struct auth_context *auth_ctx;
189 const struct auth_usersupplied_info *user_info;
190 struct auth_serversupplied_info *server_info;
191 struct auth_method_context *method;
194 static void auth_check_password_async_trigger(struct tevent_context *ev,
195 struct tevent_immediate *im,
196 void *private_data);
198 * Check a user's Plaintext, LM or NTLM password.
199 * async send hook
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 mem_ctx The memory context the request should operate on
210 * @param ev The tevent context the request should operate on
212 * @param auth_ctx Supplies the challenges and some other data.
213 * Must be created with make_auth_context(), and the challenges should be
214 * filled in, either at creation or by calling the challenge geneation
215 * function auth_get_challenge().
217 * @param user_info Contains the user supplied components, including the passwords.
219 * @return The request handle or NULL on no memory error.
223 _PUBLIC_ struct tevent_req *auth_check_password_send(TALLOC_CTX *mem_ctx,
224 struct tevent_context *ev,
225 struct auth_context *auth_ctx,
226 const struct auth_usersupplied_info *user_info)
228 struct tevent_req *req;
229 struct auth_check_password_state *state;
230 /* if all the modules say 'not for me' this is reasonable */
231 NTSTATUS nt_status;
232 struct auth_method_context *method;
233 uint8_t chal[8];
234 struct auth_usersupplied_info *user_info_tmp;
235 struct tevent_immediate *im;
237 DEBUG(3,("auth_check_password_send: "
238 "Checking password for unmapped user [%s]\\[%s]@[%s]\n",
239 user_info->client.domain_name, user_info->client.account_name,
240 user_info->workstation_name));
242 req = tevent_req_create(mem_ctx, &state,
243 struct auth_check_password_state);
244 if (req == NULL) {
245 return NULL;
248 state->auth_ctx = auth_ctx;
249 state->user_info = user_info;
250 state->method = NULL;
252 if (!user_info->mapped_state) {
253 nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx),
254 user_info, &user_info_tmp);
255 if (tevent_req_nterror(req, nt_status)) {
256 return tevent_req_post(req, ev);
258 user_info = user_info_tmp;
259 state->user_info = user_info_tmp;
262 DEBUGADD(3,("auth_check_password_send: "
263 "mapped user is: [%s]\\[%s]@[%s]\n",
264 user_info->mapped.domain_name,
265 user_info->mapped.account_name,
266 user_info->workstation_name));
268 nt_status = auth_get_challenge(auth_ctx, chal);
269 if (tevent_req_nterror(req, nt_status)) {
270 DEBUG(0,("auth_check_password_send: "
271 "Invalid challenge (length %u) stored for "
272 "this auth context set_by %s - cannot continue: %s\n",
273 (unsigned)auth_ctx->challenge.data.length,
274 auth_ctx->challenge.set_by,
275 nt_errstr(nt_status)));
276 return tevent_req_post(req, ev);
279 if (auth_ctx->challenge.set_by) {
280 DEBUG(10,("auth_check_password_send: "
281 "auth_context challenge created by %s\n",
282 auth_ctx->challenge.set_by));
285 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
286 dump_data(5, auth_ctx->challenge.data.data,
287 auth_ctx->challenge.data.length);
289 im = tevent_create_immediate(state);
290 if (tevent_req_nomem(im, req)) {
291 return tevent_req_post(req, ev);
294 for (method = auth_ctx->methods; method; method = method->next) {
295 NTSTATUS result;
297 /* check if the module wants to chek the password */
298 result = method->ops->want_check(method, req, user_info);
299 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
300 DEBUG(11,("auth_check_password_send: "
301 "%s had nothing to say\n",
302 method->ops->name));
303 continue;
306 state->method = method;
308 if (tevent_req_nterror(req, result)) {
309 return tevent_req_post(req, ev);
312 tevent_schedule_immediate(im,
313 auth_ctx->event_ctx,
314 auth_check_password_async_trigger,
315 req);
317 return req;
320 /* If all the modules say 'not for me', then this is reasonable */
321 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
322 return tevent_req_post(req, ev);
325 static void auth_check_password_async_trigger(struct tevent_context *ev,
326 struct tevent_immediate *im,
327 void *private_data)
329 struct tevent_req *req =
330 talloc_get_type_abort(private_data, struct tevent_req);
331 struct auth_check_password_state *state =
332 tevent_req_data(req, struct auth_check_password_state);
333 NTSTATUS status;
335 status = state->method->ops->check_password(state->method,
336 state,
337 state->user_info,
338 &state->server_info);
339 if (tevent_req_nterror(req, status)) {
340 return;
343 tevent_req_done(req);
347 * Check a user's Plaintext, LM or NTLM password.
348 * async receive function
350 * The return value takes precedence over the contents of the server_info
351 * struct. When the return is other than NT_STATUS_OK the contents
352 * of that structure is undefined.
355 * @param req The async request state
357 * @param mem_ctx The parent memory context for the server_info structure
359 * @param server_info If successful, contains information about the authentication,
360 * including a SAM_ACCOUNT struct describing the user.
362 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
366 _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
367 TALLOC_CTX *mem_ctx,
368 struct auth_serversupplied_info **server_info)
370 struct auth_check_password_state *state =
371 tevent_req_data(req, struct auth_check_password_state);
372 NTSTATUS status;
374 if (tevent_req_is_nterror(req, &status)) {
375 DEBUG(2,("auth_check_password_recv: "
376 "%s authentication for user [%s\\%s]"
377 "FAILED with error %s\n",
378 (state->method ? state->method->ops->name : "NO_METHOD"),
379 state->user_info->mapped.domain_name,
380 state->user_info->mapped.account_name,
381 nt_errstr(status)));
382 tevent_req_received(req);
383 return status;
386 DEBUG(5,("auth_check_password_recv: "
387 "%s authentication for user [%s\\%s] succeeded\n",
388 state->method->ops->name,
389 state->server_info->domain_name,
390 state->server_info->account_name));
392 *server_info = talloc_move(mem_ctx, &state->server_info);
394 tevent_req_received(req);
395 return NT_STATUS_OK;
398 /***************************************************************************
399 Make a auth_info struct for the auth subsystem
400 - Allow the caller to specify the methods to use
401 ***************************************************************************/
402 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
403 struct tevent_context *ev,
404 struct messaging_context *msg,
405 struct loadparm_context *lp_ctx,
406 struct auth_context **auth_ctx)
408 int i;
409 struct auth_context *ctx;
411 auth_init();
413 if (!methods) {
414 DEBUG(0,("auth_context_create: No auth method list!?\n"));
415 return NT_STATUS_INTERNAL_ERROR;
418 if (!ev) {
419 DEBUG(0,("auth_context_create: called with out event context\n"));
420 return NT_STATUS_INTERNAL_ERROR;
423 if (!msg) {
424 DEBUG(0,("auth_context_create: called with out messaging context\n"));
425 return NT_STATUS_INTERNAL_ERROR;
428 ctx = talloc(mem_ctx, struct auth_context);
429 NT_STATUS_HAVE_NO_MEMORY(ctx);
430 ctx->challenge.set_by = NULL;
431 ctx->challenge.may_be_modified = false;
432 ctx->challenge.data = data_blob(NULL, 0);
433 ctx->methods = NULL;
434 ctx->event_ctx = ev;
435 ctx->msg_ctx = msg;
436 ctx->lp_ctx = lp_ctx;
438 for (i=0; methods[i] ; i++) {
439 struct auth_method_context *method;
441 method = talloc(ctx, struct auth_method_context);
442 NT_STATUS_HAVE_NO_MEMORY(method);
444 method->ops = auth_backend_byname(methods[i]);
445 if (!method->ops) {
446 DEBUG(1,("auth_context_create: failed to find method=%s\n",
447 methods[i]));
448 return NT_STATUS_INTERNAL_ERROR;
450 method->auth_ctx = ctx;
451 method->depth = i;
452 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
455 if (!ctx->methods) {
456 return NT_STATUS_INTERNAL_ERROR;
459 ctx->check_password = auth_check_password;
460 ctx->get_challenge = auth_get_challenge;
461 ctx->set_challenge = auth_context_set_challenge;
462 ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
463 ctx->get_server_info_principal = auth_get_server_info_principal;
465 *auth_ctx = ctx;
467 return NT_STATUS_OK;
469 /***************************************************************************
470 Make a auth_info struct for the auth subsystem
471 - Uses default auth_methods, depending on server role and smb.conf settings
472 ***************************************************************************/
473 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
474 struct tevent_context *ev,
475 struct messaging_context *msg,
476 struct loadparm_context *lp_ctx,
477 struct auth_context **auth_ctx)
479 const char **auth_methods = NULL;
480 switch (lp_server_role(lp_ctx)) {
481 case ROLE_STANDALONE:
482 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
483 break;
484 case ROLE_DOMAIN_MEMBER:
485 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
486 break;
487 case ROLE_DOMAIN_CONTROLLER:
488 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
489 break;
491 return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx);
495 /* the list of currently registered AUTH backends */
496 static struct auth_backend {
497 const struct auth_operations *ops;
498 } *backends = NULL;
499 static int num_backends;
502 register a AUTH backend.
504 The 'name' can be later used by other backends to find the operations
505 structure for this backend.
507 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
509 struct auth_operations *new_ops;
511 if (auth_backend_byname(ops->name) != NULL) {
512 /* its already registered! */
513 DEBUG(0,("AUTH backend '%s' already registered\n",
514 ops->name));
515 return NT_STATUS_OBJECT_NAME_COLLISION;
518 backends = talloc_realloc(talloc_autofree_context(), backends,
519 struct auth_backend, num_backends+1);
520 NT_STATUS_HAVE_NO_MEMORY(backends);
522 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
523 NT_STATUS_HAVE_NO_MEMORY(new_ops);
524 new_ops->name = talloc_strdup(new_ops, ops->name);
525 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
527 backends[num_backends].ops = new_ops;
529 num_backends++;
531 DEBUG(3,("AUTH backend '%s' registered\n",
532 ops->name));
534 return NT_STATUS_OK;
538 return the operations structure for a named backend of the specified type
540 const struct auth_operations *auth_backend_byname(const char *name)
542 int i;
544 for (i=0;i<num_backends;i++) {
545 if (strcmp(backends[i].ops->name, name) == 0) {
546 return backends[i].ops;
550 return NULL;
554 return the AUTH interface version, and the size of some critical types
555 This can be used by backends to either detect compilation errors, or provide
556 multiple implementations for different smbd compilation options in one module
558 const struct auth_critical_sizes *auth_interface_version(void)
560 static const struct auth_critical_sizes critical_sizes = {
561 AUTH_INTERFACE_VERSION,
562 sizeof(struct auth_operations),
563 sizeof(struct auth_method_context),
564 sizeof(struct auth_context),
565 sizeof(struct auth_usersupplied_info),
566 sizeof(struct auth_serversupplied_info)
569 return &critical_sizes;
572 _PUBLIC_ NTSTATUS auth_init(void)
574 static bool initialized = false;
575 extern NTSTATUS auth_developer_init(void);
576 extern NTSTATUS auth_winbind_init(void);
577 extern NTSTATUS auth_anonymous_init(void);
578 extern NTSTATUS auth_unix_init(void);
579 extern NTSTATUS auth_sam_init(void);
580 extern NTSTATUS auth_server_init(void);
582 init_module_fn static_init[] = { STATIC_auth_MODULES };
584 if (initialized) return NT_STATUS_OK;
585 initialized = true;
587 run_init_functions(static_init);
589 return NT_STATUS_OK;
592 NTSTATUS server_service_auth_init(void)
594 return auth_init();