2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2002.
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);
63 DEBUG(0, ("Unexpected incoming packet, it's MID (%u) does not match"
64 " a MID in our outstanding list!\n", mid));
68 /***********************************************************
69 SMB signing - Common code before we set a new signing implementation
70 ************************************************************/
72 static BOOL cli_set_smb_signing_common(struct cli_state *cli)
74 if (!cli->sign_info.negotiated_smb_signing
75 && !cli->sign_info.mandatory_signing) {
79 if (cli->sign_info.doing_signing) {
83 if (cli->sign_info.free_signing_context)
84 cli->sign_info.free_signing_context(&cli->sign_info);
86 /* These calls are INCOMPATIBLE with SMB signing */
87 cli->readbraw_supported = False;
88 cli->writebraw_supported = False;
93 /***********************************************************
94 SMB signing - Common code for 'real' implementations
95 ************************************************************/
97 static BOOL set_smb_signing_real_common(struct smb_sign_info *si)
99 if (si->mandatory_signing) {
100 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
101 si->doing_signing = True;
104 DEBUG(5, ("SMB signing enabled!\n"));
109 static void mark_packet_signed(char *outbuf)
112 flags2 = SVAL(outbuf,smb_flg2);
113 flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
114 SSVAL(outbuf,smb_flg2, flags2);
117 /***********************************************************
118 SMB signing - NULL implementation - calculate a MAC to send.
119 ************************************************************/
121 static void null_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
123 /* we can't zero out the sig, as we might be trying to send a
124 session request - which is NBT-level, not SMB level and doesn't
129 /***********************************************************
130 SMB signing - NULL implementation - check a MAC sent by server.
131 ************************************************************/
133 static BOOL null_check_incoming_message(char *inbuf, struct smb_sign_info *si)
138 /***********************************************************
139 SMB signing - NULL implementation - free signing context
140 ************************************************************/
142 static void null_free_signing_context(struct smb_sign_info *si)
148 SMB signing - NULL implementation - setup the MAC key.
150 @note Used as an initialisation only - it will not correctly
151 shut down a real signing mechanism
154 static BOOL null_set_signing(struct smb_sign_info *si)
156 si->signing_context = NULL;
158 si->sign_outgoing_message = null_sign_outgoing_message;
159 si->check_incoming_message = null_check_incoming_message;
160 si->free_signing_context = null_free_signing_context;
166 * Free the signing context
169 static void free_signing_context(struct smb_sign_info *si)
171 if (si->free_signing_context) {
172 si->free_signing_context(si);
173 si->signing_context = NULL;
176 null_set_signing(si);
180 static BOOL signing_good(char *inbuf, struct smb_sign_info *si, BOOL good)
182 DEBUG(10, ("got SMB signature of\n"));
183 dump_data(10,&inbuf[smb_ss_field] , 8);
185 if (good && !si->doing_signing) {
186 si->doing_signing = True;
190 if (si->doing_signing) {
191 DEBUG(1, ("SMB signature check failed!\n"));
194 DEBUG(3, ("Server did not sign reply correctly\n"));
195 free_signing_context(si);
202 /***********************************************************
203 SMB signing - Simple implementation - calculate a MAC on the packet
204 ************************************************************/
206 static void simple_packet_signature(struct smb_basic_signing_context *data,
207 const uchar *buf, uint32 seq_number,
208 unsigned char calc_md5_mac[16])
210 const size_t offset_end_of_sig = (smb_ss_field + 8);
211 unsigned char sequence_buf[8];
212 struct MD5Context md5_ctx;
215 * Firstly put the sequence number into the first 4 bytes.
216 * and zero out the next 4 bytes.
218 * We do this here, to avoid modifying the packet.
221 SIVAL(sequence_buf, 0, seq_number);
222 SIVAL(sequence_buf, 4, 0);
224 /* Calculate the 16 byte MAC - but don't alter the data in the
227 This makes for a bit for fussing about, but it's not too bad.
231 /* intialise with the key */
232 MD5Update(&md5_ctx, data->mac_key.data,
233 data->mac_key.length);
235 /* copy in the first bit of the SMB header */
236 MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4);
238 /* copy in the sequence number, instead of the signature */
239 MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
241 /* copy in the rest of the packet in, skipping the signature */
242 MD5Update(&md5_ctx, buf + offset_end_of_sig,
243 smb_len(buf) - (offset_end_of_sig - 4));
245 /* calculate the MD5 sig */
246 MD5Final(calc_md5_mac, &md5_ctx);
250 /***********************************************************
251 SMB signing - Simple implementation - send the MAC.
252 ************************************************************/
254 static void cli_simple_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
256 unsigned char calc_md5_mac[16];
257 struct smb_basic_signing_context *data = si->signing_context;
259 /* mark the packet as signed - BEFORE we sign it...*/
260 mark_packet_signed(outbuf);
262 simple_packet_signature(data, outbuf, data->send_seq_num, calc_md5_mac);
264 DEBUG(10, ("sent SMB signature of\n"));
265 dump_data(10, calc_md5_mac, 8);
267 memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
269 /* cli->outbuf[smb_ss_field+2]=0;
270 Uncomment this to test if the remote server actually verifies signatures...*/
272 data->send_seq_num++;
273 store_sequence_for_reply(&data->outstanding_packet_list,
274 SVAL(outbuf,smb_mid),
276 data->send_seq_num++;
279 /***********************************************************
280 SMB signing - Simple implementation - check a MAC sent by server.
281 ************************************************************/
283 static BOOL cli_simple_check_incoming_message(char *inbuf, struct smb_sign_info *si)
286 uint32 reply_seq_number;
287 unsigned char calc_md5_mac[16];
288 unsigned char *server_sent_mac;
290 struct smb_basic_signing_context *data = si->signing_context;
292 if (!get_sequence_for_reply(&data->outstanding_packet_list,
293 SVAL(inbuf, smb_mid),
294 &reply_seq_number)) {
298 simple_packet_signature(data, inbuf, reply_seq_number, calc_md5_mac);
300 server_sent_mac = &inbuf[smb_ss_field];
301 good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
304 DEBUG(5, ("BAD SIG: wanted SMB signature of\n"));
305 dump_data(5, calc_md5_mac, 8);
307 DEBUG(5, ("BAD SIG: got SMB signature of\n"));
308 dump_data(5, server_sent_mac, 8);
310 return signing_good(inbuf, si, good);
313 /***********************************************************
314 SMB signing - Simple implementation - free signing context
315 ************************************************************/
317 static void cli_simple_free_signing_context(struct smb_sign_info *si)
319 struct smb_basic_signing_context *data = si->signing_context;
320 struct outstanding_packet_lookup *list = data->outstanding_packet_list;
323 struct outstanding_packet_lookup *old_head = list;
324 DLIST_REMOVE(list, list);
328 data_blob_free(&data->mac_key);
329 SAFE_FREE(si->signing_context);
334 /***********************************************************
335 SMB signing - Simple implementation - setup the MAC key.
336 ************************************************************/
338 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
340 struct smb_basic_signing_context *data;
342 if (!user_session_key)
345 if (!cli_set_smb_signing_common(cli)) {
349 if (!set_smb_signing_real_common(&cli->sign_info)) {
353 data = smb_xmalloc(sizeof(*data));
355 cli->sign_info.signing_context = data;
357 data->mac_key = data_blob(NULL, response.length + 16);
359 memcpy(&data->mac_key.data[0], user_session_key, 16);
360 memcpy(&data->mac_key.data[16],response.data, response.length);
362 /* Initialise the sequence number */
363 data->send_seq_num = 0;
365 /* Initialise the list of outstanding packets */
366 data->outstanding_packet_list = NULL;
368 cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
369 cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
370 cli->sign_info.free_signing_context = cli_simple_free_signing_context;
375 /***********************************************************
376 SMB signing - TEMP implementation - calculate a MAC to send.
377 ************************************************************/
379 static void cli_temp_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
381 /* mark the packet as signed - BEFORE we sign it...*/
382 mark_packet_signed(outbuf);
384 /* I wonder what BSRSPYL stands for - but this is what MS
386 memcpy(&outbuf[smb_ss_field], "BSRSPYL ", 8);
390 /***********************************************************
391 SMB signing - TEMP implementation - check a MAC sent by server.
392 ************************************************************/
394 static BOOL cli_temp_check_incoming_message(char *inbuf, struct smb_sign_info *si)
399 /***********************************************************
400 SMB signing - TEMP implementation - free signing context
401 ************************************************************/
403 static void cli_temp_free_signing_context(struct smb_sign_info *si)
408 /***********************************************************
409 SMB signing - NULL implementation - setup the MAC key.
410 ************************************************************/
412 BOOL cli_null_set_signing(struct cli_state *cli)
414 return null_set_signing(&cli->sign_info);
417 /***********************************************************
418 SMB signing - temp implementation - setup the MAC key.
419 ************************************************************/
421 BOOL cli_temp_set_signing(struct cli_state *cli)
423 if (!cli_set_smb_signing_common(cli)) {
427 cli->sign_info.signing_context = NULL;
429 cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
430 cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
431 cli->sign_info.free_signing_context = cli_temp_free_signing_context;
436 void cli_free_signing_context(struct cli_state *cli)
438 free_signing_context(&cli->sign_info);
442 * Sign a packet with the current mechanism
445 void cli_calculate_sign_mac(struct cli_state *cli)
447 cli->sign_info.sign_outgoing_message(cli->outbuf, &cli->sign_info);
451 * Check a packet with the current mechanism
452 * @return False if we had an established signing connection
453 * which had a back checksum, True otherwise
456 BOOL cli_check_sign_mac(struct cli_state *cli)
460 if (smb_len(cli->inbuf) < (smb_ss_field + 8 - 4)) {
461 DEBUG(cli->sign_info.doing_signing ? 1 : 10, ("Can't check signature on short packet! smb_len = %u\n", smb_len(cli->inbuf)));
464 good = cli->sign_info.check_incoming_message(cli->inbuf, &cli->sign_info);
468 if (cli->sign_info.doing_signing) {
471 free_signing_context(&cli->sign_info);
478 /***********************************************************
479 SMB signing - server API's.
480 ************************************************************/
482 void srv_enable_signing(void)
486 void srv_disable_signing(void)
490 BOOL srv_check_sign_mac(char *buf)
495 void srv_calculate_sign_mac(char *buf)
499 BOOL allow_sendfile(void)