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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "dlinklist.h"
24 #include "auth/auth.h"
25 #include "lib/events/events.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 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;
107 * Check a user's Plaintext, LM or NTLM password.
109 * Check a user's password, as given in the user_info struct and return various
110 * interesting details in the server_info struct.
112 * The return value takes precedence over the contents of the server_info
113 * struct. When the return is other than NT_STATUS_OK the contents
114 * of that structure is undefined.
116 * @param user_info Contains the user supplied components, including the passwords.
118 * @param auth_context Supplies the challenges and some other data.
119 * Must be created with make_auth_context(), and the challenges should be
120 * filled in, either at creation or by calling the challenge geneation
121 * function auth_get_challenge().
123 * @param server_info If successful, contains information about the authentication,
124 * including a SAM_ACCOUNT struct describing the user.
126 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
130 NTSTATUS auth_check_password(struct auth_context *auth_ctx,
132 const struct auth_usersupplied_info *user_info,
133 struct auth_serversupplied_info **server_info)
135 /* if all the modules say 'not for me' this is reasonable */
137 struct auth_method_context *method;
138 const char *method_name = "NO METHOD";
139 const uint8_t *challenge;
140 struct auth_usersupplied_info *user_info_tmp;
142 DEBUG(3, ("auth_check_password: Checking password for unmapped user [%s]\\[%s]@[%s]\n",
143 user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
145 if (!user_info->mapped_state) {
146 nt_status = map_user_info(mem_ctx, user_info, &user_info_tmp);
147 if (!NT_STATUS_IS_OK(nt_status)) {
150 user_info = user_info_tmp;
153 DEBUGADD(3,("auth_check_password: mapped user is: [%s]\\[%s]@[%s]\n",
154 user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
156 nt_status = auth_get_challenge(auth_ctx, &challenge);
158 if (!NT_STATUS_IS_OK(nt_status)) {
159 DEBUG(0, ("auth_check_password: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
160 (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
164 if (auth_ctx->challenge.set_by) {
165 DEBUG(10, ("auth_check_password: auth_context challenge created by %s\n",
166 auth_ctx->challenge.set_by));
169 DEBUG(10, ("challenge is: \n"));
170 dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
172 nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
173 for (method = auth_ctx->methods; method; method = method->next) {
176 result = method->ops->check_password(method, mem_ctx, user_info, server_info);
178 /* check if the module did anything */
179 if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
180 method_name = method->ops->name;
185 DEBUG(11,("auth_check_password: %s had nothing to say\n", method->ops->name));
188 if (!NT_STATUS_IS_OK(nt_status)) {
189 DEBUG(2,("auth_check_password: %s authentication for user [%s\\%s] FAILED with error %s\n",
190 method_name, user_info->mapped.domain_name, user_info->mapped.account_name,
191 nt_errstr(nt_status)));
195 DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n",
196 method_name, (*server_info)->domain_name, (*server_info)->account_name));
201 /***************************************************************************
202 Make a auth_info struct for the auth subsystem
203 ***************************************************************************/
204 NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods,
205 struct auth_context **auth_ctx,
206 struct event_context *ev)
209 struct auth_context *ctx;
212 DEBUG(0,("auth_context_create: No auth method list!?\n"));
213 return NT_STATUS_INTERNAL_ERROR;
216 ctx = talloc(mem_ctx, struct auth_context);
217 NT_STATUS_HAVE_NO_MEMORY(ctx);
218 ctx->challenge.set_by = NULL;
219 ctx->challenge.may_be_modified = False;
220 ctx->challenge.data = data_blob(NULL, 0);
224 ev = event_context_init(ctx);
227 return NT_STATUS_NO_MEMORY;
233 for (i=0; methods[i] ; i++) {
234 struct auth_method_context *method;
236 method = talloc(ctx, struct auth_method_context);
237 NT_STATUS_HAVE_NO_MEMORY(method);
239 method->ops = auth_backend_byname(methods[i]);
241 DEBUG(1,("auth_context_create: failed to find method=%s\n",
243 return NT_STATUS_INTERNAL_ERROR;
245 method->auth_ctx = ctx;
247 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
251 return NT_STATUS_INTERNAL_ERROR;
259 /* the list of currently registered AUTH backends */
260 static struct auth_backend {
261 const struct auth_operations *ops;
263 static int num_backends;
266 register a AUTH backend.
268 The 'name' can be later used by other backends to find the operations
269 structure for this backend.
271 NTSTATUS auth_register(const void *_ops)
273 const struct auth_operations *ops = _ops;
274 struct auth_operations *new_ops;
276 if (auth_backend_byname(ops->name) != NULL) {
277 /* its already registered! */
278 DEBUG(0,("AUTH backend '%s' already registered\n",
280 return NT_STATUS_OBJECT_NAME_COLLISION;
283 backends = realloc_p(backends, struct auth_backend, num_backends+1);
285 smb_panic("out of memory in auth_register");
288 new_ops = smb_xmemdup(ops, sizeof(*ops));
289 new_ops->name = smb_xstrdup(ops->name);
291 backends[num_backends].ops = new_ops;
295 DEBUG(3,("AUTH backend '%s' registered\n",
302 return the operations structure for a named backend of the specified type
304 const struct auth_operations *auth_backend_byname(const char *name)
308 for (i=0;i<num_backends;i++) {
309 if (strcmp(backends[i].ops->name, name) == 0) {
310 return backends[i].ops;
318 return the AUTH interface version, and the size of some critical types
319 This can be used by backends to either detect compilation errors, or provide
320 multiple implementations for different smbd compilation options in one module
322 const struct auth_critical_sizes *auth_interface_version(void)
324 static const struct auth_critical_sizes critical_sizes = {
325 AUTH_INTERFACE_VERSION,
326 sizeof(struct auth_operations),
327 sizeof(struct auth_method_context),
328 sizeof(struct auth_context),
329 sizeof(struct auth_usersupplied_info),
330 sizeof(struct auth_serversupplied_info)
333 return &critical_sizes;
336 NTSTATUS server_service_auth_init(void)
338 init_module_fn static_init[] = STATIC_AUTH_MODULES;
339 init_module_fn *shared_init = load_samba_modules(NULL, "auth");
341 run_init_functions(static_init);
342 run_init_functions(shared_init);
344 talloc_free(shared_init);