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"
27 /***************************************************************************
29 ***************************************************************************/
30 NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by)
32 auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
33 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
35 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
36 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
41 /***************************************************************************
43 ***************************************************************************/
44 BOOL auth_challenge_may_be_modified(struct auth_context *auth_ctx)
46 return auth_ctx->challenge.may_be_modified;
49 /****************************************************************************
50 Try to get a challenge out of the various authentication modules.
51 Returns a const char of length 8 bytes.
52 ****************************************************************************/
53 NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
56 struct auth_method_context *method;
58 if (auth_ctx->challenge.data.length) {
59 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n",
60 auth_ctx->challenge.set_by));
61 *_chal = auth_ctx->challenge.data.data;
65 for (method = auth_ctx->methods; method; method = method->next) {
66 DATA_BLOB challenge = data_blob(NULL,0);
68 nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
69 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
73 NT_STATUS_NOT_OK_RETURN(nt_status);
75 if (challenge.length != 8) {
76 DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n",
77 (unsigned)challenge.length, method->ops->name));
78 return NT_STATUS_INTERNAL_ERROR;
81 auth_ctx->challenge.data = challenge;
82 auth_ctx->challenge.set_by = method->ops->name;
87 if (!auth_ctx->challenge.set_by) {
89 generate_random_buffer(chal, 8);
91 auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
92 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
93 auth_ctx->challenge.set_by = "random";
95 auth_ctx->challenge.may_be_modified = True;
98 DEBUG(10,("auth_get_challenge: challenge set by %s\n",
99 auth_ctx->challenge.set_by));
101 *_chal = auth_ctx->challenge.data.data;
106 * Check a user's Plaintext, LM or NTLM password.
108 * Check a user's password, as given in the user_info struct and return various
109 * interesting details in the server_info struct.
111 * The return value takes precedence over the contents of the server_info
112 * struct. When the return is other than NT_STATUS_OK the contents
113 * of that structure is undefined.
115 * @param user_info Contains the user supplied components, including the passwords.
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 */
136 struct auth_method_context *method;
137 const char *method_name = "NO METHOD";
138 const uint8_t *challenge;
139 struct auth_usersupplied_info *user_info_tmp;
141 DEBUG(3, ("auth_check_password: Checking password for unmapped user [%s]\\[%s]@[%s]\n",
142 user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
144 if (!user_info->mapped_state) {
145 nt_status = map_user_info(mem_ctx, user_info, &user_info_tmp);
146 if (!NT_STATUS_IS_OK(nt_status)) {
149 user_info = user_info_tmp;
152 DEBUGADD(3,("auth_check_password: mapped user is: [%s]\\[%s]@[%s]\n",
153 user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
155 nt_status = auth_get_challenge(auth_ctx, &challenge);
157 if (!NT_STATUS_IS_OK(nt_status)) {
158 DEBUG(0, ("auth_check_password: Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
159 (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
163 if (auth_ctx->challenge.set_by) {
164 DEBUG(10, ("auth_check_password: auth_context challenge created by %s\n",
165 auth_ctx->challenge.set_by));
168 DEBUG(10, ("challenge is: \n"));
169 dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
171 nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
172 for (method = auth_ctx->methods; method; method = method->next) {
175 result = method->ops->check_password(method, mem_ctx, user_info, server_info);
177 /* check if the module did anything */
178 if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
179 method_name = method->ops->name;
184 DEBUG(11,("auth_check_password: %s had nothing to say\n", method->ops->name));
187 if (!NT_STATUS_IS_OK(nt_status)) {
188 DEBUG(2,("auth_check_password: %s authentication for user [%s\\%s] FAILED with error %s\n",
189 method_name, user_info->mapped.domain_name, user_info->mapped.account_name,
190 nt_errstr(nt_status)));
194 DEBUG(5,("auth_check_password: %s authentication for user [%s\\%s] succeeded\n",
195 method_name, (*server_info)->domain_name, (*server_info)->account_name));
200 /***************************************************************************
201 Make a auth_info struct for the auth subsystem
202 ***************************************************************************/
203 NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, const char **methods,
204 struct auth_context **auth_ctx,
205 struct event_context *ev)
208 struct auth_context *ctx;
211 DEBUG(0,("auth_context_create: No auth method list!?\n"));
212 return NT_STATUS_INTERNAL_ERROR;
215 ctx = talloc(mem_ctx, struct auth_context);
216 NT_STATUS_HAVE_NO_MEMORY(ctx);
217 ctx->challenge.set_by = NULL;
218 ctx->challenge.may_be_modified = False;
219 ctx->challenge.data = data_blob(NULL, 0);
223 ev = event_context_init(ctx);
226 return NT_STATUS_NO_MEMORY;
232 for (i=0; methods[i] ; i++) {
233 struct auth_method_context *method;
235 method = talloc(ctx, struct auth_method_context);
236 NT_STATUS_HAVE_NO_MEMORY(method);
238 method->ops = auth_backend_byname(methods[i]);
240 DEBUG(1,("auth_context_create: failed to find method=%s\n",
242 return NT_STATUS_INTERNAL_ERROR;
244 method->auth_ctx = ctx;
246 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
250 return NT_STATUS_INTERNAL_ERROR;
258 /* the list of currently registered AUTH backends */
259 static struct auth_backend {
260 const struct auth_operations *ops;
262 static int num_backends;
265 register a AUTH backend.
267 The 'name' can be later used by other backends to find the operations
268 structure for this backend.
270 NTSTATUS auth_register(const void *_ops)
272 const struct auth_operations *ops = _ops;
273 struct auth_operations *new_ops;
275 if (auth_backend_byname(ops->name) != NULL) {
276 /* its already registered! */
277 DEBUG(0,("AUTH backend '%s' already registered\n",
279 return NT_STATUS_OBJECT_NAME_COLLISION;
282 backends = realloc_p(backends, struct auth_backend, num_backends+1);
284 smb_panic("out of memory in auth_register");
287 new_ops = smb_xmemdup(ops, sizeof(*ops));
288 new_ops->name = smb_xstrdup(ops->name);
290 backends[num_backends].ops = new_ops;
294 DEBUG(3,("AUTH backend '%s' registered\n",
301 return the operations structure for a named backend of the specified type
303 const struct auth_operations *auth_backend_byname(const char *name)
307 for (i=0;i<num_backends;i++) {
308 if (strcmp(backends[i].ops->name, name) == 0) {
309 return backends[i].ops;
317 return the AUTH interface version, and the size of some critical types
318 This can be used by backends to either detect compilation errors, or provide
319 multiple implementations for different smbd compilation options in one module
321 const struct auth_critical_sizes *auth_interface_version(void)
323 static const struct auth_critical_sizes critical_sizes = {
324 AUTH_INTERFACE_VERSION,
325 sizeof(struct auth_operations),
326 sizeof(struct auth_method_context),
327 sizeof(struct auth_context),
328 sizeof(struct auth_usersupplied_info),
329 sizeof(struct auth_serversupplied_info)
332 return &critical_sizes;
335 NTSTATUS server_service_auth_init(void)