source: branches/samba-3.5.x/source4/auth/ntlm/auth.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 16 years ago

Samba 3.5.0: Initial import

File size: 18.3 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett 2001-2002
5 Copyright (C) Stefan Metzmacher 2005
6
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.
11
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.
16
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/>.
19*/
20
21#include "includes.h"
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"
27
28/***************************************************************************
29 Set a fixed challenge
30***************************************************************************/
31_PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by)
32{
33 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
34 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
35
36 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
37 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
38
39 return NT_STATUS_OK;
40}
41
42/***************************************************************************
43 Set a fixed challenge
44***************************************************************************/
45bool auth_challenge_may_be_modified(struct auth_context *auth_ctx)
46{
47 return auth_ctx->challenge.may_be_modified;
48}
49
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)
55{
56 NTSTATUS nt_status;
57 struct auth_method_context *method;
58
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;
63 return NT_STATUS_OK;
64 }
65
66 for (method = auth_ctx->methods; method; method = method->next) {
67 DATA_BLOB challenge = data_blob(NULL,0);
68
69 nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
70 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
71 continue;
72 }
73
74 NT_STATUS_NOT_OK_RETURN(nt_status);
75
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;
80 }
81
82 auth_ctx->challenge.data = challenge;
83 auth_ctx->challenge.set_by = method->ops->name;
84
85 break;
86 }
87
88 if (!auth_ctx->challenge.set_by) {
89 uint8_t chal[8];
90 generate_random_buffer(chal, 8);
91
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";
95
96 auth_ctx->challenge.may_be_modified = true;
97 }
98
99 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
100 auth_ctx->challenge.set_by));
101
102 *_chal = auth_ctx->challenge.data.data;
103 return NT_STATUS_OK;
104}
105
106/****************************************************************************
107 Try to get a challenge out of the various authentication modules.
108 Returns a const char of length 8 bytes.
109****************************************************************************/
110_PUBLIC_ NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx,
111 struct auth_context *auth_ctx,
112 const char *principal,
113 struct auth_serversupplied_info **server_info)
114{
115 NTSTATUS nt_status;
116 struct auth_method_context *method;
117
118 for (method = auth_ctx->methods; method; method = method->next) {
119 if (!method->ops->get_server_info_principal) {
120 continue;
121 }
122
123 nt_status = method->ops->get_server_info_principal(mem_ctx, auth_ctx, principal, server_info);
124 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
125 continue;
126 }
127
128 NT_STATUS_NOT_OK_RETURN(nt_status);
129
130 break;
131 }
132
133 return NT_STATUS_OK;
134}
135
136struct auth_check_password_sync_state {
137 bool finished;
138 NTSTATUS status;
139 struct auth_serversupplied_info *server_info;
140};
141
142static void auth_check_password_sync_callback(struct auth_check_password_request *req,
143 void *private_data)
144{
145 struct auth_check_password_sync_state *s = talloc_get_type(private_data,
146 struct auth_check_password_sync_state);
147
148 s->finished = true;
149 s->status = auth_check_password_recv(req, s, &s->server_info);
150}
151
152/**
153 * Check a user's Plaintext, LM or NTLM password.
154 * (sync version)
155 *
156 * Check a user's password, as given in the user_info struct and return various
157 * interesting details in the server_info struct.
158 *
159 * The return value takes precedence over the contents of the server_info
160 * struct. When the return is other than NT_STATUS_OK the contents
161 * of that structure is undefined.
162 *
163 * @param auth_ctx Supplies the challenges and some other data.
164 * Must be created with auth_context_create(), and the challenges should be
165 * filled in, either at creation or by calling the challenge geneation
166 * function auth_get_challenge().
167 *
168 * @param user_info Contains the user supplied components, including the passwords.
169 *
170 * @param mem_ctx The parent memory context for the server_info structure
171 *
172 * @param server_info If successful, contains information about the authentication,
173 * including a SAM_ACCOUNT struct describing the user.
174 *
175 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
176 *
177 **/
178
179_PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
180 TALLOC_CTX *mem_ctx,
181 const struct auth_usersupplied_info *user_info,
182 struct auth_serversupplied_info **server_info)
183{
184 struct auth_check_password_sync_state *sync_state;
185 NTSTATUS status;
186
187 sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state);
188 NT_STATUS_HAVE_NO_MEMORY(sync_state);
189
190 auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state);
191
192 while (!sync_state->finished) {
193 event_loop_once(auth_ctx->event_ctx);
194 }
195
196 status = sync_state->status;
197
198 if (NT_STATUS_IS_OK(status)) {
199 *server_info = talloc_steal(mem_ctx, sync_state->server_info);
200 }
201
202 talloc_free(sync_state);
203 return status;
204}
205
206struct auth_check_password_request {
207 struct auth_context *auth_ctx;
208 const struct auth_usersupplied_info *user_info;
209 struct auth_serversupplied_info *server_info;
210 struct auth_method_context *method;
211 NTSTATUS status;
212 struct {
213 void (*fn)(struct auth_check_password_request *req, void *private_data);
214 void *private_data;
215 } callback;
216};
217
218static void auth_check_password_async_timed_handler(struct tevent_context *ev, struct tevent_timer *te,
219 struct timeval t, void *ptr)
220{
221 struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request);
222 req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info);
223 req->callback.fn(req, req->callback.private_data);
224}
225
226/**
227 * Check a user's Plaintext, LM or NTLM password.
228 * async send hook
229 *
230 * Check a user's password, as given in the user_info struct and return various
231 * interesting details in the server_info struct.
232 *
233 * The return value takes precedence over the contents of the server_info
234 * struct. When the return is other than NT_STATUS_OK the contents
235 * of that structure is undefined.
236 *
237 * @param auth_ctx Supplies the challenges and some other data.
238 * Must be created with make_auth_context(), and the challenges should be
239 * filled in, either at creation or by calling the challenge geneation
240 * function auth_get_challenge().
241 *
242 * @param user_info Contains the user supplied components, including the passwords.
243 *
244 * @param callback A callback function which will be called when the operation is finished.
245 * The callback function needs to call auth_check_password_recv() to get the return values
246 *
247 * @param private_data A private pointer which will ba passed to the callback function
248 *
249 **/
250
251_PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx,
252 const struct auth_usersupplied_info *user_info,
253 void (*callback)(struct auth_check_password_request *req, void *private_data),
254 void *private_data)
255{
256 /* if all the modules say 'not for me' this is reasonable */
257 NTSTATUS nt_status;
258 struct auth_method_context *method;
259 const uint8_t *challenge;
260 struct auth_usersupplied_info *user_info_tmp;
261 struct auth_check_password_request *req = NULL;
262
263 DEBUG(3, ("auth_check_password_send: Checking password for unmapped user [%s]\\[%s]@[%s]\n",
264 user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
265
266 req = talloc_zero(auth_ctx, struct auth_check_password_request);
267 if (!req) {
268 callback(NULL, private_data);
269 return;
270 }
271 req->auth_ctx = auth_ctx;
272 req->user_info = user_info;
273 req->callback.fn = callback;
274 req->callback.private_data = private_data;
275
276 if (!user_info->mapped_state) {
277 nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp);
278 if (!NT_STATUS_IS_OK(nt_status)) goto failed;
279 user_info = user_info_tmp;
280 req->user_info = user_info_tmp;
281 }
282
283 DEBUGADD(3,("auth_check_password_send: mapped user is: [%s]\\[%s]@[%s]\n",
284 user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
285
286 nt_status = auth_get_challenge(auth_ctx, &challenge);
287 if (!NT_STATUS_IS_OK(nt_status)) {
288 DEBUG(0, ("auth_check_password_send: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
289 (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
290 goto failed;
291 }
292
293 if (auth_ctx->challenge.set_by) {
294 DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n",
295 auth_ctx->challenge.set_by));
296 }
297
298 DEBUG(10, ("auth_check_password_send: challenge is: \n"));
299 dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
300
301 nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
302 for (method = auth_ctx->methods; method; method = method->next) {
303 NTSTATUS result;
304 struct tevent_timer *te = NULL;
305
306 /* check if the module wants to chek the password */
307 result = method->ops->want_check(method, req, user_info);
308 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
309 DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name));
310 continue;
311 }
312
313 nt_status = result;
314 req->method = method;
315
316 if (!NT_STATUS_IS_OK(nt_status)) break;
317
318 te = event_add_timed(auth_ctx->event_ctx, req,
319 timeval_zero(),
320 auth_check_password_async_timed_handler, req);
321 if (!te) {
322 nt_status = NT_STATUS_NO_MEMORY;
323 goto failed;
324 }
325 return;
326 }
327
328failed:
329 req->status = nt_status;
330 req->callback.fn(req, req->callback.private_data);
331}
332
333/**
334 * Check a user's Plaintext, LM or NTLM password.
335 * async receive function
336 *
337 * The return value takes precedence over the contents of the server_info
338 * struct. When the return is other than NT_STATUS_OK the contents
339 * of that structure is undefined.
340 *
341 *
342 * @param req The async auth_check_password state, passes to the callers callback function
343 *
344 * @param mem_ctx The parent memory context for the server_info structure
345 *
346 * @param server_info If successful, contains information about the authentication,
347 * including a SAM_ACCOUNT struct describing the user.
348 *
349 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
350 *
351 **/
352
353_PUBLIC_ NTSTATUS auth_check_password_recv(struct auth_check_password_request *req,
354 TALLOC_CTX *mem_ctx,
355 struct auth_serversupplied_info **server_info)
356{
357 NTSTATUS status;
358
359 NT_STATUS_HAVE_NO_MEMORY(req);
360
361 if (NT_STATUS_IS_OK(req->status)) {
362 DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n",
363 req->method->ops->name, req->server_info->domain_name, req->server_info->account_name));
364
365 *server_info = talloc_steal(mem_ctx, req->server_info);
366 } else {
367 DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n",
368 (req->method ? req->method->ops->name : "NO_METHOD"),
369 req->user_info->mapped.domain_name,
370 req->user_info->mapped.account_name,
371 nt_errstr(req->status)));
372 }
373
374 status = req->status;
375 talloc_free(req);
376 return status;
377}
378
379/***************************************************************************
380 Make a auth_info struct for the auth subsystem
381 - Allow the caller to specify the methods to use
382***************************************************************************/
383_PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods,
384 struct tevent_context *ev,
385 struct messaging_context *msg,
386 struct loadparm_context *lp_ctx,
387 struct auth_context **auth_ctx)
388{
389 int i;
390 struct auth_context *ctx;
391
392 auth_init();
393
394 if (!methods) {
395 DEBUG(0,("auth_context_create: No auth method list!?\n"));
396 return NT_STATUS_INTERNAL_ERROR;
397 }
398
399 if (!ev) {
400 DEBUG(0,("auth_context_create: called with out event context\n"));
401 return NT_STATUS_INTERNAL_ERROR;
402 }
403
404 if (!msg) {
405 DEBUG(0,("auth_context_create: called with out messaging context\n"));
406 return NT_STATUS_INTERNAL_ERROR;
407 }
408
409 ctx = talloc(mem_ctx, struct auth_context);
410 NT_STATUS_HAVE_NO_MEMORY(ctx);
411 ctx->challenge.set_by = NULL;
412 ctx->challenge.may_be_modified = false;
413 ctx->challenge.data = data_blob(NULL, 0);
414 ctx->methods = NULL;
415 ctx->event_ctx = ev;
416 ctx->msg_ctx = msg;
417 ctx->lp_ctx = lp_ctx;
418
419 for (i=0; methods[i] ; i++) {
420 struct auth_method_context *method;
421
422 method = talloc(ctx, struct auth_method_context);
423 NT_STATUS_HAVE_NO_MEMORY(method);
424
425 method->ops = auth_backend_byname(methods[i]);
426 if (!method->ops) {
427 DEBUG(1,("auth_context_create: failed to find method=%s\n",
428 methods[i]));
429 return NT_STATUS_INTERNAL_ERROR;
430 }
431 method->auth_ctx = ctx;
432 method->depth = i;
433 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
434 }
435
436 if (!ctx->methods) {
437 return NT_STATUS_INTERNAL_ERROR;
438 }
439
440 ctx->check_password = auth_check_password;
441 ctx->get_challenge = auth_get_challenge;
442 ctx->set_challenge = auth_context_set_challenge;
443 ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
444 ctx->get_server_info_principal = auth_get_server_info_principal;
445
446 *auth_ctx = ctx;
447
448 return NT_STATUS_OK;
449}
450/***************************************************************************
451 Make a auth_info struct for the auth subsystem
452 - Uses default auth_methods, depending on server role and smb.conf settings
453***************************************************************************/
454_PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx,
455 struct tevent_context *ev,
456 struct messaging_context *msg,
457 struct loadparm_context *lp_ctx,
458 struct auth_context **auth_ctx)
459{
460 const char **auth_methods = NULL;
461 switch (lp_server_role(lp_ctx)) {
462 case ROLE_STANDALONE:
463 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
464 break;
465 case ROLE_DOMAIN_MEMBER:
466 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
467 break;
468 case ROLE_DOMAIN_CONTROLLER:
469 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
470 break;
471 }
472 return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx);
473}
474
475
476/* the list of currently registered AUTH backends */
477static struct auth_backend {
478 const struct auth_operations *ops;
479} *backends = NULL;
480static int num_backends;
481
482/*
483 register a AUTH backend.
484
485 The 'name' can be later used by other backends to find the operations
486 structure for this backend.
487*/
488_PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
489{
490 struct auth_operations *new_ops;
491
492 if (auth_backend_byname(ops->name) != NULL) {
493 /* its already registered! */
494 DEBUG(0,("AUTH backend '%s' already registered\n",
495 ops->name));
496 return NT_STATUS_OBJECT_NAME_COLLISION;
497 }
498
499 backends = talloc_realloc(talloc_autofree_context(), backends,
500 struct auth_backend, num_backends+1);
501 NT_STATUS_HAVE_NO_MEMORY(backends);
502
503 new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
504 NT_STATUS_HAVE_NO_MEMORY(new_ops);
505 new_ops->name = talloc_strdup(new_ops, ops->name);
506 NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
507
508 backends[num_backends].ops = new_ops;
509
510 num_backends++;
511
512 DEBUG(3,("AUTH backend '%s' registered\n",
513 ops->name));
514
515 return NT_STATUS_OK;
516}
517
518/*
519 return the operations structure for a named backend of the specified type
520*/
521const struct auth_operations *auth_backend_byname(const char *name)
522{
523 int i;
524
525 for (i=0;i<num_backends;i++) {
526 if (strcmp(backends[i].ops->name, name) == 0) {
527 return backends[i].ops;
528 }
529 }
530
531 return NULL;
532}
533
534/*
535 return the AUTH interface version, and the size of some critical types
536 This can be used by backends to either detect compilation errors, or provide
537 multiple implementations for different smbd compilation options in one module
538*/
539const struct auth_critical_sizes *auth_interface_version(void)
540{
541 static const struct auth_critical_sizes critical_sizes = {
542 AUTH_INTERFACE_VERSION,
543 sizeof(struct auth_operations),
544 sizeof(struct auth_method_context),
545 sizeof(struct auth_context),
546 sizeof(struct auth_usersupplied_info),
547 sizeof(struct auth_serversupplied_info)
548 };
549
550 return &critical_sizes;
551}
552
553_PUBLIC_ NTSTATUS auth_init(void)
554{
555 static bool initialized = false;
556 extern NTSTATUS auth_developer_init(void);
557 extern NTSTATUS auth_winbind_init(void);
558 extern NTSTATUS auth_anonymous_init(void);
559 extern NTSTATUS auth_unix_init(void);
560 extern NTSTATUS auth_sam_init(void);
561 extern NTSTATUS auth_server_init(void);
562
563 init_module_fn static_init[] = { STATIC_auth_MODULES };
564
565 if (initialized) return NT_STATUS_OK;
566 initialized = true;
567
568 run_init_functions(static_init);
569
570 return NT_STATUS_OK;
571}
572
573NTSTATUS server_service_auth_init(void)
574{
575 return auth_init();
576}
Note: See TracBrowser for help on using the repository browser.