Removed unused var.
[ira/wip.git] / source3 / libsmb / smb_signing.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB Signing Code
4    Copyright (C) Jeremy Allison 2002.
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 struct smb_basic_signing_context {
25         DATA_BLOB mac_key;
26         uint32 send_seq_num;
27         uint32 reply_seq_num;
28 };
29
30 /***********************************************************
31  SMB signing - Common code before we set a new signing implementation
32 ************************************************************/
33
34 static BOOL set_smb_signing_common(struct cli_state *cli) 
35 {
36         if (!cli->sign_info.negotiated_smb_signing 
37             && !cli->sign_info.mandetory_signing) {
38                 return False;
39         }
40
41         if (cli->sign_info.doing_signing) {
42                 return False;
43         }
44         
45         if (cli->sign_info.free_signing_context)
46                 cli->sign_info.free_signing_context(cli);
47
48         /* These calls are INCOMPATIBLE with SMB signing */
49         cli->readbraw_supported = False;
50         cli->writebraw_supported = False;
51         
52         return True;
53 }
54
55 /***********************************************************
56  SMB signing - Common code for 'real' implementations
57 ************************************************************/
58
59 static BOOL set_smb_signing_real_common(struct cli_state *cli) 
60 {
61         if (cli->sign_info.mandetory_signing) {
62                 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
63                 cli->sign_info.doing_signing = True;
64         }
65
66         DEBUG(5, ("SMB signing enabled!\n"));
67
68         return True;
69 }
70
71 static void mark_packet_signed(struct cli_state *cli) 
72 {
73         uint16 flags2;
74         flags2 = SVAL(cli->outbuf,smb_flg2);
75         flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
76         SSVAL(cli->outbuf,smb_flg2, flags2);
77 }
78
79 static BOOL signing_good(struct cli_state *cli, BOOL good) 
80 {
81         DEBUG(10, ("got SMB signature of\n"));
82         dump_data(10,&cli->outbuf[smb_ss_field] , 8);
83
84         if (good && !cli->sign_info.doing_signing) {
85                 cli->sign_info.doing_signing = True;
86         }
87
88         if (!good) {
89                 if (cli->sign_info.doing_signing) {
90                         DEBUG(1, ("SMB signature check failed!\n"));
91                         return False;
92                 } else {
93                         DEBUG(3, ("Server did not sign reply correctly\n"));
94                         cli_free_signing_context(cli);
95                         return False;
96                 }
97         }
98         return True;
99 }       
100
101 /***********************************************************
102  SMB signing - Simple implementation - calculate a MAC to send.
103 ************************************************************/
104
105 static void cli_simple_sign_outgoing_message(struct cli_state *cli)
106 {
107         unsigned char calc_md5_mac[16];
108         struct MD5Context md5_ctx;
109         struct smb_basic_signing_context *data = cli->sign_info.signing_context;
110
111         /*
112          * Firstly put the sequence number into the first 4 bytes.
113          * and zero out the next 4 bytes.
114          */
115         SIVAL(cli->outbuf, smb_ss_field, 
116               data->send_seq_num);
117         SIVAL(cli->outbuf, smb_ss_field + 4, 0);
118
119         /* mark the packet as signed - BEFORE we sign it...*/
120         mark_packet_signed(cli);
121
122         /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
123         MD5Init(&md5_ctx);
124         MD5Update(&md5_ctx, data->mac_key.data, 
125                   data->mac_key.length); 
126         MD5Update(&md5_ctx, cli->outbuf + 4, smb_len(cli->outbuf));
127         MD5Final(calc_md5_mac, &md5_ctx);
128
129         DEBUG(10, ("sent SMB signature of\n"));
130         dump_data(10, calc_md5_mac, 8);
131
132         memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8);
133
134 /*      cli->outbuf[smb_ss_field+2]=0; 
135         Uncomment this to test if the remote server actually verifies signitures...*/
136         data->send_seq_num++;
137         data->reply_seq_num = data->send_seq_num;
138         data->send_seq_num++;
139 }
140
141 /***********************************************************
142  SMB signing - Simple implementation - check a MAC sent by server.
143 ************************************************************/
144
145 static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
146 {
147         BOOL good;
148         unsigned char calc_md5_mac[16];
149         unsigned char server_sent_mac[8];
150         struct MD5Context md5_ctx;
151         struct smb_basic_signing_context *data = cli->sign_info.signing_context;
152
153         /*
154          * Firstly put the sequence number into the first 4 bytes.
155          * and zero out the next 4 bytes.
156          */
157
158         memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
159
160         DEBUG(10, ("got SMB signature of\n"));
161         dump_data(10, server_sent_mac, 8);
162
163         SIVAL(cli->inbuf, smb_ss_field, data->reply_seq_num);
164         SIVAL(cli->inbuf, smb_ss_field + 4, 0);
165
166         /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
167         MD5Init(&md5_ctx);
168         MD5Update(&md5_ctx, data->mac_key.data, 
169                   data->mac_key.length); 
170         MD5Update(&md5_ctx, cli->inbuf + 4, smb_len(cli->inbuf));
171         MD5Final(calc_md5_mac, &md5_ctx);
172
173         good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
174         
175         return signing_good(cli, good);
176 }
177
178 /***********************************************************
179  SMB signing - Simple implementation - free signing context
180 ************************************************************/
181
182 static void cli_simple_free_signing_context(struct cli_state *cli)
183 {
184         struct smb_basic_signing_context *data = cli->sign_info.signing_context;
185
186         data_blob_free(&data->mac_key);
187         SAFE_FREE(cli->sign_info.signing_context);
188
189         return;
190 }
191
192 /***********************************************************
193  SMB signing - Simple implementation - setup the MAC key.
194 ************************************************************/
195
196 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
197 {
198         struct smb_basic_signing_context *data;
199
200         if (!set_smb_signing_common(cli)) {
201                 return False;
202         }
203
204         if (!set_smb_signing_real_common(cli)) {
205                 return False;
206         }
207
208         data = smb_xmalloc(sizeof(*data));
209         cli->sign_info.signing_context = data;
210         
211         data->mac_key = data_blob(NULL, MIN(response.length + 16, 40));
212
213         memcpy(&data->mac_key.data[0], user_session_key, 16);
214         memcpy(&data->mac_key.data[16],response.data, MIN(response.length, 40 - 16));
215
216         /* Initialize the sequence number */
217         data->send_seq_num = 0;
218
219         cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
220         cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
221         cli->sign_info.free_signing_context = cli_simple_free_signing_context;
222
223         return True;
224 }
225
226 /***********************************************************
227  SMB signing - NTLMSSP implementation - calculate a MAC to send.
228 ************************************************************/
229
230 static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
231 {
232         NTSTATUS nt_status;
233         DATA_BLOB sig;
234         NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
235
236         /* mark the packet as signed - BEFORE we sign it...*/
237         mark_packet_signed(cli);
238         
239         nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4, 
240                                                smb_len(cli->outbuf), &sig);
241         
242         if (!NT_STATUS_IS_OK(nt_status)) {
243                 DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
244                 return;
245         }
246
247         DEBUG(10, ("sent SMB signature of\n"));
248         dump_data(10, sig.data, MIN(sig.length, 8));
249         memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
250         
251         data_blob_free(&sig);
252 }
253
254 /***********************************************************
255  SMB signing - NTLMSSP implementation - check a MAC sent by server.
256 ************************************************************/
257
258 static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
259 {
260         BOOL good;
261         NTSTATUS nt_status;
262         DATA_BLOB sig = data_blob(&cli->outbuf[smb_ss_field], 8);
263
264         NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
265
266         nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4, 
267                                                 smb_len(cli->outbuf), &sig);
268         
269         data_blob_free(&sig);
270         
271         good = NT_STATUS_IS_OK(nt_status);
272         if (!NT_STATUS_IS_OK(nt_status)) {
273                 DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
274         }
275
276         return signing_good(cli, good);
277 }
278
279 /***********************************************************
280  SMB signing - NTLMSSP implementation - free signing context
281 ************************************************************/
282
283 static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
284 {
285         ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
286 }
287
288 /***********************************************************
289  SMB signing - NTLMSSP implementation - setup the MAC key.
290 ************************************************************/
291
292 BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
293                              NTLMSSP_CLIENT_STATE *ntlmssp_state)
294 {
295         if (!set_smb_signing_common(cli)) {
296                 return False;
297         }
298
299         if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
300                 return False;
301         }
302
303         if (!set_smb_signing_real_common(cli)) {
304                 return False;
305         }
306
307         cli->sign_info.signing_context = ntlmssp_state;
308         ntlmssp_state->ref_count++;
309
310         cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
311         cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
312         cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
313
314         return True;
315 }
316
317 /***********************************************************
318  SMB signing - NULL implementation - calculate a MAC to send.
319 ************************************************************/
320
321 static void cli_null_sign_outgoing_message(struct cli_state *cli)
322 {
323         /* we can't zero out the sig, as we might be trying to send a
324            session request - which is NBT-level, not SMB level and doesn't
325            have the field */
326         return;
327 }
328
329 /***********************************************************
330  SMB signing - NULL implementation - check a MAC sent by server.
331 ************************************************************/
332
333 static BOOL cli_null_check_incoming_message(struct cli_state *cli)
334 {
335         return True;
336 }
337
338 /***********************************************************
339  SMB signing - NULL implementation - free signing context
340 ************************************************************/
341
342 static void cli_null_free_signing_context(struct cli_state *cli)
343 {
344         return;
345 }
346
347 /**
348  SMB signing - NULL implementation - setup the MAC key.
349
350  @note Used as an initialisation only - it will not correctly
351        shut down a real signing mechinism
352 */
353
354 BOOL cli_null_set_signing(struct cli_state *cli)
355 {
356         cli->sign_info.signing_context = NULL;
357         
358         cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
359         cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
360         cli->sign_info.free_signing_context = cli_null_free_signing_context;
361
362         return True;
363 }
364
365 /***********************************************************
366  SMB signing - TEMP implementation - calculate a MAC to send.
367 ************************************************************/
368
369 static void cli_temp_sign_outgoing_message(struct cli_state *cli)
370 {
371         /* mark the packet as signed - BEFORE we sign it...*/
372         mark_packet_signed(cli);
373
374         /* I wonder what BSRSPYL stands for - but this is what MS 
375            actually sends! */
376         memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
377         return;
378 }
379
380 /***********************************************************
381  SMB signing - TEMP implementation - check a MAC sent by server.
382 ************************************************************/
383
384 static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
385 {
386         return True;
387 }
388
389 /***********************************************************
390  SMB signing - TEMP implementation - free signing context
391 ************************************************************/
392
393 static void cli_temp_free_signing_context(struct cli_state *cli)
394 {
395         return;
396 }
397
398 /***********************************************************
399  SMB signing - NULL implementation - setup the MAC key.
400 ************************************************************/
401
402 BOOL cli_temp_set_signing(struct cli_state *cli)
403 {
404         if (!set_smb_signing_common(cli)) {
405                 return False;
406         }
407
408         cli->sign_info.signing_context = NULL;
409         
410         cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
411         cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
412         cli->sign_info.free_signing_context = cli_temp_free_signing_context;
413
414         return True;
415 }
416
417 /**
418  * Free the signing context
419  */
420  
421 void cli_free_signing_context(struct cli_state *cli) 
422 {
423         if (cli->sign_info.free_signing_context) 
424                 cli->sign_info.free_signing_context(cli);
425
426         cli_null_set_signing(cli);
427 }
428
429 /**
430  * Sign a packet with the current mechanism
431  */
432  
433 void cli_caclulate_sign_mac(struct cli_state *cli)
434 {
435         cli->sign_info.sign_outgoing_message(cli);
436 }
437
438 /**
439  * Check a packet with the current mechanism
440  * @return False if we had an established signing connection
441  *         which had a back checksum, True otherwise
442  */
443  
444 BOOL cli_check_sign_mac(struct cli_state *cli) 
445 {
446         BOOL good;
447         good = cli->sign_info.check_incoming_message(cli);
448         
449         if (!good) {
450                 if (cli->sign_info.doing_signing) {
451                         return False;
452                 } else {
453                         cli_free_signing_context(cli);  
454                 }
455         }
456
457         return True;
458 }
459