Updates to our NTLMSSP code:
[abartlet/samba.git/.git] / source3 / auth / auth_ntlmssp.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    handle NLTMSSP, server side
5
6    Copyright (C) Andrew Tridgell      2001
7    Copyright (C) Andrew Bartlett 2001-2003
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 NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
27 {
28         NTSTATUS nt_status;
29         TALLOC_CTX *mem_ctx;
30
31         mem_ctx = talloc_init("NTLMSSP context");
32         
33         *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
34         if (!*ntlmssp_state) {
35                 DEBUG(0,("ntlmssp_start: talloc failed!\n"));
36                 talloc_destroy(mem_ctx);
37                 return NT_STATUS_NO_MEMORY;
38         }
39
40         ZERO_STRUCTP(*ntlmssp_state);
41
42         (*ntlmssp_state)->mem_ctx = mem_ctx;
43
44         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&(*ntlmssp_state)->auth_context))) {
45                 return nt_status;
46         }
47         return NT_STATUS_OK;
48 }
49
50 NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
51 {
52         TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
53         if ((*ntlmssp_state)->auth_context) {
54                 ((*ntlmssp_state)->auth_context->free)(&(*ntlmssp_state)->auth_context);
55         }
56         if ((*ntlmssp_state)->server_info) {
57                 free_server_info(&(*ntlmssp_state)->server_info);
58         }
59
60         talloc_destroy(mem_ctx);
61         return NT_STATUS_OK;
62 }
63
64 NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, 
65                                DATA_BLOB request, DATA_BLOB *reply) 
66 {
67         uint32 ntlmssp_command;
68                 
69         if (!msrpc_parse(&request, "Cd",
70                          "NTLMSSP",
71                          &ntlmssp_command)) {
72                 return NT_STATUS_LOGON_FAILURE;
73         }
74
75         if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
76                 return ntlmssp_negotiate(ntlmssp_state, request, reply);
77         } else if (ntlmssp_command == NTLMSSP_AUTH) {
78                 return ntlmssp_auth(ntlmssp_state, request, reply);
79         } else {
80                 return NT_STATUS_LOGON_FAILURE;
81         }
82 }
83
84 static const char *ntlmssp_target_name(uint32 neg_flags, uint32 *chal_flags) 
85 {
86         if (neg_flags & NTLMSSP_REQUEST_TARGET) {
87                 if (lp_server_role() == ROLE_STANDALONE) {
88                         *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
89                         return global_myname();
90                 } else {
91                         *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
92                         return lp_workgroup();
93                 };
94         } else {
95                 return "";
96         }
97 }
98
99 NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state, 
100                            DATA_BLOB request, DATA_BLOB *reply) 
101 {
102         DATA_BLOB struct_blob;
103         fstring dnsname, dnsdomname;
104         uint32 ntlmssp_command, neg_flags, chal_flags;
105         char *cliname=NULL, *domname=NULL;
106         const uint8 *cryptkey;
107         const char *target_name;
108
109         /* parse the NTLMSSP packet */
110 #if 0
111         file_save("ntlmssp_negotiate.dat", request.data, request.length);
112 #endif
113
114         if (!msrpc_parse(&request, "CddAA",
115                          "NTLMSSP",
116                          &ntlmssp_command,
117                          &neg_flags,
118                          &cliname,
119                          &domname)) {
120                 return NT_STATUS_LOGON_FAILURE;
121         }
122
123         SAFE_FREE(cliname);
124         SAFE_FREE(domname);
125   
126         debug_ntlmssp_flags(neg_flags);
127
128         cryptkey = ntlmssp_state->auth_context->get_ntlm_challenge(ntlmssp_state->auth_context);
129
130         /* Give them the challenge. For now, ignore neg_flags and just
131            return the flags we want. Obviously this is not correct */
132         
133         chal_flags = 
134                 NTLMSSP_NEGOTIATE_128 | 
135                 NTLMSSP_NEGOTIATE_NTLM |
136                 NTLMSSP_CHAL_TARGET_INFO;
137         
138         if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
139                 chal_flags |= NTLMSSP_NEGOTIATE_UNICODE;
140                 ntlmssp_state->unicode = True;
141         } else {
142                 chal_flags |= NTLMSSP_NEGOTIATE_OEM;
143         }
144
145         target_name = ntlmssp_target_name(neg_flags, &chal_flags); 
146
147         dnsdomname[0] = '\0';
148         get_mydomname(dnsdomname);
149         strlower(dnsdomname);
150         
151         dnsname[0] = '\0';
152         get_myfullname(dnsname);
153         strlower(dnsname);
154         
155         /* the numbers here are the string type flags */
156         msrpc_gen(&struct_blob, "aaaaa",
157                   ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, lp_workgroup(),
158                   ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, global_myname(),
159                   ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsname,
160                   ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
161                   ntlmssp_state->unicode, 0, "");
162
163         {
164                 const char *gen_string;
165                 if (ntlmssp_state->unicode) {
166                         gen_string = "CdUdbddB";
167                 } else {
168                         gen_string = "CdAdbddB";
169                 }
170                 
171                 msrpc_gen(reply, gen_string,
172                           "NTLMSSP", 
173                           NTLMSSP_CHALLENGE,
174                           target_name,
175                           chal_flags,
176                           cryptkey, 8,
177                           0, 0,
178                           struct_blob.data, struct_blob.length);
179         }
180                 
181         data_blob_free(&struct_blob);
182
183         return NT_STATUS_MORE_PROCESSING_REQUIRED;
184 }
185
186 NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state, 
187                       DATA_BLOB request, DATA_BLOB *reply) 
188 {
189         char *workgroup = NULL, *user = NULL, *machine = NULL;
190         DATA_BLOB lmhash, nthash, sess_key;
191         DATA_BLOB plaintext_password = data_blob(NULL, 0);
192         uint32 ntlmssp_command, neg_flags;
193         NTSTATUS nt_status;
194         uint32 auth_flags = AUTH_FLAG_NONE;
195         auth_usersupplied_info *user_info = NULL;
196
197         const char *parse_string;
198
199         /* parse the NTLMSSP packet */
200 #if 0
201         file_save("ntlmssp_auth.dat", request.data, request.length);
202 #endif
203
204         if (ntlmssp_state->unicode) {
205                 parse_string = "CdBBUUUBd";
206         } else {
207                 parse_string = "CdBBAAABd";
208         }
209
210         /* now the NTLMSSP encoded auth hashes */
211         if (!msrpc_parse(&request, parse_string,
212                          "NTLMSSP", 
213                          &ntlmssp_command, 
214                          &lmhash,
215                          &nthash,
216                          &workgroup, 
217                          &user, 
218                          &machine,
219                          &sess_key,
220                          &neg_flags)) {
221                 return NT_STATUS_LOGON_FAILURE;
222         }
223
224         data_blob_free(&sess_key);
225         
226         DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
227                  user, workgroup, machine, lmhash.length, nthash.length));
228
229         /* the client has given us its machine name (which we otherwise would not get on port 445).
230            we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
231
232         set_remote_machine_name(machine);
233
234         /* setup the string used by %U */
235         sub_set_smb_name(user);
236
237         reload_services(True);
238
239 #if 0
240         file_save("nthash1.dat", nthash.data, nthash.length);
241         file_save("lmhash1.dat", lmhash.data, lmhash.length);
242 #endif
243
244         if (lmhash.length) {
245                 auth_flags |= AUTH_FLAG_LM_RESP;
246         }
247
248         if (nthash.length == 24) {
249                 auth_flags |= AUTH_FLAG_NTLM_RESP;
250         } else if (nthash.length > 24) {
251                 auth_flags |= AUTH_FLAG_NTLMv2_RESP;
252         };
253
254         
255
256         nt_status = make_user_info_map(&user_info, user, workgroup, machine, 
257                                        lmhash, nthash, plaintext_password, 
258                                        auth_flags, True);
259
260         ntlmssp_state->orig_user = talloc_strdup(ntlmssp_state->mem_ctx, user);
261         ntlmssp_state->orig_domain = talloc_strdup(ntlmssp_state->mem_ctx, workgroup);
262
263         SAFE_FREE(user);
264         SAFE_FREE(workgroup);
265         SAFE_FREE(machine);
266
267         if (!NT_STATUS_IS_OK(nt_status)) {
268                 return nt_status;
269         }
270
271         nt_status = ntlmssp_state->auth_context->check_ntlm_password(ntlmssp_state->auth_context, user_info, &ntlmssp_state->server_info); 
272                         
273         (ntlmssp_state->auth_context->free)(&ntlmssp_state->auth_context);
274
275         free_user_info(&user_info);
276         
277         data_blob_free(&lmhash);
278         
279         data_blob_free(&nthash);
280
281         *reply = data_blob(NULL, 0);
282
283         return nt_status;
284 }