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