2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2003.
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
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.
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.
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.
24 /* Lookup a packet's MID (multiplex id) and figure out it's sequence number */
25 struct outstanding_packet_lookup {
28 struct outstanding_packet_lookup *prev, *next;
31 struct smb_basic_signing_context {
34 struct outstanding_packet_lookup *outstanding_packet_list;
37 static void store_sequence_for_reply(struct outstanding_packet_lookup **list,
38 uint16 mid, uint32 reply_seq_num)
40 struct outstanding_packet_lookup *t;
41 struct outstanding_packet_lookup *tmp;
43 t = smb_xmalloc(sizeof(*t));
46 DLIST_ADD_END(*list, t, tmp);
48 t->reply_seq_num = reply_seq_num;
51 static BOOL get_sequence_for_reply(struct outstanding_packet_lookup **list,
52 uint16 mid, uint32 *reply_seq_num)
54 struct outstanding_packet_lookup *t;
56 for (t = *list; t; t = t->next) {
58 *reply_seq_num = t->reply_seq_num;
59 DLIST_REMOVE(*list, t);
64 DEBUG(0, ("Unexpected incoming packet, it's MID (%u) does not match"
65 " a MID in our outstanding list!\n", mid));
69 /***********************************************************
70 SMB signing - Common code before we set a new signing implementation
71 ************************************************************/
73 static BOOL cli_set_smb_signing_common(struct cli_state *cli)
75 if (!cli->sign_info.negotiated_smb_signing
76 && !cli->sign_info.mandatory_signing) {
80 if (cli->sign_info.doing_signing) {
84 if (cli->sign_info.free_signing_context)
85 cli->sign_info.free_signing_context(&cli->sign_info);
87 /* These calls are INCOMPATIBLE with SMB signing */
88 cli->readbraw_supported = False;
89 cli->writebraw_supported = False;
94 /***********************************************************
95 SMB signing - Common code for 'real' implementations
96 ************************************************************/
98 static BOOL set_smb_signing_real_common(struct smb_sign_info *si)
100 if (si->mandatory_signing) {
101 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
102 si->doing_signing = True;
105 DEBUG(5, ("SMB signing enabled!\n"));
110 static void mark_packet_signed(char *outbuf)
113 flags2 = SVAL(outbuf,smb_flg2);
114 flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
115 SSVAL(outbuf,smb_flg2, flags2);
118 /***********************************************************
119 SMB signing - NULL implementation - calculate a MAC to send.
120 ************************************************************/
122 static void null_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
124 /* we can't zero out the sig, as we might be trying to send a
125 session request - which is NBT-level, not SMB level and doesn't
130 /***********************************************************
131 SMB signing - NULL implementation - check a MAC sent by server.
132 ************************************************************/
134 static BOOL null_check_incoming_message(char *inbuf, struct smb_sign_info *si)
139 /***********************************************************
140 SMB signing - NULL implementation - free signing context
141 ************************************************************/
143 static void null_free_signing_context(struct smb_sign_info *si)
149 SMB signing - NULL implementation - setup the MAC key.
151 @note Used as an initialisation only - it will not correctly
152 shut down a real signing mechanism
155 static BOOL null_set_signing(struct smb_sign_info *si)
157 si->signing_context = NULL;
159 si->sign_outgoing_message = null_sign_outgoing_message;
160 si->check_incoming_message = null_check_incoming_message;
161 si->free_signing_context = null_free_signing_context;
167 * Free the signing context
170 static void free_signing_context(struct smb_sign_info *si)
172 if (si->free_signing_context) {
173 si->free_signing_context(si);
174 si->signing_context = NULL;
177 null_set_signing(si);
181 static BOOL signing_good(char *inbuf, struct smb_sign_info *si, BOOL good)
183 DEBUG(10, ("signing_good: got SMB signature of\n"));
184 dump_data(10,&inbuf[smb_ss_field] , 8);
186 if (good && !si->doing_signing) {
187 si->doing_signing = True;
191 if (si->doing_signing) {
192 DEBUG(1, ("SMB signature check failed!\n"));
195 DEBUG(3, ("Server did not sign reply correctly\n"));
196 free_signing_context(si);
203 /***********************************************************
204 SMB signing - Simple implementation - calculate a MAC on the packet
205 ************************************************************/
207 static void simple_packet_signature(struct smb_basic_signing_context *data,
208 const uchar *buf, uint32 seq_number,
209 unsigned char calc_md5_mac[16])
211 const size_t offset_end_of_sig = (smb_ss_field + 8);
212 unsigned char sequence_buf[8];
213 struct MD5Context md5_ctx;
216 * Firstly put the sequence number into the first 4 bytes.
217 * and zero out the next 4 bytes.
219 * We do this here, to avoid modifying the packet.
222 DEBUG(10,("simple_packet_signature: sequence number %u\n", seq_number ));
224 SIVAL(sequence_buf, 0, seq_number);
225 SIVAL(sequence_buf, 4, 0);
227 /* Calculate the 16 byte MAC - but don't alter the data in the
230 This makes for a bit for fussing about, but it's not too bad.
234 /* intialise with the key */
235 MD5Update(&md5_ctx, data->mac_key.data,
236 data->mac_key.length);
238 /* copy in the first bit of the SMB header */
239 MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4);
241 /* copy in the sequence number, instead of the signature */
242 MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
244 /* copy in the rest of the packet in, skipping the signature */
245 MD5Update(&md5_ctx, buf + offset_end_of_sig,
246 smb_len(buf) - (offset_end_of_sig - 4));
248 /* calculate the MD5 sig */
249 MD5Final(calc_md5_mac, &md5_ctx);
253 /***********************************************************
254 SMB signing - Client implementation - send the MAC.
255 ************************************************************/
257 static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
259 unsigned char calc_md5_mac[16];
260 struct smb_basic_signing_context *data = si->signing_context;
262 if (!si->doing_signing)
265 /* JRA Paranioa test - we should be able to get rid of this... */
266 if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
267 DEBUG(1, ("client_sign_outgoing_message: Logic error. Can't check signature on short packet! smb_len = %u\n",
272 /* mark the packet as signed - BEFORE we sign it...*/
273 mark_packet_signed(outbuf);
275 simple_packet_signature(data, outbuf, data->send_seq_num, calc_md5_mac);
277 DEBUG(10, ("client_sign_outgoing_message: sent SMB signature of\n"));
278 dump_data(10, calc_md5_mac, 8);
280 memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
282 /* cli->outbuf[smb_ss_field+2]=0;
283 Uncomment this to test if the remote server actually verifies signatures...*/
285 data->send_seq_num++;
286 store_sequence_for_reply(&data->outstanding_packet_list,
287 SVAL(outbuf,smb_mid),
289 data->send_seq_num++;
292 /***********************************************************
293 SMB signing - Client implementation - check a MAC sent by server.
294 ************************************************************/
296 static BOOL client_check_incoming_message(char *inbuf, struct smb_sign_info *si)
299 uint32 reply_seq_number;
300 unsigned char calc_md5_mac[16];
301 unsigned char *server_sent_mac;
303 struct smb_basic_signing_context *data = si->signing_context;
305 if (!si->doing_signing)
308 if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
309 DEBUG(1, ("client_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf)));
313 if (!get_sequence_for_reply(&data->outstanding_packet_list,
314 SVAL(inbuf, smb_mid),
315 &reply_seq_number)) {
319 simple_packet_signature(data, inbuf, reply_seq_number, calc_md5_mac);
321 server_sent_mac = &inbuf[smb_ss_field];
322 good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
325 DEBUG(5, ("client_check_incoming_message: BAD SIG: wanted SMB signature of\n"));
326 dump_data(5, calc_md5_mac, 8);
328 DEBUG(5, ("client_check_incoming_message: BAD SIG: got SMB signature of\n"));
329 dump_data(5, server_sent_mac, 8);
331 return signing_good(inbuf, si, good);
334 /***********************************************************
335 SMB signing - Simple implementation - free signing context
336 ************************************************************/
338 static void simple_free_signing_context(struct smb_sign_info *si)
340 struct smb_basic_signing_context *data = si->signing_context;
341 struct outstanding_packet_lookup *list = data->outstanding_packet_list;
344 struct outstanding_packet_lookup *old_head = list;
345 DLIST_REMOVE(list, list);
349 data_blob_free(&data->mac_key);
350 SAFE_FREE(si->signing_context);
355 /***********************************************************
356 SMB signing - Simple implementation - setup the MAC key.
357 ************************************************************/
359 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
361 struct smb_basic_signing_context *data;
363 if (!user_session_key)
366 if (!cli_set_smb_signing_common(cli)) {
370 if (!set_smb_signing_real_common(&cli->sign_info)) {
374 data = smb_xmalloc(sizeof(*data));
376 cli->sign_info.signing_context = data;
378 data->mac_key = data_blob(NULL, response.length + 16);
380 memcpy(&data->mac_key.data[0], user_session_key, 16);
382 DEBUG(10, ("cli_simple_set_signing: user_session_key\n"));
383 dump_data(10, user_session_key, 16);
385 if (response.length) {
386 memcpy(&data->mac_key.data[16],response.data, response.length);
387 DEBUG(10, ("cli_simple_set_signing: response_data\n"));
388 dump_data(10, response.data, response.length);
390 DEBUG(10, ("cli_simple_set_signing: NULL response_data\n"));
393 /* Initialise the sequence number */
394 data->send_seq_num = 0;
396 /* Initialise the list of outstanding packets */
397 data->outstanding_packet_list = NULL;
399 cli->sign_info.sign_outgoing_message = client_sign_outgoing_message;
400 cli->sign_info.check_incoming_message = client_check_incoming_message;
401 cli->sign_info.free_signing_context = simple_free_signing_context;
406 /***********************************************************
407 SMB signing - TEMP implementation - calculate a MAC to send.
408 ************************************************************/
410 static void temp_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
412 /* mark the packet as signed - BEFORE we sign it...*/
413 mark_packet_signed(outbuf);
415 /* I wonder what BSRSPYL stands for - but this is what MS
417 memcpy(&outbuf[smb_ss_field], "BSRSPYL ", 8);
421 /***********************************************************
422 SMB signing - TEMP implementation - check a MAC sent by server.
423 ************************************************************/
425 static BOOL temp_check_incoming_message(char *inbuf, struct smb_sign_info *si)
430 /***********************************************************
431 SMB signing - TEMP implementation - free signing context
432 ************************************************************/
434 static void temp_free_signing_context(struct smb_sign_info *si)
439 /***********************************************************
440 SMB signing - NULL implementation - setup the MAC key.
441 ************************************************************/
443 BOOL cli_null_set_signing(struct cli_state *cli)
445 return null_set_signing(&cli->sign_info);
448 /***********************************************************
449 SMB signing - temp implementation - setup the MAC key.
450 ************************************************************/
452 BOOL cli_temp_set_signing(struct cli_state *cli)
454 if (!cli_set_smb_signing_common(cli)) {
458 cli->sign_info.signing_context = NULL;
460 cli->sign_info.sign_outgoing_message = temp_sign_outgoing_message;
461 cli->sign_info.check_incoming_message = temp_check_incoming_message;
462 cli->sign_info.free_signing_context = temp_free_signing_context;
467 void cli_free_signing_context(struct cli_state *cli)
469 free_signing_context(&cli->sign_info);
473 * Sign a packet with the current mechanism
476 void cli_calculate_sign_mac(struct cli_state *cli)
478 cli->sign_info.sign_outgoing_message(cli->outbuf, &cli->sign_info);
482 * Check a packet with the current mechanism
483 * @return False if we had an established signing connection
484 * which had a bad checksum, True otherwise.
487 BOOL cli_check_sign_mac(struct cli_state *cli)
489 if (!cli->sign_info.check_incoming_message(cli->inbuf, &cli->sign_info)) {
490 free_signing_context(&cli->sign_info);
496 /***********************************************************
497 SMB signing - Server implementation - send the MAC.
498 ************************************************************/
500 static void srv_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
502 unsigned char calc_md5_mac[16];
503 struct smb_basic_signing_context *data = si->signing_context;
505 if (!si->doing_signing)
508 /* JRA Paranioa test - we should be able to get rid of this... */
509 if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
510 DEBUG(1, ("srv_sign_outgoing_message: Logic error. Can't check signature on short packet! smb_len = %u\n",
515 /* mark the packet as signed - BEFORE we sign it...*/
516 mark_packet_signed(outbuf);
518 simple_packet_signature(data, outbuf, data->send_seq_num, calc_md5_mac);
520 DEBUG(10, ("srv_sign_outgoing_message: sent SMB signature of\n"));
521 dump_data(10, calc_md5_mac, 8);
523 memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
525 /* cli->outbuf[smb_ss_field+2]=0;
526 Uncomment this to test if the remote server actually verifies signatures...*/
528 data->send_seq_num++;
530 store_sequence_for_reply(&data->outstanding_packet_list,
531 SVAL(outbuf,smb_mid),
533 data->send_seq_num++;
537 /***********************************************************
538 SMB signing - Server implementation - check a MAC sent by server.
539 ************************************************************/
541 static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si)
544 uint32 reply_seq_number;
545 unsigned char calc_md5_mac[16];
546 unsigned char *server_sent_mac;
548 struct smb_basic_signing_context *data = si->signing_context;
550 if (!si->doing_signing)
553 if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
554 DEBUG(1, ("srv_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf)));
559 if (!get_sequence_for_reply(&data->outstanding_packet_list,
560 SVAL(inbuf, smb_mid),
561 &reply_seq_number)) {
565 reply_seq_number = data->send_seq_num;
566 data->send_seq_num++;
569 simple_packet_signature(data, inbuf, reply_seq_number, calc_md5_mac);
571 server_sent_mac = &inbuf[smb_ss_field];
572 good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
575 DEBUG(5, ("srv_check_incoming_message: BAD SIG: wanted SMB signature of\n"));
576 dump_data(5, calc_md5_mac, 8);
578 DEBUG(5, ("srv_check_incoming_message: BAD SIG: got SMB signature of\n"));
579 dump_data(5, server_sent_mac, 8);
581 return signing_good(inbuf, si, good);
584 /***********************************************************
585 SMB signing - server API's.
586 ************************************************************/
588 static struct smb_sign_info srv_sign_info = {
589 null_sign_outgoing_message,
590 null_check_incoming_message,
591 null_free_signing_context,
599 /***********************************************************
600 Turn signing off or on for oplock break code.
601 ************************************************************/
603 BOOL srv_oplock_set_signing(BOOL onoff)
605 BOOL ret = srv_sign_info.doing_signing;
606 srv_sign_info.doing_signing = onoff;
610 /***********************************************************
611 Called to validate an incoming packet from the client.
612 ************************************************************/
614 BOOL srv_check_sign_mac(char *inbuf)
616 /* Check if it's a session keepalive. */
617 if(CVAL(inbuf,0) == SMBkeepalive)
620 return srv_sign_info.check_incoming_message(inbuf, &srv_sign_info);
623 /***********************************************************
624 Called to sign an outgoing packet to the client.
625 ************************************************************/
627 void srv_calculate_sign_mac(char *outbuf)
629 /* Check if it's a session keepalive. */
630 /* JRA Paranioa test - do we ever generate these in the server ? */
631 if(CVAL(outbuf,0) == SMBkeepalive)
634 srv_sign_info.sign_outgoing_message(outbuf, &srv_sign_info);
637 /***********************************************************
638 Called by server negprot when signing has been negotiated.
639 ************************************************************/
641 void srv_set_signing_negotiated(void)
643 srv_sign_info.allow_smb_signing = True;
644 srv_sign_info.negotiated_smb_signing = True;
645 if (lp_server_signing() == Required)
646 srv_sign_info.mandatory_signing = True;
648 srv_sign_info.sign_outgoing_message = temp_sign_outgoing_message;
649 srv_sign_info.check_incoming_message = temp_check_incoming_message;
650 srv_sign_info.free_signing_context = temp_free_signing_context;
653 /***********************************************************
654 Returns whether signing is active. We can't use sendfile or raw
655 reads/writes if it is.
656 ************************************************************/
658 BOOL srv_is_signing_active(void)
660 return srv_sign_info.doing_signing;
663 /***********************************************************
664 Turn on signing from this packet onwards.
665 ************************************************************/
667 void srv_set_signing(const uchar user_session_key[16], const DATA_BLOB response)
669 struct smb_basic_signing_context *data;
671 if (!user_session_key)
674 if (!srv_sign_info.negotiated_smb_signing && !srv_sign_info.mandatory_signing) {
675 DEBUG(5,("srv_set_signing: signing negotiated = %u, mandatory_signing = %u. Not allowing smb signing.\n",
676 (unsigned int)srv_sign_info.negotiated_smb_signing,
677 (unsigned int)srv_sign_info.mandatory_signing ));
681 /* Once we've turned on, ignore any more sessionsetups. */
682 if (srv_sign_info.doing_signing) {
686 if (srv_sign_info.free_signing_context)
687 srv_sign_info.free_signing_context(&srv_sign_info);
689 srv_sign_info.doing_signing = True;
691 data = smb_xmalloc(sizeof(*data));
693 srv_sign_info.signing_context = data;
695 data->mac_key = data_blob(NULL, response.length + 16);
697 memcpy(&data->mac_key.data[0], user_session_key, 16);
699 memcpy(&data->mac_key.data[16],response.data, response.length);
701 /* Initialise the sequence number */
702 data->send_seq_num = 0;
704 /* Initialise the list of outstanding packets */
705 data->outstanding_packet_list = NULL;
707 srv_sign_info.sign_outgoing_message = srv_sign_outgoing_message;
708 srv_sign_info.check_incoming_message = srv_check_incoming_message;
709 srv_sign_info.free_signing_context = simple_free_signing_context;