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 "lib/ldb/include/ldb.h"
25 #include "auth/auth.h"
26 #include "lib/events/events.h"
29 /***************************************************************************
31 ***************************************************************************/
32 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 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;
108 * Check a user's Plaintext, LM or NTLM password.
110 * Check a user's password, as given in the user_info struct and return various
111 * interesting details in the server_info struct.
113 * The return value takes precedence over the contents of the server_info
114 * struct. When the return is other than NT_STATUS_OK the contents
115 * of that structure is undefined.
117 * @param user_info Contains the user supplied components, including the passwords.
119 * @param auth_context Supplies the challenges and some other data.
120 * Must be created with make_auth_context(), and the challenges should be
121 * filled in, either at creation or by calling the challenge geneation
122 * function auth_get_challenge().
124 * @param server_info If successful, contains information about the authentication,
125 * including a SAM_ACCOUNT struct describing the user.
127 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
131 NTSTATUS auth_check_password(struct auth_context *auth_ctx,
133 const struct auth_usersupplied_info *user_info,
134 struct auth_serversupplied_info **server_info)
136 /* if all the modules say 'not for me' this is reasonable */
138 struct auth_method_context *method;
139 const char *method_name = "NO METHOD";
140 const uint8_t *challenge;
141 struct auth_usersupplied_info *user_info_tmp;
143 DEBUG(3, ("auth_check_password: Checking password for unmapped user [%s]\\[%s]@[%s]\n",
144 user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
146 if (!user_info->mapped_state) {
147 nt_status = map_user_info(mem_ctx, user_info, &user_info_tmp);
148 if (!NT_STATUS_IS_OK(nt_status)) {
151 user_info = user_info_tmp;
154 DEBUGADD(3,("auth_check_password: mapped user is: [%s]\\[%s]@[%s]\n",
155 user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
157 nt_status = auth_get_challenge(auth_ctx, &challenge);
159 if (!NT_STATUS_IS_OK(nt_status)) {
160 DEBUG(0, ("auth_check_password: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
161 (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
165 if (auth_ctx->challenge.set_by) {
166 DEBUG(10, ("auth_check_password: auth_context challenge created by %s\n",
167 auth_ctx->challenge.set_by));
170 DEBUG(10, ("challenge is: \n"));
171 dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
173 nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
174 for (method = auth_ctx->methods; method; method = method->next) {
177 /* check if the module wants to chek the password */
178 result = method->ops->want_check(method, mem_ctx, user_info);
179 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
180 DEBUG(11,("auth_check_password: %s had nothing to say\n", method->ops->name));
184 method_name = method->ops->name;
187 if (!NT_STATUS_IS_OK(nt_status)) break;
189 nt_status = method->ops->check_password(method, mem_ctx, user_info, server_info);
193 if (!NT_STATUS_IS_OK(nt_status)) {
194 DEBUG(2,("auth_check_password: %s authentication for user [%s\\%s] FAILED with error %s\n",
195 method_name, user_info->mapped.domain_name, user_info->mapped.account_name,
196 nt_errstr(nt_status)));
200 DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n",
201 method_name, (*server_info)->domain_name, (*server_info)->account_name));
206 /***************************************************************************
207 Make a auth_info struct for the auth subsystem
208 ***************************************************************************/
209 NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods,
210 struct auth_context **auth_ctx,
211 struct event_context *ev)
214 struct auth_context *ctx;
217 DEBUG(0,("auth_context_create: No auth method list!?\n"));
218 return NT_STATUS_INTERNAL_ERROR;
221 ctx = talloc(mem_ctx, struct auth_context);
222 NT_STATUS_HAVE_NO_MEMORY(ctx);
223 ctx->challenge.set_by = NULL;
224 ctx->challenge.may_be_modified = False;
225 ctx->challenge.data = data_blob(NULL, 0);
229 ev = event_context_init(ctx);
232 return NT_STATUS_NO_MEMORY;
238 for (i=0; methods[i] ; i++) {
239 struct auth_method_context *method;
241 method = talloc(ctx, struct auth_method_context);
242 NT_STATUS_HAVE_NO_MEMORY(method);
244 method->ops = auth_backend_byname(methods[i]);
246 DEBUG(1,("auth_context_create: failed to find method=%s\n",
248 return NT_STATUS_INTERNAL_ERROR;
250 method->auth_ctx = ctx;
252 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
256 return NT_STATUS_INTERNAL_ERROR;
264 /* the list of currently registered AUTH backends */
265 static struct auth_backend {
266 const struct auth_operations *ops;
268 static int num_backends;
271 register a AUTH backend.
273 The 'name' can be later used by other backends to find the operations
274 structure for this backend.
276 NTSTATUS auth_register(const void *_ops)
278 const struct auth_operations *ops = _ops;
279 struct auth_operations *new_ops;
281 if (auth_backend_byname(ops->name) != NULL) {
282 /* its already registered! */
283 DEBUG(0,("AUTH backend '%s' already registered\n",
285 return NT_STATUS_OBJECT_NAME_COLLISION;
288 backends = realloc_p(backends, struct auth_backend, num_backends+1);
290 return NT_STATUS_NO_MEMORY;
293 new_ops = smb_xmemdup(ops, sizeof(*ops));
294 new_ops->name = smb_xstrdup(ops->name);
296 backends[num_backends].ops = new_ops;
300 DEBUG(3,("AUTH backend '%s' registered\n",
307 return the operations structure for a named backend of the specified type
309 const struct auth_operations *auth_backend_byname(const char *name)
313 for (i=0;i<num_backends;i++) {
314 if (strcmp(backends[i].ops->name, name) == 0) {
315 return backends[i].ops;
323 return the AUTH interface version, and the size of some critical types
324 This can be used by backends to either detect compilation errors, or provide
325 multiple implementations for different smbd compilation options in one module
327 const struct auth_critical_sizes *auth_interface_version(void)
329 static const struct auth_critical_sizes critical_sizes = {
330 AUTH_INTERFACE_VERSION,
331 sizeof(struct auth_operations),
332 sizeof(struct auth_method_context),
333 sizeof(struct auth_context),
334 sizeof(struct auth_usersupplied_info),
335 sizeof(struct auth_serversupplied_info)
338 return &critical_sizes;
341 NTSTATUS auth_init(void)
343 static BOOL initialized = False;
345 init_module_fn static_init[] = STATIC_auth_MODULES;
346 init_module_fn *shared_init;
348 if (initialized) return NT_STATUS_OK;
351 shared_init = load_samba_modules(NULL, "auth");
353 run_init_functions(static_init);
354 run_init_functions(shared_init);
356 talloc_free(shared_init);
361 NTSTATUS server_service_auth_init(void)