r6765: expanded the cldap test suite to test the usage of the DomainGuid,
[samba.git] / source / auth / auth.c
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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "dlinklist.h"
24 #include "auth/auth.h"
25
26 /***************************************************************************
27  Set a fixed challenge
28 ***************************************************************************/
29 NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) 
30 {
31         auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
32         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
33
34         auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
35         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
36
37         return NT_STATUS_OK;
38 }
39
40 /***************************************************************************
41  Set a fixed challenge
42 ***************************************************************************/
43 BOOL auth_challenge_may_be_modified(struct auth_context *auth_ctx) 
44 {
45         return auth_ctx->challenge.may_be_modified;
46 }
47
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)
53 {
54         NTSTATUS nt_status;
55         struct auth_method_context *method;
56
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;
61                 return NT_STATUS_OK;
62         }
63
64         for (method = auth_ctx->methods; method; method = method->next) {
65                 DATA_BLOB challenge = data_blob(NULL,0);
66
67                 nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
68                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
69                         continue;
70                 }
71
72                 NT_STATUS_NOT_OK_RETURN(nt_status);
73
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;
78                 }
79
80                 auth_ctx->challenge.data        = challenge;
81                 auth_ctx->challenge.set_by      = method->ops->name;
82
83                 break;
84         }
85
86         if (!auth_ctx->challenge.set_by) {
87                 uint8_t chal[8];
88                 generate_random_buffer(chal, 8);
89
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";
93
94                 auth_ctx->challenge.may_be_modified     = True;
95         }
96
97         DEBUG(10,("auth_get_challenge: challenge set by %s\n",
98                  auth_ctx->challenge.set_by));
99
100         *_chal = auth_ctx->challenge.data.data;
101         return NT_STATUS_OK;
102 }
103
104 /**
105  * Check a user's Plaintext, LM or NTLM password.
106  *
107  * Check a user's password, as given in the user_info struct and return various
108  * interesting details in the server_info struct.
109  *
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.
113  *
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.
116  *
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().  
121  *
122  * @param server_info If successful, contains information about the authentication, 
123  *                    including a SAM_ACCOUNT struct describing the user.
124  *
125  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
126  *
127  **/
128
129 NTSTATUS auth_check_password(struct auth_context *auth_ctx,
130                              TALLOC_CTX *mem_ctx,
131                              const struct auth_usersupplied_info *user_info, 
132                              struct auth_serversupplied_info **server_info)
133 {
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;
139
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));
142
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));
145
146         nt_status = auth_get_challenge(auth_ctx, &challenge);
147
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)));
151                 return nt_status;
152         }
153
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));
157         }
158
159         DEBUG(10, ("challenge is: \n"));
160         dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
161
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);
169 #endif
170
171         for (method = auth_ctx->methods; method; method = method->next) {
172                 NTSTATUS result;
173
174                 result = method->ops->check_password(method, mem_ctx, user_info, server_info);
175
176                 /* check if the module did anything */
177                 if (!NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
178                         method_name = method->ops->name;
179                         nt_status = result;
180                         break;
181                 }
182
183                 DEBUG(11,("auth_check_password: %s had nothing to say\n", method->ops->name));
184         }
185
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)));
190                 return nt_status;
191         }
192
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));
195
196         return nt_status;
197 }
198
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) 
203 {
204         int i;
205         struct auth_context *ctx;
206
207         if (!methods) {
208                 DEBUG(0,("auth_context_create: No auth method list!?\n"));
209                 return NT_STATUS_INTERNAL_ERROR;
210         }
211
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);
217         ctx->methods                    = NULL;
218
219         for (i=0; methods[i] ; i++) {
220                 struct auth_method_context *method;
221
222                 method = talloc(ctx, struct auth_method_context);
223                 NT_STATUS_HAVE_NO_MEMORY(method);
224
225                 method->ops = auth_backend_byname(methods[i]);
226                 if (!method->ops) {
227                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
228                                 methods[i]));
229                         return NT_STATUS_INTERNAL_ERROR;
230                 }
231                 method->auth_ctx        = ctx;
232                 method->depth           = i;
233                 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
234         }
235
236         if (!ctx->methods) {
237                 return NT_STATUS_INTERNAL_ERROR;
238         }
239
240         *auth_ctx = ctx;
241
242         return NT_STATUS_OK;
243 }
244
245 /* the list of currently registered AUTH backends */
246 static struct auth_backend {
247         const struct auth_operations *ops;
248 } *backends = NULL;
249 static int num_backends;
250
251 /*
252   register a AUTH backend. 
253
254   The 'name' can be later used by other backends to find the operations
255   structure for this backend.
256 */
257 NTSTATUS auth_register(const void *_ops)
258 {
259         const struct auth_operations *ops = _ops;
260         struct auth_operations *new_ops;
261         
262         if (auth_backend_byname(ops->name) != NULL) {
263                 /* its already registered! */
264                 DEBUG(0,("AUTH backend '%s' already registered\n", 
265                          ops->name));
266                 return NT_STATUS_OBJECT_NAME_COLLISION;
267         }
268
269         backends = realloc_p(backends, struct auth_backend, num_backends+1);
270         if (!backends) {
271                 smb_panic("out of memory in auth_register");
272         }
273
274         new_ops = smb_xmemdup(ops, sizeof(*ops));
275         new_ops->name = smb_xstrdup(ops->name);
276
277         backends[num_backends].ops = new_ops;
278
279         num_backends++;
280
281         DEBUG(3,("AUTH backend '%s' registered\n", 
282                  ops->name));
283
284         return NT_STATUS_OK;
285 }
286
287 /*
288   return the operations structure for a named backend of the specified type
289 */
290 const struct auth_operations *auth_backend_byname(const char *name)
291 {
292         int i;
293
294         for (i=0;i<num_backends;i++) {
295                 if (strcmp(backends[i].ops->name, name) == 0) {
296                         return backends[i].ops;
297                 }
298         }
299
300         return NULL;
301 }
302
303 /*
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
307 */
308 const struct auth_critical_sizes *auth_interface_version(void)
309 {
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)
317         };
318
319         return &critical_sizes;
320 }
321
322 NTSTATUS server_service_auth_init(void)
323 {
324         return NT_STATUS_OK;    
325 }