Merge a trivial fix across from HEAD. Not that this
[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->inbuf[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         unsigned char sequence_buf[8];
151         struct MD5Context md5_ctx;
152         struct smb_basic_signing_context *data = cli->sign_info.signing_context;
153         const size_t offset_end_of_sig = (smb_ss_field + 8);
154
155         /*
156          * Firstly put the sequence number into the first 4 bytes.
157          * and zero out the next 4 bytes.
158          */
159
160         SIVAL(sequence_buf, 0, data->reply_seq_num);
161         SIVAL(sequence_buf, 4, 0);
162
163         if (smb_len(cli->inbuf) < (offset_end_of_sig - 4)) {
164                 DEBUG(1, ("Can't check signature on short packet! smb_len = %u\n", smb_len(cli->inbuf)));
165                 return False;
166         }
167
168         /* get a copy of the server-sent mac */
169         memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
170         
171         /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
172         MD5Init(&md5_ctx);
173         MD5Update(&md5_ctx, data->mac_key.data, 
174                   data->mac_key.length); 
175         MD5Update(&md5_ctx, cli->inbuf + 4, smb_ss_field - 4);
176         MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
177         
178         MD5Update(&md5_ctx, cli->inbuf + offset_end_of_sig, 
179                   smb_len(cli->inbuf) - (offset_end_of_sig - 4));
180         MD5Final(calc_md5_mac, &md5_ctx);
181
182         good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
183         
184         if (!good) {
185                 DEBUG(5, ("BAD SIG: wanted SMB signature of\n"));
186                 dump_data(5, calc_md5_mac, 8);
187                 
188                 DEBUG(5, ("BAD SIG: got SMB signature of\n"));
189                 dump_data(5, server_sent_mac, 8);
190         }
191         return signing_good(cli, good);
192 }
193
194 /***********************************************************
195  SMB signing - Simple implementation - free signing context
196 ************************************************************/
197
198 static void cli_simple_free_signing_context(struct cli_state *cli)
199 {
200         struct smb_basic_signing_context *data = cli->sign_info.signing_context;
201
202         data_blob_free(&data->mac_key);
203         SAFE_FREE(cli->sign_info.signing_context);
204
205         return;
206 }
207
208 /***********************************************************
209  SMB signing - Simple implementation - setup the MAC key.
210 ************************************************************/
211
212 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
213 {
214         struct smb_basic_signing_context *data;
215
216         if (!set_smb_signing_common(cli)) {
217                 return False;
218         }
219
220         if (!set_smb_signing_real_common(cli)) {
221                 return False;
222         }
223
224         data = smb_xmalloc(sizeof(*data));
225         cli->sign_info.signing_context = data;
226         
227         data->mac_key = data_blob(NULL, MIN(response.length + 16, 40));
228
229         memcpy(&data->mac_key.data[0], user_session_key, 16);
230         memcpy(&data->mac_key.data[16],response.data, MIN(response.length, 40 - 16));
231
232         /* Initialise the sequence number */
233         data->send_seq_num = 0;
234
235         cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
236         cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
237         cli->sign_info.free_signing_context = cli_simple_free_signing_context;
238
239         return True;
240 }
241
242 /***********************************************************
243  SMB signing - NTLMSSP implementation - calculate a MAC to send.
244 ************************************************************/
245
246 static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
247 {
248         NTSTATUS nt_status;
249         DATA_BLOB sig;
250         NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
251
252         /* mark the packet as signed - BEFORE we sign it...*/
253         mark_packet_signed(cli);
254         
255         nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4, 
256                                                smb_len(cli->outbuf), &sig);
257         
258         if (!NT_STATUS_IS_OK(nt_status)) {
259                 DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
260                 return;
261         }
262
263         DEBUG(10, ("sent SMB signature of\n"));
264         dump_data(10, sig.data, MIN(sig.length, 8));
265         memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
266         
267         data_blob_free(&sig);
268 }
269
270 /***********************************************************
271  SMB signing - NTLMSSP implementation - check a MAC sent by server.
272 ************************************************************/
273
274 static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
275 {
276         BOOL good;
277         NTSTATUS nt_status;
278         DATA_BLOB sig = data_blob(&cli->inbuf[smb_ss_field], 8);
279
280         NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
281
282         nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4, 
283                                                 smb_len(cli->outbuf), &sig);
284         
285         data_blob_free(&sig);
286         
287         good = NT_STATUS_IS_OK(nt_status);
288         if (!NT_STATUS_IS_OK(nt_status)) {
289                 DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
290         }
291
292         return signing_good(cli, good);
293 }
294
295 /***********************************************************
296  SMB signing - NTLMSSP implementation - free signing context
297 ************************************************************/
298
299 static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
300 {
301         ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
302 }
303
304 /***********************************************************
305  SMB signing - NTLMSSP implementation - setup the MAC key.
306 ************************************************************/
307
308 BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
309                              NTLMSSP_CLIENT_STATE *ntlmssp_state)
310 {
311         if (!set_smb_signing_common(cli)) {
312                 return False;
313         }
314
315         if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
316                 return False;
317         }
318
319         if (!set_smb_signing_real_common(cli)) {
320                 return False;
321         }
322
323         cli->sign_info.signing_context = ntlmssp_state;
324         ntlmssp_state->ref_count++;
325
326         cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
327         cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
328         cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
329
330         return True;
331 }
332
333 /***********************************************************
334  SMB signing - NULL implementation - calculate a MAC to send.
335 ************************************************************/
336
337 static void cli_null_sign_outgoing_message(struct cli_state *cli)
338 {
339         /* we can't zero out the sig, as we might be trying to send a
340            session request - which is NBT-level, not SMB level and doesn't
341            have the field */
342         return;
343 }
344
345 /***********************************************************
346  SMB signing - NULL implementation - check a MAC sent by server.
347 ************************************************************/
348
349 static BOOL cli_null_check_incoming_message(struct cli_state *cli)
350 {
351         return True;
352 }
353
354 /***********************************************************
355  SMB signing - NULL implementation - free signing context
356 ************************************************************/
357
358 static void cli_null_free_signing_context(struct cli_state *cli)
359 {
360         return;
361 }
362
363 /**
364  SMB signing - NULL implementation - setup the MAC key.
365
366  @note Used as an initialisation only - it will not correctly
367        shut down a real signing mechanism
368 */
369
370 BOOL cli_null_set_signing(struct cli_state *cli)
371 {
372         cli->sign_info.signing_context = NULL;
373         
374         cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
375         cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
376         cli->sign_info.free_signing_context = cli_null_free_signing_context;
377
378         return True;
379 }
380
381 /***********************************************************
382  SMB signing - TEMP implementation - calculate a MAC to send.
383 ************************************************************/
384
385 static void cli_temp_sign_outgoing_message(struct cli_state *cli)
386 {
387         /* mark the packet as signed - BEFORE we sign it...*/
388         mark_packet_signed(cli);
389
390         /* I wonder what BSRSPYL stands for - but this is what MS 
391            actually sends! */
392         memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
393         return;
394 }
395
396 /***********************************************************
397  SMB signing - TEMP implementation - check a MAC sent by server.
398 ************************************************************/
399
400 static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
401 {
402         return True;
403 }
404
405 /***********************************************************
406  SMB signing - TEMP implementation - free signing context
407 ************************************************************/
408
409 static void cli_temp_free_signing_context(struct cli_state *cli)
410 {
411         return;
412 }
413
414 /***********************************************************
415  SMB signing - NULL implementation - setup the MAC key.
416 ************************************************************/
417
418 BOOL cli_temp_set_signing(struct cli_state *cli)
419 {
420         if (!set_smb_signing_common(cli)) {
421                 return False;
422         }
423
424         cli->sign_info.signing_context = NULL;
425         
426         cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
427         cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
428         cli->sign_info.free_signing_context = cli_temp_free_signing_context;
429
430         return True;
431 }
432
433 /**
434  * Free the signing context
435  */
436  
437 void cli_free_signing_context(struct cli_state *cli) 
438 {
439         if (cli->sign_info.free_signing_context) 
440                 cli->sign_info.free_signing_context(cli);
441
442         cli_null_set_signing(cli);
443 }
444
445 /**
446  * Sign a packet with the current mechanism
447  */
448  
449 void cli_caclulate_sign_mac(struct cli_state *cli)
450 {
451         cli->sign_info.sign_outgoing_message(cli);
452 }
453
454 /**
455  * Check a packet with the current mechanism
456  * @return False if we had an established signing connection
457  *         which had a back checksum, True otherwise
458  */
459  
460 BOOL cli_check_sign_mac(struct cli_state *cli) 
461 {
462         BOOL good;
463         good = cli->sign_info.check_incoming_message(cli);
464         
465         if (!good) {
466                 if (cli->sign_info.doing_signing) {
467                         return False;
468                 } else {
469                         cli_free_signing_context(cli);  
470                 }
471         }
472
473         return True;
474 }
475