6644bc0d6005aac121e62cef656b4b9059609a51
[ira/wip.git] / source3 / libsmb / clisigning.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB Signing Code
4    Copyright (C) Jeremy Allison 2003.
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 3 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, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 /* Lookup a packet's MID (multiplex id) and figure out it's sequence number */
24 struct outstanding_packet_lookup {
25         struct outstanding_packet_lookup *prev, *next;
26         uint16 mid;
27         uint32 reply_seq_num;
28         bool can_delete; /* Set to False in trans state. */
29 };
30
31 struct smb_basic_signing_context {
32         DATA_BLOB mac_key;
33         uint32 send_seq_num;
34         struct outstanding_packet_lookup *outstanding_packet_list;
35 };
36
37 static bool store_sequence_for_reply(struct outstanding_packet_lookup **list, 
38                                      uint16 mid, uint32 reply_seq_num)
39 {
40         struct outstanding_packet_lookup *t;
41
42         /* Ensure we only add a mid once. */
43         for (t = *list; t; t = t->next) {
44                 if (t->mid == mid) {
45                         return False;
46                 }
47         }
48
49         t = SMB_XMALLOC_P(struct outstanding_packet_lookup);
50         ZERO_STRUCTP(t);
51
52         t->mid = mid;
53         t->reply_seq_num = reply_seq_num;
54         t->can_delete = True;
55
56         /*
57          * Add to the *start* of the list not the end of the list.
58          * This ensures that the *last* send sequence with this mid
59          * is returned by preference.
60          * This can happen if the mid wraps and one of the early
61          * mid numbers didn't get a reply and is still lurking on
62          * the list. JRA. Found by Fran Fabrizio <fran@cis.uab.edu>.
63          */
64
65         DLIST_ADD(*list, t);
66         DEBUG(10,("store_sequence_for_reply: stored seq = %u mid = %u\n",
67                         (unsigned int)reply_seq_num, (unsigned int)mid ));
68         return True;
69 }
70
71 static bool get_sequence_for_reply(struct outstanding_packet_lookup **list,
72                                    uint16 mid, uint32 *reply_seq_num)
73 {
74         struct outstanding_packet_lookup *t;
75
76         for (t = *list; t; t = t->next) {
77                 if (t->mid == mid) {
78                         *reply_seq_num = t->reply_seq_num;
79                         DEBUG(10,("get_sequence_for_reply: found seq = %u mid = %u\n",
80                                 (unsigned int)t->reply_seq_num, (unsigned int)t->mid ));
81                         if (t->can_delete) {
82                                 DLIST_REMOVE(*list, t);
83                                 SAFE_FREE(t);
84                         }
85                         return True;
86                 }
87         }
88         return False;
89 }
90
91 static bool set_sequence_can_delete_flag(struct outstanding_packet_lookup **list, uint16 mid, bool can_delete_entry)
92 {
93         struct outstanding_packet_lookup *t;
94
95         for (t = *list; t; t = t->next) {
96                 if (t->mid == mid) {
97                         t->can_delete = can_delete_entry;
98                         return True;
99                 }
100         }
101         return False;
102 }
103
104 /***********************************************************
105  SMB signing - Common code before we set a new signing implementation
106 ************************************************************/
107
108 static bool cli_set_smb_signing_common(struct cli_state *cli) 
109 {
110         if (!cli->sign_info.allow_smb_signing) {
111                 return False;
112         }
113
114         if (!cli->sign_info.negotiated_smb_signing 
115             && !cli->sign_info.mandatory_signing) {
116                 return False;
117         }
118
119         if (cli->sign_info.doing_signing) {
120                 return False;
121         }
122
123         if (cli->sign_info.free_signing_context)
124                 cli->sign_info.free_signing_context(&cli->sign_info);
125
126         /* These calls are INCOMPATIBLE with SMB signing */
127         cli->readbraw_supported = False;
128         cli->writebraw_supported = False;
129
130         return True;
131 }
132
133 /***********************************************************
134  SMB signing - Common code for 'real' implementations
135 ************************************************************/
136
137 static bool set_smb_signing_real_common(struct smb_sign_info *si)
138 {
139         if (si->mandatory_signing) {
140                 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
141         }
142
143         si->doing_signing = True;
144         DEBUG(5, ("SMB signing enabled!\n"));
145
146         return True;
147 }
148
149 static void mark_packet_signed(char *outbuf)
150 {
151         uint16 flags2;
152         flags2 = SVAL(outbuf,smb_flg2);
153         flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
154         SSVAL(outbuf,smb_flg2, flags2);
155 }
156
157 /***********************************************************
158  SMB signing - NULL implementation - calculate a MAC to send.
159 ************************************************************/
160
161 static void null_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
162 {
163         /* we can't zero out the sig, as we might be trying to send a
164            session request - which is NBT-level, not SMB level and doesn't
165            have the field */
166         return;
167 }
168
169 /***********************************************************
170  SMB signing - NULL implementation - check a MAC sent by server.
171 ************************************************************/
172
173 static bool null_check_incoming_message(const char *inbuf,
174                                         struct smb_sign_info *si,
175                                         bool must_be_ok)
176 {
177         return True;
178 }
179
180 /***********************************************************
181  SMB signing - NULL implementation - free signing context
182 ************************************************************/
183
184 static void null_free_signing_context(struct smb_sign_info *si)
185 {
186         return;
187 }
188
189 /**
190  SMB signing - NULL implementation - setup the MAC key.
191
192  @note Used as an initialisation only - it will not correctly
193        shut down a real signing mechanism
194 */
195
196 static bool null_set_signing(struct smb_sign_info *si)
197 {
198         si->signing_context = NULL;
199
200         si->sign_outgoing_message = null_sign_outgoing_message;
201         si->check_incoming_message = null_check_incoming_message;
202         si->free_signing_context = null_free_signing_context;
203
204         return True;
205 }
206
207 /**
208  * Free the signing context
209  */
210
211 static void free_signing_context(struct smb_sign_info *si)
212 {
213         if (si->free_signing_context) {
214                 si->free_signing_context(si);
215                 si->signing_context = NULL;
216         }
217
218         null_set_signing(si);
219 }
220
221
222 static bool signing_good(const char *inbuf, struct smb_sign_info *si,
223                          bool good, uint32 seq, bool must_be_ok)
224 {
225         if (good) {
226
227                 if (!si->doing_signing) {
228                         si->doing_signing = True;
229                 }
230
231                 if (!si->seen_valid) {
232                         si->seen_valid = True;
233                 }
234
235         } else {
236                 if (!si->mandatory_signing && !si->seen_valid) {
237
238                         if (!must_be_ok) {
239                                 return True;
240                         }
241                         /* Non-mandatory signing - just turn off if this is the first bad packet.. */
242                         DEBUG(5, ("srv_check_incoming_message: signing negotiated but not required and peer\n"
243                                   "isn't sending correct signatures. Turning off.\n"));
244                         si->negotiated_smb_signing = False;
245                         si->allow_smb_signing = False;
246                         si->doing_signing = False;
247                         free_signing_context(si);
248                         return True;
249                 } else if (!must_be_ok) {
250                         /* This packet is known to be unsigned */
251                         return True;
252                 } else {
253                         /* Mandatory signing or bad packet after signing started - fail and disconnect. */
254                         if (seq)
255                                 DEBUG(0, ("signing_good: BAD SIG: seq %u\n", (unsigned int)seq));
256                         return False;
257                 }
258         }
259         return True;
260 }       
261
262 /***********************************************************
263  SMB signing - Simple implementation - calculate a MAC on the packet
264 ************************************************************/
265
266 static void simple_packet_signature(struct smb_basic_signing_context *data, 
267                                     const uchar *buf, uint32 seq_number, 
268                                     unsigned char calc_md5_mac[16])
269 {
270         const size_t offset_end_of_sig = (smb_ss_field + 8);
271         unsigned char sequence_buf[8];
272         struct MD5Context md5_ctx;
273 #if 0
274         /* JRA - apparently this is incorrect. */
275         unsigned char key_buf[16];
276 #endif
277
278         /*
279          * Firstly put the sequence number into the first 4 bytes.
280          * and zero out the next 4 bytes.
281          *
282          * We do this here, to avoid modifying the packet.
283          */
284
285         DEBUG(10,("simple_packet_signature: sequence number %u\n", seq_number ));
286
287         SIVAL(sequence_buf, 0, seq_number);
288         SIVAL(sequence_buf, 4, 0);
289
290         /* Calculate the 16 byte MAC - but don't alter the data in the
291            incoming packet.
292
293            This makes for a bit of fussing about, but it's not too bad.
294         */
295         MD5Init(&md5_ctx);
296
297         /* intialise with the key */
298         MD5Update(&md5_ctx, data->mac_key.data, data->mac_key.length); 
299 #if 0
300         /* JRA - apparently this is incorrect. */
301         /* NB. When making and verifying SMB signatures, Windows apparently
302                 zero-pads the key to 128 bits if it isn't long enough.
303                 From Nalin Dahyabhai <nalin@redhat.com> */
304         if (data->mac_key.length < sizeof(key_buf)) {
305                 memset(key_buf, 0, sizeof(key_buf));
306                 MD5Update(&md5_ctx, key_buf, sizeof(key_buf) - data->mac_key.length);
307         }
308 #endif
309
310         /* copy in the first bit of the SMB header */
311         MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4);
312
313         /* copy in the sequence number, instead of the signature */
314         MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
315
316         /* copy in the rest of the packet in, skipping the signature */
317         MD5Update(&md5_ctx, buf + offset_end_of_sig, 
318                   smb_len(buf) - (offset_end_of_sig - 4));
319
320         /* calculate the MD5 sig */ 
321         MD5Final(calc_md5_mac, &md5_ctx);
322 }
323
324
325 /***********************************************************
326  SMB signing - Client implementation - send the MAC.
327 ************************************************************/
328
329 static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
330 {
331         unsigned char calc_md5_mac[16];
332         struct smb_basic_signing_context *data =
333                 (struct smb_basic_signing_context *)si->signing_context;
334
335         if (!si->doing_signing)
336                 return;
337
338         /* JRA Paranioa test - we should be able to get rid of this... */
339         if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
340                 DEBUG(1, ("client_sign_outgoing_message: Logic error. Can't check signature on short packet! smb_len = %u\n",
341                                         smb_len(outbuf) ));
342                 abort();
343         }
344
345         /* mark the packet as signed - BEFORE we sign it...*/
346         mark_packet_signed(outbuf);
347
348         simple_packet_signature(data, (const unsigned char *)outbuf,
349                                 data->send_seq_num, calc_md5_mac);
350
351         DEBUG(10, ("client_sign_outgoing_message: sent SMB signature of\n"));
352         dump_data(10, calc_md5_mac, 8);
353
354         memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
355
356 /*      cli->outbuf[smb_ss_field+2]=0; 
357         Uncomment this to test if the remote server actually verifies signatures...*/
358
359         /* Instead of re-introducing the trans_info_conect we
360            used to have here, we use the fact that during a
361            SMBtrans/SMBtrans2/SMBnttrans send that the mid stays
362            constant. This means that calling store_sequence_for_reply()
363            will return False for all trans secondaries, as the mid is already
364            on the stored sequence list. As the send_seqence_number must
365            remain constant for all primary+secondary trans sends, we
366            only increment the send sequence number when we successfully
367            add a new entry to the outstanding sequence list. This means
368            I can isolate the fix here rather than re-adding the trans
369            signing on/off calls in libsmb/clitrans2.c JRA.
370          */
371
372         if (store_sequence_for_reply(&data->outstanding_packet_list, SVAL(outbuf,smb_mid), data->send_seq_num + 1)) {
373                 data->send_seq_num += 2;
374         }
375 }
376
377 /***********************************************************
378  SMB signing - Client implementation - check a MAC sent by server.
379 ************************************************************/
380
381 static bool client_check_incoming_message(const char *inbuf,
382                                           struct smb_sign_info *si,
383                                           bool must_be_ok)
384 {
385         bool good;
386         uint32 reply_seq_number;
387         unsigned char calc_md5_mac[16];
388         unsigned char *server_sent_mac;
389
390         struct smb_basic_signing_context *data =
391                 (struct smb_basic_signing_context *)si->signing_context;
392
393         if (!si->doing_signing)
394                 return True;
395
396         if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
397                 DEBUG(1, ("client_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf)));
398                 return False;
399         }
400
401         if (!get_sequence_for_reply(&data->outstanding_packet_list, SVAL(inbuf, smb_mid), &reply_seq_number)) {
402                 DEBUG(1, ("client_check_incoming_message: received message "
403                         "with mid %u with no matching send record.\n", (unsigned int)SVAL(inbuf, smb_mid) ));
404                 return False;
405         }
406
407         simple_packet_signature(data, (const unsigned char *)inbuf,
408                                 reply_seq_number, calc_md5_mac);
409
410         server_sent_mac = (unsigned char *)&inbuf[smb_ss_field];
411         good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
412
413         if (!good) {
414                 DEBUG(5, ("client_check_incoming_message: BAD SIG: wanted SMB signature of\n"));
415                 dump_data(5, calc_md5_mac, 8);
416
417                 DEBUG(5, ("client_check_incoming_message: BAD SIG: got SMB signature of\n"));
418                 dump_data(5, server_sent_mac, 8);
419 #if 1 /* JRATEST */
420                 {
421                         int i;
422                         for (i = -5; i < 5; i++) {
423                                 simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number+i, calc_md5_mac);
424                                 if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) {
425                                         DEBUG(0,("client_check_incoming_message: out of seq. seq num %u matches. \
426 We were expecting seq %u\n", reply_seq_number+i, reply_seq_number ));
427                                         break;
428                                 }
429                         }
430                 }
431 #endif /* JRATEST */
432
433         } else {
434                 DEBUG(10, ("client_check_incoming_message: seq %u: got good SMB signature of\n", (unsigned int)reply_seq_number));
435                 dump_data(10, server_sent_mac, 8);
436         }
437         return signing_good(inbuf, si, good, reply_seq_number, must_be_ok);
438 }
439
440 /***********************************************************
441  SMB signing - Simple implementation - free signing context
442 ************************************************************/
443
444 static void simple_free_signing_context(struct smb_sign_info *si)
445 {
446         struct smb_basic_signing_context *data =
447                 (struct smb_basic_signing_context *)si->signing_context;
448         struct outstanding_packet_lookup *list;
449         struct outstanding_packet_lookup *next;
450
451         for (list = data->outstanding_packet_list; list; list = next) {
452                 next = list->next;
453                 DLIST_REMOVE(data->outstanding_packet_list, list);
454                 SAFE_FREE(list);
455         }
456
457         data_blob_free(&data->mac_key);
458
459         SAFE_FREE(si->signing_context);
460
461         return;
462 }
463
464 /***********************************************************
465  SMB signing - Simple implementation - setup the MAC key.
466 ************************************************************/
467
468 bool cli_simple_set_signing(struct cli_state *cli,
469                             const DATA_BLOB user_session_key,
470                             const DATA_BLOB response)
471 {
472         struct smb_basic_signing_context *data;
473
474         if (!user_session_key.length)
475                 return False;
476
477         if (!cli_set_smb_signing_common(cli)) {
478                 return False;
479         }
480
481         if (!set_smb_signing_real_common(&cli->sign_info)) {
482                 return False;
483         }
484
485         data = SMB_XMALLOC_P(struct smb_basic_signing_context);
486         memset(data, '\0', sizeof(*data));
487
488         cli->sign_info.signing_context = data;
489
490         data->mac_key = data_blob(NULL, response.length + user_session_key.length);
491
492         memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length);
493
494         DEBUG(10, ("cli_simple_set_signing: user_session_key\n"));
495         dump_data(10, user_session_key.data, user_session_key.length);
496
497         if (response.length) {
498                 memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
499                 DEBUG(10, ("cli_simple_set_signing: response_data\n"));
500                 dump_data(10, response.data, response.length);
501         } else {
502                 DEBUG(10, ("cli_simple_set_signing: NULL response_data\n"));
503         }
504
505         dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length);
506
507         /* Initialise the sequence number */
508         data->send_seq_num = 0;
509
510         /* Initialise the list of outstanding packets */
511         data->outstanding_packet_list = NULL;
512
513         cli->sign_info.sign_outgoing_message = client_sign_outgoing_message;
514         cli->sign_info.check_incoming_message = client_check_incoming_message;
515         cli->sign_info.free_signing_context = simple_free_signing_context;
516
517         return True;
518 }
519
520 /***********************************************************
521  SMB signing - TEMP implementation - calculate a MAC to send.
522 ************************************************************/
523
524 static void temp_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
525 {
526         /* mark the packet as signed - BEFORE we sign it...*/
527         mark_packet_signed(outbuf);
528
529         /* I wonder what BSRSPYL stands for - but this is what MS 
530            actually sends! */
531         memcpy(&outbuf[smb_ss_field], "BSRSPYL ", 8);
532         return;
533 }
534
535 /***********************************************************
536  SMB signing - TEMP implementation - check a MAC sent by server.
537 ************************************************************/
538
539 static bool temp_check_incoming_message(const char *inbuf,
540                                         struct smb_sign_info *si, bool foo)
541 {
542         return True;
543 }
544
545 /***********************************************************
546  SMB signing - TEMP implementation - free signing context
547 ************************************************************/
548
549 static void temp_free_signing_context(struct smb_sign_info *si)
550 {
551         return;
552 }
553
554 /***********************************************************
555  SMB signing - NULL implementation - setup the MAC key.
556 ************************************************************/
557
558 bool cli_null_set_signing(struct cli_state *cli)
559 {
560         return null_set_signing(&cli->sign_info);
561 }
562
563 /***********************************************************
564  SMB signing - temp implementation - setup the MAC key.
565 ************************************************************/
566
567 bool cli_temp_set_signing(struct cli_state *cli)
568 {
569         if (!cli_set_smb_signing_common(cli)) {
570                 return False;
571         }
572
573         cli->sign_info.signing_context = NULL;
574
575         cli->sign_info.sign_outgoing_message = temp_sign_outgoing_message;
576         cli->sign_info.check_incoming_message = temp_check_incoming_message;
577         cli->sign_info.free_signing_context = temp_free_signing_context;
578
579         return True;
580 }
581
582 void cli_free_signing_context(struct cli_state *cli)
583 {
584         free_signing_context(&cli->sign_info);
585 }
586
587 /**
588  * Sign a packet with the current mechanism
589  */
590
591 void cli_calculate_sign_mac(struct cli_state *cli, char *buf)
592 {
593         cli->sign_info.sign_outgoing_message(buf, &cli->sign_info);
594 }
595
596 /**
597  * Check a packet with the current mechanism
598  * @return False if we had an established signing connection
599  *         which had a bad checksum, True otherwise.
600  */
601
602 bool cli_check_sign_mac(struct cli_state *cli, char *buf)
603 {
604         if (!cli->sign_info.check_incoming_message(buf, &cli->sign_info, True)) {
605                 free_signing_context(&cli->sign_info);  
606                 return False;
607         }
608         return True;
609 }
610
611 /***********************************************************
612  Enter trans/trans2/nttrans state.
613 ************************************************************/
614
615 bool client_set_trans_sign_state_on(struct cli_state *cli, uint16 mid)
616 {
617         struct smb_sign_info *si = &cli->sign_info;
618         struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context;
619
620         if (!si->doing_signing) {
621                 return True;
622         }
623
624         if (!data) {
625                 return False;
626         }
627
628         if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, False)) {
629                 return False;
630         }
631
632         return True;
633 }
634
635 /***********************************************************
636  Leave trans/trans2/nttrans state.
637 ************************************************************/
638
639 bool client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid)
640 {
641         uint32 reply_seq_num;
642         struct smb_sign_info *si = &cli->sign_info;
643         struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context;
644
645         if (!si->doing_signing) {
646                 return True;
647         }
648
649         if (!data) {
650                 return False;
651         }
652
653         if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, True)) {
654                 return False;
655         }
656
657         /* Now delete the stored mid entry. */
658         if (!get_sequence_for_reply(&data->outstanding_packet_list, mid, &reply_seq_num)) {
659                 return False;
660         }
661
662         return True;
663 }
664
665 /***********************************************************
666  Is client signing on ?
667 ************************************************************/
668
669 bool client_is_signing_on(struct cli_state *cli)
670 {
671         struct smb_sign_info *si = &cli->sign_info;
672         return si->doing_signing;
673 }