r1294: A nice, large, commit...
[kai/samba.git] / source4 / libcli / auth / gensec_ntlmssp.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc authentication operations
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 struct gensec_ntlmssp_state {
27         TALLOC_CTX *mem_ctx;
28         struct auth_context *auth_context;
29         struct auth_serversupplied_info *server_info;
30         struct ntlmssp_state *ntlmssp_state;
31 };
32
33
34 /**
35  * Return the challenge as determined by the authentication subsystem 
36  * @return an 8 byte random challenge
37  */
38
39 static const uint8_t *auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state)
40 {
41         struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
42
43         return gensec_ntlmssp_state->auth_context->get_ntlm_challenge(gensec_ntlmssp_state->auth_context);
44 }
45
46 /**
47  * Some authentication methods 'fix' the challenge, so we may not be able to set it
48  *
49  * @return If the effective challenge used by the auth subsystem may be modified
50  */
51 static BOOL auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
52 {
53         struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
54
55         return gensec_ntlmssp_state->auth_context->challenge_may_be_modified;
56 }
57
58 /**
59  * NTLM2 authentication modifies the effective challenge, 
60  * @param challenge The new challenge value
61  */
62 static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
63 {
64         struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
65         struct auth_context *auth_context = gensec_ntlmssp_state->auth_context;
66
67         SMB_ASSERT(challenge->length == 8);
68
69         auth_context->challenge = data_blob_talloc(auth_context->mem_ctx, 
70                                                    challenge->data, challenge->length);
71
72         auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)";
73
74         DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by));
75         DEBUG(5, ("challenge is: \n"));
76         dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
77         return NT_STATUS_OK;
78 }
79
80 /**
81  * Check the password on an NTLMSSP login.  
82  *
83  * Return the session keys used on the connection.
84  */
85
86 static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key) 
87 {
88         struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
89         struct auth_usersupplied_info *user_info = NULL;
90         NTSTATUS nt_status;
91
92 #if 0
93         /* the client has given us its machine name (which we otherwise would not get on port 445).
94            we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
95
96         set_remote_machine_name(gensec_ntlmssp_state->ntlmssp_state->workstation, True);
97
98         /* setup the string used by %U */
99         /* sub_set_smb_name checks for weird internally */
100         sub_set_smb_name(gensec_ntlmssp_state->ntlmssp_state->user);
101
102         reload_services(True);
103
104 #endif
105         nt_status = make_user_info_map(&user_info, 
106                                        gensec_ntlmssp_state->ntlmssp_state->user, 
107                                        gensec_ntlmssp_state->ntlmssp_state->domain, 
108                                        gensec_ntlmssp_state->ntlmssp_state->workstation, 
109                                        gensec_ntlmssp_state->ntlmssp_state->lm_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->lm_resp : NULL, 
110                                        gensec_ntlmssp_state->ntlmssp_state->nt_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->nt_resp : NULL, 
111                                        NULL, NULL, NULL,
112                                        True);
113
114         if (!NT_STATUS_IS_OK(nt_status)) {
115                 return nt_status;
116         }
117
118         nt_status = gensec_ntlmssp_state->auth_context->check_ntlm_password(gensec_ntlmssp_state->auth_context, 
119                                                                           user_info, &gensec_ntlmssp_state->server_info); 
120
121         free_user_info(&user_info);
122
123         if (!NT_STATUS_IS_OK(nt_status)) {
124                 return nt_status;
125         }
126         if (gensec_ntlmssp_state->server_info->user_session_key.length) {
127                 DEBUG(10, ("Got NT session key of length %u\n", gensec_ntlmssp_state->server_info->user_session_key.length));
128                 *user_session_key = data_blob_talloc(ntlmssp_state->mem_ctx, 
129                                                    gensec_ntlmssp_state->server_info->user_session_key.data,
130                                                    gensec_ntlmssp_state->server_info->user_session_key.length);
131         }
132         if (gensec_ntlmssp_state->server_info->lm_session_key.length) {
133                 DEBUG(10, ("Got LM session key of length %u\n", gensec_ntlmssp_state->server_info->lm_session_key.length));
134                 *lm_session_key = data_blob_talloc(ntlmssp_state->mem_ctx, 
135                                                    gensec_ntlmssp_state->server_info->lm_session_key.data,
136                                                    gensec_ntlmssp_state->server_info->lm_session_key.length);
137         }
138         return nt_status;
139 }
140
141 static NTSTATUS gensec_ntlmssp_start(struct gensec_security *gensec_security)
142 {
143         struct gensec_ntlmssp_state *gensec_ntlmssp_state;
144         
145         TALLOC_CTX *mem_ctx = talloc_init("gensec_ntlmssp");
146         if (!mem_ctx) {
147                 return NT_STATUS_NO_MEMORY;
148         }
149
150         gensec_ntlmssp_state = talloc_p(mem_ctx, struct gensec_ntlmssp_state);
151         if (!gensec_ntlmssp_state) {
152                 return NT_STATUS_NO_MEMORY;
153         }
154
155         gensec_ntlmssp_state->mem_ctx = mem_ctx;
156         gensec_ntlmssp_state->ntlmssp_state = NULL;
157         gensec_ntlmssp_state->auth_context = NULL;
158         gensec_ntlmssp_state->server_info = NULL;
159
160         gensec_security->private_data = gensec_ntlmssp_state;
161         return NT_STATUS_OK;
162 }
163
164 static NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
165 {
166         NTSTATUS nt_status;
167         NTSTATUS status;
168         struct ntlmssp_state *ntlmssp_state;
169         struct gensec_ntlmssp_state *gensec_ntlmssp_state;
170
171         status = gensec_ntlmssp_start(gensec_security);
172         if (!NT_STATUS_IS_OK(status)) {
173                 return status;
174         }
175
176         gensec_ntlmssp_state = gensec_security->private_data;
177
178         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_start(&gensec_ntlmssp_state->ntlmssp_state))) {
179                 return nt_status;
180         }
181
182         ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state;
183         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&gensec_ntlmssp_state->auth_context))) {
184                 return nt_status;
185         }
186
187         ntlmssp_state->auth_context = gensec_ntlmssp_state;
188         ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
189         ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
190         ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
191         ntlmssp_state->check_password = auth_ntlmssp_check_password;
192         ntlmssp_state->server_role = lp_server_role();
193         
194         return NT_STATUS_OK;
195 }
196
197 static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
198 {
199         struct gensec_ntlmssp_state *gensec_ntlmssp_state;
200         char *password = NULL;
201         
202         NTSTATUS status;
203         status = gensec_ntlmssp_start(gensec_security);
204         if (!NT_STATUS_IS_OK(status)) {
205                 return status;
206         }
207
208         gensec_ntlmssp_state = gensec_security->private_data;
209         status = ntlmssp_client_start(&gensec_ntlmssp_state->ntlmssp_state);
210         if (!NT_STATUS_IS_OK(status)) {
211                 return status;
212         }
213
214         status = ntlmssp_set_domain(gensec_ntlmssp_state->ntlmssp_state, 
215                                     gensec_security->user.domain);
216         if (!NT_STATUS_IS_OK(status)) {
217                 return status;
218         }
219         
220         status = ntlmssp_set_username(gensec_ntlmssp_state->ntlmssp_state, 
221                                       gensec_security->user.name);
222         if (!NT_STATUS_IS_OK(status)) {
223                 return status;
224         }
225
226         status = gensec_get_password(gensec_security, gensec_ntlmssp_state->mem_ctx, &password);
227         if (!NT_STATUS_IS_OK(status)) {
228                 return status;
229         }
230
231         if (password) {
232                 status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state, 
233                                               password);
234                 if (!NT_STATUS_IS_OK(status)) {
235                         return status;
236                 }
237         }
238
239         gensec_security->private_data = gensec_ntlmssp_state;
240
241         return status;
242 }
243
244 /*
245   wrappers for the ntlmssp_*() functions
246 */
247 static NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security, 
248                                       TALLOC_CTX *mem_ctx, 
249                                       uint8_t *data, size_t length, DATA_BLOB *sig)
250 {
251         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
252
253         return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
254 }
255
256 static NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security, 
257                                      TALLOC_CTX *mem_ctx, 
258                                      const uint8_t *data, size_t length, 
259                                      const DATA_BLOB *sig)
260 {
261         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
262
263         return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
264 }
265
266 static NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security, 
267                                     TALLOC_CTX *mem_ctx, 
268                                     uint8_t *data, size_t length, 
269                                     DATA_BLOB *sig)
270 {
271         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
272
273         return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
274 }
275
276 static NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security, 
277                                     TALLOC_CTX *mem_ctx, 
278                                     const uint8_t *data, size_t length, 
279                                     DATA_BLOB *sig)
280 {
281         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
282
283         return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
284 }
285
286 static NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security, 
287                                     DATA_BLOB *session_key)
288 {
289         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
290
291         return ntlmssp_session_key(gensec_ntlmssp_state->ntlmssp_state, session_key);
292 }
293
294 /**
295  * Next state function for the wrapped NTLMSSP state machine
296  * 
297  * @param gensec_ntlmssp_state NTLMSSP State
298  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
299  * @param in The request, as a DATA_BLOB
300  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
301  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
302  *                or NT_STATUS_OK if the user is authenticated. 
303  */
304
305 static NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx, 
306                                const DATA_BLOB in, DATA_BLOB *out) 
307 {
308         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
309
310         return ntlmssp_update(gensec_ntlmssp_state->ntlmssp_state, out_mem_ctx, in, out);
311 }
312
313 /** 
314  * Return the credentials of a logged on user, including session keys
315  * etc.
316  *
317  * Only valid after a successful authentication
318  *
319  * May only be called once per authentication.
320  *
321  */
322
323 static NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security,
324                                      struct auth_session_info **session_info) 
325 {
326         NTSTATUS nt_status;
327         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
328         nt_status = make_session_info(gensec_ntlmssp_state->server_info, session_info);
329
330         if (!NT_STATUS_IS_OK(nt_status)) {
331                 return nt_status;
332         }
333
334         /* the session_info owns this now */
335         gensec_ntlmssp_state->server_info = NULL;
336
337         (*session_info)->session_key = data_blob_talloc((*session_info)->mem_ctx, 
338                                                         gensec_ntlmssp_state->ntlmssp_state->session_key.data,
339                                                         gensec_ntlmssp_state->ntlmssp_state->session_key.length);
340
341         (*session_info)->workstation = talloc_strdup((*session_info)->mem_ctx, 
342                                                      gensec_ntlmssp_state->ntlmssp_state->workstation);
343
344         return NT_STATUS_OK;
345 }
346
347 static void gensec_ntlmssp_end(struct gensec_security *gensec_security)
348 {
349         struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
350
351         if (gensec_ntlmssp_state->ntlmssp_state) {
352                 ntlmssp_end(&gensec_ntlmssp_state->ntlmssp_state);
353         }
354
355         if (gensec_ntlmssp_state->auth_context) {
356                 free_auth_context(&gensec_ntlmssp_state->auth_context);
357         }
358         if (gensec_ntlmssp_state->server_info) {
359                 free_server_info(&gensec_ntlmssp_state->server_info);
360         }
361         talloc_destroy(gensec_ntlmssp_state->mem_ctx);
362         gensec_security->private_data = NULL;
363 }
364
365 static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
366         .name           = "ntlmssp",
367         .sasl_name      = "NTLM",
368         .auth_type      = DCERPC_AUTH_TYPE_NTLMSSP,
369         .oid            = OID_NTLMSSP,
370         .client_start   = gensec_ntlmssp_client_start,
371         .server_start   = gensec_ntlmssp_server_start,
372         .update         = gensec_ntlmssp_update,
373         .seal_packet    = gensec_ntlmssp_seal_packet,
374         .sign_packet    = gensec_ntlmssp_sign_packet,
375         .check_packet   = gensec_ntlmssp_check_packet,
376         .unseal_packet  = gensec_ntlmssp_unseal_packet,
377         .session_key    = gensec_ntlmssp_session_key,
378         .session_info   = gensec_ntlmssp_session_info,
379         .end            = gensec_ntlmssp_end
380 };
381
382
383 NTSTATUS gensec_ntlmssp_init(void)
384 {
385         NTSTATUS ret;
386         ret = register_backend("gensec", &gensec_ntlmssp_security_ops);
387         if (!NT_STATUS_IS_OK(ret)) {
388                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
389                         gensec_ntlmssp_security_ops.name));
390                 return ret;
391         }
392
393         /* ugly cludge, but we need the auth subsystem for this to work */
394         auth_init();
395
396         return ret;
397 }