5b608e0a7a90866135f417b312663c8646731674
[amitay/samba.git] / source3 / libsmb / 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 /**
27  * Default challange generation code.
28  *
29  */
30    
31
32 static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state)
33 {
34         static uchar chal[8];
35         generate_random_buffer(chal, sizeof(chal), False);
36
37         return chal;
38 }
39
40 NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
41 {
42         TALLOC_CTX *mem_ctx;
43
44         mem_ctx = talloc_init("NTLMSSP context");
45         
46         *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
47         if (!*ntlmssp_state) {
48                 DEBUG(0,("ntlmssp_start: talloc failed!\n"));
49                 talloc_destroy(mem_ctx);
50                 return NT_STATUS_NO_MEMORY;
51         }
52
53         ZERO_STRUCTP(*ntlmssp_state);
54
55         (*ntlmssp_state)->mem_ctx = mem_ctx;
56         (*ntlmssp_state)->get_challenge = get_challenge;
57
58         (*ntlmssp_state)->get_global_myname = global_myname;
59         (*ntlmssp_state)->get_domain = lp_workgroup;
60         (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */
61
62         return NT_STATUS_OK;
63 }
64
65 NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
66 {
67         TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
68
69         data_blob_free(&(*ntlmssp_state)->chal);
70         data_blob_free(&(*ntlmssp_state)->lm_resp);
71         data_blob_free(&(*ntlmssp_state)->nt_resp);
72
73         SAFE_FREE((*ntlmssp_state)->user);
74         SAFE_FREE((*ntlmssp_state)->domain);
75         SAFE_FREE((*ntlmssp_state)->workstation);
76
77         talloc_destroy(mem_ctx);
78         *ntlmssp_state = NULL;
79         return NT_STATUS_OK;
80 }
81
82 NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, 
83                                DATA_BLOB request, DATA_BLOB *reply) 
84 {
85         uint32 ntlmssp_command;
86         *reply = data_blob(NULL, 0);
87
88         if (!msrpc_parse(&request, "Cd",
89                          "NTLMSSP",
90                          &ntlmssp_command)) {
91                 
92                 return NT_STATUS_LOGON_FAILURE;
93         }
94
95         if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
96                 return ntlmssp_negotiate(ntlmssp_state, request, reply);
97         } else if (ntlmssp_command == NTLMSSP_AUTH) {
98                 return ntlmssp_auth(ntlmssp_state, request, reply);
99         } else {
100                 return NT_STATUS_LOGON_FAILURE;
101         }
102 }
103
104 static const char *ntlmssp_target_name(NTLMSSP_STATE *ntlmssp_state, 
105                                        uint32 neg_flags, uint32 *chal_flags) 
106 {
107         if (neg_flags & NTLMSSP_REQUEST_TARGET) {
108                 *chal_flags |= NTLMSSP_CHAL_TARGET_INFO;
109                 *chal_flags |= NTLMSSP_REQUEST_TARGET;
110                 if (ntlmssp_state->server_role == ROLE_STANDALONE) {
111                         *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
112                         return ntlmssp_state->get_global_myname();
113                 } else {
114                         *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
115                         return ntlmssp_state->get_domain();
116                 };
117         } else {
118                 return "";
119         }
120 }
121
122 NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state, 
123                            DATA_BLOB request, DATA_BLOB *reply) 
124 {
125         DATA_BLOB struct_blob;
126         fstring dnsname, dnsdomname;
127         uint32 ntlmssp_command, neg_flags, chal_flags;
128         char *cliname=NULL, *domname=NULL;
129         const uint8 *cryptkey;
130         const char *target_name;
131
132         /* parse the NTLMSSP packet */
133 #if 0
134         file_save("ntlmssp_negotiate.dat", request.data, request.length);
135 #endif
136
137         if (!msrpc_parse(&request, "CddAA",
138                          "NTLMSSP",
139                          &ntlmssp_command,
140                          &neg_flags,
141                          &cliname,
142                          &domname)) {
143                 return NT_STATUS_LOGON_FAILURE;
144         }
145
146         SAFE_FREE(cliname);
147         SAFE_FREE(domname);
148   
149         debug_ntlmssp_flags(neg_flags);
150
151         cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
152
153         data_blob_free(&ntlmssp_state->chal);
154         ntlmssp_state->chal = data_blob(cryptkey, 8);
155
156         /* Give them the challenge. For now, ignore neg_flags and just
157            return the flags we want. Obviously this is not correct */
158         
159         chal_flags = 
160                 NTLMSSP_NEGOTIATE_128 | 
161                 NTLMSSP_NEGOTIATE_NTLM;
162         
163         if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
164                 chal_flags |= NTLMSSP_NEGOTIATE_UNICODE;
165                 ntlmssp_state->unicode = True;
166         } else {
167                 chal_flags |= NTLMSSP_NEGOTIATE_OEM;
168         }
169
170         target_name = ntlmssp_target_name(ntlmssp_state, 
171                                           neg_flags, &chal_flags); 
172
173         /* This should be a 'netbios domain -> DNS domain' mapping */
174         dnsdomname[0] = '\0';
175         get_mydomname(dnsdomname);
176         strlower(dnsdomname);
177         
178         dnsname[0] = '\0';
179         get_myfullname(dnsname);
180         strlower(dnsname);
181         
182         if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) 
183         {
184                 const char *target_name_dns = "";
185                 if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) {
186                         target_name_dns = dnsdomname;
187                 } else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) {
188                         target_name_dns = dnsname;
189                 }
190
191                 /* the numbers here are the string type flags */
192                 msrpc_gen(&struct_blob, "aaaaa",
193                           ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, target_name,
194                           ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
195                           ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, target_name_dns,
196                           ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
197                           ntlmssp_state->unicode, 0, "");
198         } else {
199                 struct_blob = data_blob(NULL, 0);
200         }
201
202         {
203                 const char *gen_string;
204                 if (ntlmssp_state->unicode) {
205                         gen_string = "CdUdbddB";
206                 } else {
207                         gen_string = "CdAdbddB";
208                 }
209                 
210                 msrpc_gen(reply, gen_string,
211                           "NTLMSSP", 
212                           NTLMSSP_CHALLENGE,
213                           target_name,
214                           chal_flags,
215                           cryptkey, 8,
216                           0, 0,
217                           struct_blob.data, struct_blob.length);
218         }
219                 
220         data_blob_free(&struct_blob);
221
222         return NT_STATUS_MORE_PROCESSING_REQUIRED;
223 }
224
225 NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state, 
226                       DATA_BLOB request, DATA_BLOB *reply) 
227 {
228         DATA_BLOB sess_key;
229         uint32 ntlmssp_command, neg_flags;
230         NTSTATUS nt_status;
231
232         const char *parse_string;
233
234         /* parse the NTLMSSP packet */
235 #if 0
236         file_save("ntlmssp_auth.dat", request.data, request.length);
237 #endif
238
239         if (ntlmssp_state->unicode) {
240                 parse_string = "CdBBUUUBd";
241         } else {
242                 parse_string = "CdBBAAABd";
243         }
244
245         data_blob_free(&ntlmssp_state->lm_resp);
246         data_blob_free(&ntlmssp_state->nt_resp);
247
248         SAFE_FREE(ntlmssp_state->user);
249         SAFE_FREE(ntlmssp_state->domain);
250         SAFE_FREE(ntlmssp_state->workstation);
251
252         /* now the NTLMSSP encoded auth hashes */
253         if (!msrpc_parse(&request, parse_string,
254                          "NTLMSSP", 
255                          &ntlmssp_command, 
256                          &ntlmssp_state->lm_resp,
257                          &ntlmssp_state->nt_resp,
258                          &ntlmssp_state->domain, 
259                          &ntlmssp_state->user, 
260                          &ntlmssp_state->workstation,
261                          &sess_key,
262                          &neg_flags)) {
263                 return NT_STATUS_LOGON_FAILURE;
264         }
265
266         data_blob_free(&sess_key);
267         
268         DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%d len2=%d\n",
269                  ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, ntlmssp_state->lm_resp.length, ntlmssp_state->nt_resp.length));
270
271 #if 0
272         file_save("nthash1.dat",  &ntlmssp_state->nt_resp.data,  &ntlmssp_state->nt_resp.length);
273         file_save("lmhash1.dat",  &ntlmssp_state->lm_resp.data,  &ntlmssp_state->lm_resp.length);
274 #endif
275
276         nt_status = ntlmssp_state->check_password(ntlmssp_state);
277         
278         *reply = data_blob(NULL, 0);
279
280         return nt_status;
281 }