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