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"
26 /***************************************************************************
28 ***************************************************************************/
29 NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by)
31 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
32 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
34 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
35 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
40 /***************************************************************************
42 ***************************************************************************/
43 BOOL auth_challenge_may_be_modified(struct auth_context *auth_ctx)
45 return auth_ctx->challenge.may_be_modified;
48 /****************************************************************************
49 Try to get a challenge out of the various authentication modules.
50 Returns a const char of length 8 bytes.
51 ****************************************************************************/
52 NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
55 struct auth_method_context *method;
57 if (auth_ctx->challenge.data.length) {
58 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
59 auth_ctx->challenge.set_by));
60 *_chal = auth_ctx->challenge.data.data;
64 for (method = auth_ctx->methods; method; method = method->next) {
65 DATA_BLOB challenge = data_blob(NULL,0);
67 nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
68 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
72 NT_STATUS_NOT_OK_RETURN(nt_status);
74 if (challenge.length != 8) {
75 DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n",
76 challenge.length, method->ops->name));
77 return NT_STATUS_INTERNAL_ERROR;
80 auth_ctx->challenge.data = challenge;
81 auth_ctx->challenge.set_by = method->ops->name;
86 if (!auth_ctx->challenge.set_by) {
88 generate_random_buffer(chal, 8);
90 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
91 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
92 auth_ctx->challenge.set_by = "random";
94 auth_ctx->challenge.may_be_modified = True;
97 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
98 auth_ctx->challenge.set_by));
100 *_chal = auth_ctx->challenge.data.data;
105 * Check a user's Plaintext, LM or NTLM password.
107 * Check a user's password, as given in the user_info struct and return various
108 * interesting details in the server_info struct.
110 * The return value takes precedence over the contents of the server_info
111 * struct. When the return is other than NT_STATUS_OK the contents
112 * of that structure is undefined.
114 * @param user_info Contains the user supplied components, including the passwords.
115 * Must be created with make_user_info() or one of its wrappers.
117 * @param auth_context Supplies the challenges and some other data.
118 * Must be created with make_auth_context(), and the challenges should be
119 * filled in, either at creation or by calling the challenge geneation
120 * function auth_get_challenge().
122 * @param server_info If successful, contains information about the authentication,
123 * including a SAM_ACCOUNT struct describing the user.
125 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
129 NTSTATUS auth_check_password(struct auth_context *auth_ctx,
131 const struct auth_usersupplied_info *user_info,
132 struct auth_serversupplied_info **server_info)
134 /* if all the modules say 'not for me' this is reasonable */
135 NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
136 struct auth_method_context *method;
137 const char *method_name = "NO METHOD";
138 const uint8_t *challenge;
140 DEBUG(3, ("auth_check_password: Checking password for unmapped user [%s]\\[%s]@[%s]\n",
141 user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
143 DEBUGADD(3,("auth_check_password: mapped user is: [%s]\\[%s]@[%s]\n",
144 user_info->domain_name, user_info->account_name, user_info->workstation_name));
146 nt_status = auth_get_challenge(auth_ctx, &challenge);
148 if (!NT_STATUS_IS_OK(nt_status)) {
149 DEBUG(0, ("auth_check_password: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
150 auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
154 if (auth_ctx->challenge.set_by) {
155 DEBUG(10, ("auth_check_password: auth_context challenge created by %s\n",
156 auth_ctx->challenge.set_by));
159 DEBUG(10, ("challenge is: \n"));
160 dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
162 #ifdef DEBUG_PASSWORD
163 DEBUG(100, ("user_info has passwords of length %d and %d\n",
164 user_info->lm_resp.length, user_info->nt_resp.length));
165 DEBUG(100, ("lm:\n"));
166 dump_data(100, user_info->lm_resp.data, user_info->lm_resp.length);
167 DEBUG(100, ("nt:\n"));
168 dump_data(100, user_info->nt_resp.data, user_info->nt_resp.length);
171 for (method = auth_ctx->methods; method; method = method->next) {
174 result = method->ops->check_password(method, mem_ctx, user_info, server_info);
176 /* check if the module did anything */
177 if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
178 method_name = method->ops->name;
183 DEBUG(11,("auth_check_password: %s had nothing to say\n", method->ops->name));
186 if (!NT_STATUS_IS_OK(nt_status)) {
187 DEBUG(2,("auth_check_password: %s authentication for user [%s\\%s] FAILED with error %s\n",
188 method_name, user_info->domain_name, user_info->account_name,
189 nt_errstr(nt_status)));
193 DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n",
194 method_name, (*server_info)->domain_name, (*server_info)->account_name));
199 /***************************************************************************
200 Make a auth_info struct for the auth subsystem
201 ***************************************************************************/
202 NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods, struct auth_context **auth_ctx)
205 struct auth_context *ctx;
208 DEBUG(0,("auth_context_create: No auth method list!?\n"));
209 return NT_STATUS_INTERNAL_ERROR;
212 ctx = talloc(mem_ctx, struct auth_context);
213 NT_STATUS_HAVE_NO_MEMORY(ctx);
214 ctx->challenge.set_by = NULL;
215 ctx->challenge.may_be_modified = False;
216 ctx->challenge.data = data_blob(NULL, 0);
219 for (i=0; methods[i] ; i++) {
220 struct auth_method_context *method;
222 method = talloc(ctx, struct auth_method_context);
223 NT_STATUS_HAVE_NO_MEMORY(method);
225 method->ops = auth_backend_byname(methods[i]);
227 DEBUG(1,("auth_context_create: failed to find method=%s\n",
229 return NT_STATUS_INTERNAL_ERROR;
231 method->auth_ctx = ctx;
233 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
237 return NT_STATUS_INTERNAL_ERROR;
245 /* the list of currently registered AUTH backends */
246 static struct auth_backend {
247 const struct auth_operations *ops;
249 static int num_backends;
252 register a AUTH backend.
254 The 'name' can be later used by other backends to find the operations
255 structure for this backend.
257 NTSTATUS auth_register(const void *_ops)
259 const struct auth_operations *ops = _ops;
260 struct auth_operations *new_ops;
262 if (auth_backend_byname(ops->name) != NULL) {
263 /* its already registered! */
264 DEBUG(0,("AUTH backend '%s' already registered\n",
266 return NT_STATUS_OBJECT_NAME_COLLISION;
269 backends = realloc_p(backends, struct auth_backend, num_backends+1);
271 smb_panic("out of memory in auth_register");
274 new_ops = smb_xmemdup(ops, sizeof(*ops));
275 new_ops->name = smb_xstrdup(ops->name);
277 backends[num_backends].ops = new_ops;
281 DEBUG(3,("AUTH backend '%s' registered\n",
288 return the operations structure for a named backend of the specified type
290 const struct auth_operations *auth_backend_byname(const char *name)
294 for (i=0;i<num_backends;i++) {
295 if (strcmp(backends[i].ops->name, name) == 0) {
296 return backends[i].ops;
304 return the AUTH interface version, and the size of some critical types
305 This can be used by backends to either detect compilation errors, or provide
306 multiple implementations for different smbd compilation options in one module
308 const struct auth_critical_sizes *auth_interface_version(void)
310 static const struct auth_critical_sizes critical_sizes = {
311 AUTH_INTERFACE_VERSION,
312 sizeof(struct auth_operations),
313 sizeof(struct auth_method_context),
314 sizeof(struct auth_context),
315 sizeof(struct auth_usersupplied_info),
316 sizeof(struct auth_serversupplied_info)
319 return &critical_sizes;
322 NTSTATUS server_service_auth_init(void)