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 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 | /* Lookup a packet's MID (multiplex id) and figure out it's sequence number */
|
---|
25 | struct outstanding_packet_lookup {
|
---|
26 | struct outstanding_packet_lookup *prev, *next;
|
---|
27 | uint16 mid;
|
---|
28 | uint32 reply_seq_num;
|
---|
29 | BOOL can_delete; /* Set to False in trans state. */
|
---|
30 | };
|
---|
31 |
|
---|
32 | struct smb_basic_signing_context {
|
---|
33 | DATA_BLOB mac_key;
|
---|
34 | uint32 send_seq_num;
|
---|
35 | struct outstanding_packet_lookup *outstanding_packet_list;
|
---|
36 | };
|
---|
37 |
|
---|
38 | static BOOL store_sequence_for_reply(struct outstanding_packet_lookup **list,
|
---|
39 | uint16 mid, uint32 reply_seq_num)
|
---|
40 | {
|
---|
41 | struct outstanding_packet_lookup *t;
|
---|
42 |
|
---|
43 | /* Ensure we only add a mid once. */
|
---|
44 | for (t = *list; t; t = t->next) {
|
---|
45 | if (t->mid == mid) {
|
---|
46 | return False;
|
---|
47 | }
|
---|
48 | }
|
---|
49 |
|
---|
50 | t = SMB_XMALLOC_P(struct outstanding_packet_lookup);
|
---|
51 | ZERO_STRUCTP(t);
|
---|
52 |
|
---|
53 | t->mid = mid;
|
---|
54 | t->reply_seq_num = reply_seq_num;
|
---|
55 | t->can_delete = True;
|
---|
56 |
|
---|
57 | /*
|
---|
58 | * Add to the *start* of the list not the end of the list.
|
---|
59 | * This ensures that the *last* send sequence with this mid
|
---|
60 | * is returned by preference.
|
---|
61 | * This can happen if the mid wraps and one of the early
|
---|
62 | * mid numbers didn't get a reply and is still lurking on
|
---|
63 | * the list. JRA. Found by Fran Fabrizio <fran@cis.uab.edu>.
|
---|
64 | */
|
---|
65 |
|
---|
66 | DLIST_ADD(*list, t);
|
---|
67 | DEBUG(10,("store_sequence_for_reply: stored seq = %u mid = %u\n",
|
---|
68 | (unsigned int)reply_seq_num, (unsigned int)mid ));
|
---|
69 | return True;
|
---|
70 | }
|
---|
71 |
|
---|
72 | static BOOL get_sequence_for_reply(struct outstanding_packet_lookup **list,
|
---|
73 | uint16 mid, uint32 *reply_seq_num)
|
---|
74 | {
|
---|
75 | struct outstanding_packet_lookup *t;
|
---|
76 |
|
---|
77 | for (t = *list; t; t = t->next) {
|
---|
78 | if (t->mid == mid) {
|
---|
79 | *reply_seq_num = t->reply_seq_num;
|
---|
80 | DEBUG(10,("get_sequence_for_reply: found seq = %u mid = %u\n",
|
---|
81 | (unsigned int)t->reply_seq_num, (unsigned int)t->mid ));
|
---|
82 | if (t->can_delete) {
|
---|
83 | DLIST_REMOVE(*list, t);
|
---|
84 | SAFE_FREE(t);
|
---|
85 | }
|
---|
86 | return True;
|
---|
87 | }
|
---|
88 | }
|
---|
89 | return False;
|
---|
90 | }
|
---|
91 |
|
---|
92 | static BOOL set_sequence_can_delete_flag(struct outstanding_packet_lookup **list, uint16 mid, BOOL can_delete_entry)
|
---|
93 | {
|
---|
94 | struct outstanding_packet_lookup *t;
|
---|
95 |
|
---|
96 | for (t = *list; t; t = t->next) {
|
---|
97 | if (t->mid == mid) {
|
---|
98 | t->can_delete = can_delete_entry;
|
---|
99 | return True;
|
---|
100 | }
|
---|
101 | }
|
---|
102 | return False;
|
---|
103 | }
|
---|
104 |
|
---|
105 | /***********************************************************
|
---|
106 | SMB signing - Common code before we set a new signing implementation
|
---|
107 | ************************************************************/
|
---|
108 |
|
---|
109 | static BOOL cli_set_smb_signing_common(struct cli_state *cli)
|
---|
110 | {
|
---|
111 | if (!cli->sign_info.allow_smb_signing) {
|
---|
112 | return False;
|
---|
113 | }
|
---|
114 |
|
---|
115 | if (!cli->sign_info.negotiated_smb_signing
|
---|
116 | && !cli->sign_info.mandatory_signing) {
|
---|
117 | return False;
|
---|
118 | }
|
---|
119 |
|
---|
120 | if (cli->sign_info.doing_signing) {
|
---|
121 | return False;
|
---|
122 | }
|
---|
123 |
|
---|
124 | if (cli->sign_info.free_signing_context)
|
---|
125 | cli->sign_info.free_signing_context(&cli->sign_info);
|
---|
126 |
|
---|
127 | /* These calls are INCOMPATIBLE with SMB signing */
|
---|
128 | cli->readbraw_supported = False;
|
---|
129 | cli->writebraw_supported = False;
|
---|
130 |
|
---|
131 | return True;
|
---|
132 | }
|
---|
133 |
|
---|
134 | /***********************************************************
|
---|
135 | SMB signing - Common code for 'real' implementations
|
---|
136 | ************************************************************/
|
---|
137 |
|
---|
138 | static BOOL set_smb_signing_real_common(struct smb_sign_info *si)
|
---|
139 | {
|
---|
140 | if (si->mandatory_signing) {
|
---|
141 | DEBUG(5, ("Mandatory SMB signing enabled!\n"));
|
---|
142 | }
|
---|
143 |
|
---|
144 | si->doing_signing = True;
|
---|
145 | DEBUG(5, ("SMB signing enabled!\n"));
|
---|
146 |
|
---|
147 | return True;
|
---|
148 | }
|
---|
149 |
|
---|
150 | static void mark_packet_signed(char *outbuf)
|
---|
151 | {
|
---|
152 | uint16 flags2;
|
---|
153 | flags2 = SVAL(outbuf,smb_flg2);
|
---|
154 | flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
|
---|
155 | SSVAL(outbuf,smb_flg2, flags2);
|
---|
156 | }
|
---|
157 |
|
---|
158 | /***********************************************************
|
---|
159 | SMB signing - NULL implementation - calculate a MAC to send.
|
---|
160 | ************************************************************/
|
---|
161 |
|
---|
162 | static void null_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
|
---|
163 | {
|
---|
164 | /* we can't zero out the sig, as we might be trying to send a
|
---|
165 | session request - which is NBT-level, not SMB level and doesn't
|
---|
166 | have the field */
|
---|
167 | return;
|
---|
168 | }
|
---|
169 |
|
---|
170 | /***********************************************************
|
---|
171 | SMB signing - NULL implementation - check a MAC sent by server.
|
---|
172 | ************************************************************/
|
---|
173 |
|
---|
174 | static BOOL null_check_incoming_message(char *inbuf, struct smb_sign_info *si, BOOL must_be_ok)
|
---|
175 | {
|
---|
176 | return True;
|
---|
177 | }
|
---|
178 |
|
---|
179 | /***********************************************************
|
---|
180 | SMB signing - NULL implementation - free signing context
|
---|
181 | ************************************************************/
|
---|
182 |
|
---|
183 | static void null_free_signing_context(struct smb_sign_info *si)
|
---|
184 | {
|
---|
185 | return;
|
---|
186 | }
|
---|
187 |
|
---|
188 | /**
|
---|
189 | SMB signing - NULL implementation - setup the MAC key.
|
---|
190 |
|
---|
191 | @note Used as an initialisation only - it will not correctly
|
---|
192 | shut down a real signing mechanism
|
---|
193 | */
|
---|
194 |
|
---|
195 | static BOOL null_set_signing(struct smb_sign_info *si)
|
---|
196 | {
|
---|
197 | si->signing_context = NULL;
|
---|
198 |
|
---|
199 | si->sign_outgoing_message = null_sign_outgoing_message;
|
---|
200 | si->check_incoming_message = null_check_incoming_message;
|
---|
201 | si->free_signing_context = null_free_signing_context;
|
---|
202 |
|
---|
203 | return True;
|
---|
204 | }
|
---|
205 |
|
---|
206 | /**
|
---|
207 | * Free the signing context
|
---|
208 | */
|
---|
209 |
|
---|
210 | static void free_signing_context(struct smb_sign_info *si)
|
---|
211 | {
|
---|
212 | if (si->free_signing_context) {
|
---|
213 | si->free_signing_context(si);
|
---|
214 | si->signing_context = NULL;
|
---|
215 | }
|
---|
216 |
|
---|
217 | null_set_signing(si);
|
---|
218 | }
|
---|
219 |
|
---|
220 |
|
---|
221 | static BOOL signing_good(char *inbuf, struct smb_sign_info *si, BOOL good, uint32 seq, BOOL must_be_ok)
|
---|
222 | {
|
---|
223 | if (good) {
|
---|
224 |
|
---|
225 | if (!si->doing_signing) {
|
---|
226 | si->doing_signing = True;
|
---|
227 | }
|
---|
228 |
|
---|
229 | if (!si->seen_valid) {
|
---|
230 | si->seen_valid = True;
|
---|
231 | }
|
---|
232 |
|
---|
233 | } else {
|
---|
234 | if (!si->mandatory_signing && !si->seen_valid) {
|
---|
235 |
|
---|
236 | if (!must_be_ok) {
|
---|
237 | return True;
|
---|
238 | }
|
---|
239 | /* Non-mandatory signing - just turn off if this is the first bad packet.. */
|
---|
240 | DEBUG(5, ("srv_check_incoming_message: signing negotiated but not required and peer\n"
|
---|
241 | "isn't sending correct signatures. Turning off.\n"));
|
---|
242 | si->negotiated_smb_signing = False;
|
---|
243 | si->allow_smb_signing = False;
|
---|
244 | si->doing_signing = False;
|
---|
245 | free_signing_context(si);
|
---|
246 | return True;
|
---|
247 | } else if (!must_be_ok) {
|
---|
248 | /* This packet is known to be unsigned */
|
---|
249 | return True;
|
---|
250 | } else {
|
---|
251 | /* Mandatory signing or bad packet after signing started - fail and disconnect. */
|
---|
252 | if (seq)
|
---|
253 | DEBUG(0, ("signing_good: BAD SIG: seq %u\n", (unsigned int)seq));
|
---|
254 | return False;
|
---|
255 | }
|
---|
256 | }
|
---|
257 | return True;
|
---|
258 | }
|
---|
259 |
|
---|
260 | /***********************************************************
|
---|
261 | SMB signing - Simple implementation - calculate a MAC on the packet
|
---|
262 | ************************************************************/
|
---|
263 |
|
---|
264 | static void simple_packet_signature(struct smb_basic_signing_context *data,
|
---|
265 | const uchar *buf, uint32 seq_number,
|
---|
266 | unsigned char calc_md5_mac[16])
|
---|
267 | {
|
---|
268 | const size_t offset_end_of_sig = (smb_ss_field + 8);
|
---|
269 | unsigned char sequence_buf[8];
|
---|
270 | struct MD5Context md5_ctx;
|
---|
271 | #if 0
|
---|
272 | /* JRA - apparently this is incorrect. */
|
---|
273 | unsigned char key_buf[16];
|
---|
274 | #endif
|
---|
275 |
|
---|
276 | /*
|
---|
277 | * Firstly put the sequence number into the first 4 bytes.
|
---|
278 | * and zero out the next 4 bytes.
|
---|
279 | *
|
---|
280 | * We do this here, to avoid modifying the packet.
|
---|
281 | */
|
---|
282 |
|
---|
283 | DEBUG(10,("simple_packet_signature: sequence number %u\n", seq_number ));
|
---|
284 |
|
---|
285 | SIVAL(sequence_buf, 0, seq_number);
|
---|
286 | SIVAL(sequence_buf, 4, 0);
|
---|
287 |
|
---|
288 | /* Calculate the 16 byte MAC - but don't alter the data in the
|
---|
289 | incoming packet.
|
---|
290 |
|
---|
291 | This makes for a bit of fussing about, but it's not too bad.
|
---|
292 | */
|
---|
293 | MD5Init(&md5_ctx);
|
---|
294 |
|
---|
295 | /* intialise with the key */
|
---|
296 | MD5Update(&md5_ctx, data->mac_key.data, data->mac_key.length);
|
---|
297 | #if 0
|
---|
298 | /* JRA - apparently this is incorrect. */
|
---|
299 | /* NB. When making and verifying SMB signatures, Windows apparently
|
---|
300 | zero-pads the key to 128 bits if it isn't long enough.
|
---|
301 | From Nalin Dahyabhai <nalin@redhat.com> */
|
---|
302 | if (data->mac_key.length < sizeof(key_buf)) {
|
---|
303 | memset(key_buf, 0, sizeof(key_buf));
|
---|
304 | MD5Update(&md5_ctx, key_buf, sizeof(key_buf) - data->mac_key.length);
|
---|
305 | }
|
---|
306 | #endif
|
---|
307 |
|
---|
308 | /* copy in the first bit of the SMB header */
|
---|
309 | MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4);
|
---|
310 |
|
---|
311 | /* copy in the sequence number, instead of the signature */
|
---|
312 | MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
|
---|
313 |
|
---|
314 | /* copy in the rest of the packet in, skipping the signature */
|
---|
315 | MD5Update(&md5_ctx, buf + offset_end_of_sig,
|
---|
316 | smb_len(buf) - (offset_end_of_sig - 4));
|
---|
317 |
|
---|
318 | /* calculate the MD5 sig */
|
---|
319 | MD5Final(calc_md5_mac, &md5_ctx);
|
---|
320 | }
|
---|
321 |
|
---|
322 |
|
---|
323 | /***********************************************************
|
---|
324 | SMB signing - Client implementation - send the MAC.
|
---|
325 | ************************************************************/
|
---|
326 |
|
---|
327 | static void client_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
|
---|
328 | {
|
---|
329 | unsigned char calc_md5_mac[16];
|
---|
330 | struct smb_basic_signing_context *data =
|
---|
331 | (struct smb_basic_signing_context *)si->signing_context;
|
---|
332 |
|
---|
333 | if (!si->doing_signing)
|
---|
334 | return;
|
---|
335 |
|
---|
336 | /* JRA Paranioa test - we should be able to get rid of this... */
|
---|
337 | if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
|
---|
338 | DEBUG(1, ("client_sign_outgoing_message: Logic error. Can't check signature on short packet! smb_len = %u\n",
|
---|
339 | smb_len(outbuf) ));
|
---|
340 | abort();
|
---|
341 | }
|
---|
342 |
|
---|
343 | /* mark the packet as signed - BEFORE we sign it...*/
|
---|
344 | mark_packet_signed(outbuf);
|
---|
345 |
|
---|
346 | simple_packet_signature(data, (const unsigned char *)outbuf,
|
---|
347 | data->send_seq_num, calc_md5_mac);
|
---|
348 |
|
---|
349 | DEBUG(10, ("client_sign_outgoing_message: sent SMB signature of\n"));
|
---|
350 | dump_data(10, (const char *)calc_md5_mac, 8);
|
---|
351 |
|
---|
352 | memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
|
---|
353 |
|
---|
354 | /* cli->outbuf[smb_ss_field+2]=0;
|
---|
355 | Uncomment this to test if the remote server actually verifies signatures...*/
|
---|
356 |
|
---|
357 | /* Instead of re-introducing the trans_info_conect we
|
---|
358 | used to have here, we use the fact that during a
|
---|
359 | SMBtrans/SMBtrans2/SMBnttrans send that the mid stays
|
---|
360 | constant. This means that calling store_sequence_for_reply()
|
---|
361 | will return False for all trans secondaries, as the mid is already
|
---|
362 | on the stored sequence list. As the send_seqence_number must
|
---|
363 | remain constant for all primary+secondary trans sends, we
|
---|
364 | only increment the send sequence number when we successfully
|
---|
365 | add a new entry to the outstanding sequence list. This means
|
---|
366 | I can isolate the fix here rather than re-adding the trans
|
---|
367 | signing on/off calls in libsmb/clitrans2.c JRA.
|
---|
368 | */
|
---|
369 |
|
---|
370 | if (store_sequence_for_reply(&data->outstanding_packet_list, SVAL(outbuf,smb_mid), data->send_seq_num + 1)) {
|
---|
371 | data->send_seq_num += 2;
|
---|
372 | }
|
---|
373 | }
|
---|
374 |
|
---|
375 | /***********************************************************
|
---|
376 | SMB signing - Client implementation - check a MAC sent by server.
|
---|
377 | ************************************************************/
|
---|
378 |
|
---|
379 | static BOOL client_check_incoming_message(char *inbuf, struct smb_sign_info *si, BOOL must_be_ok)
|
---|
380 | {
|
---|
381 | BOOL good;
|
---|
382 | uint32 reply_seq_number;
|
---|
383 | unsigned char calc_md5_mac[16];
|
---|
384 | unsigned char *server_sent_mac;
|
---|
385 |
|
---|
386 | struct smb_basic_signing_context *data =
|
---|
387 | (struct smb_basic_signing_context *)si->signing_context;
|
---|
388 |
|
---|
389 | if (!si->doing_signing)
|
---|
390 | return True;
|
---|
391 |
|
---|
392 | if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
|
---|
393 | DEBUG(1, ("client_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf)));
|
---|
394 | return False;
|
---|
395 | }
|
---|
396 |
|
---|
397 | if (!get_sequence_for_reply(&data->outstanding_packet_list, SVAL(inbuf, smb_mid), &reply_seq_number)) {
|
---|
398 | DEBUG(1, ("client_check_incoming_message: received message "
|
---|
399 | "with mid %u with no matching send record.\n", (unsigned int)SVAL(inbuf, smb_mid) ));
|
---|
400 | return False;
|
---|
401 | }
|
---|
402 |
|
---|
403 | simple_packet_signature(data, (const unsigned char *)inbuf,
|
---|
404 | reply_seq_number, calc_md5_mac);
|
---|
405 |
|
---|
406 | server_sent_mac = (unsigned char *)&inbuf[smb_ss_field];
|
---|
407 | good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
|
---|
408 |
|
---|
409 | if (!good) {
|
---|
410 | DEBUG(5, ("client_check_incoming_message: BAD SIG: wanted SMB signature of\n"));
|
---|
411 | dump_data(5, (const char *)calc_md5_mac, 8);
|
---|
412 |
|
---|
413 | DEBUG(5, ("client_check_incoming_message: BAD SIG: got SMB signature of\n"));
|
---|
414 | dump_data(5, (const char *)server_sent_mac, 8);
|
---|
415 | #if 1 /* JRATEST */
|
---|
416 | {
|
---|
417 | int i;
|
---|
418 | for (i = -5; i < 5; i++) {
|
---|
419 | simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number+i, calc_md5_mac);
|
---|
420 | if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) {
|
---|
421 | DEBUG(0,("client_check_incoming_message: out of seq. seq num %u matches. \
|
---|
422 | We were expecting seq %u\n", reply_seq_number+i, reply_seq_number ));
|
---|
423 | break;
|
---|
424 | }
|
---|
425 | }
|
---|
426 | }
|
---|
427 | #endif /* JRATEST */
|
---|
428 |
|
---|
429 | } else {
|
---|
430 | DEBUG(10, ("client_check_incoming_message: seq %u: got good SMB signature of\n", (unsigned int)reply_seq_number));
|
---|
431 | dump_data(10, (const char *)server_sent_mac, 8);
|
---|
432 | }
|
---|
433 | return signing_good(inbuf, si, good, reply_seq_number, must_be_ok);
|
---|
434 | }
|
---|
435 |
|
---|
436 | /***********************************************************
|
---|
437 | SMB signing - Simple implementation - free signing context
|
---|
438 | ************************************************************/
|
---|
439 |
|
---|
440 | static void simple_free_signing_context(struct smb_sign_info *si)
|
---|
441 | {
|
---|
442 | struct smb_basic_signing_context *data =
|
---|
443 | (struct smb_basic_signing_context *)si->signing_context;
|
---|
444 | struct outstanding_packet_lookup *list;
|
---|
445 | struct outstanding_packet_lookup *next;
|
---|
446 |
|
---|
447 | for (list = data->outstanding_packet_list; list; list = next) {
|
---|
448 | next = list->next;
|
---|
449 | DLIST_REMOVE(data->outstanding_packet_list, list);
|
---|
450 | SAFE_FREE(list);
|
---|
451 | }
|
---|
452 |
|
---|
453 | data_blob_free(&data->mac_key);
|
---|
454 |
|
---|
455 | SAFE_FREE(si->signing_context);
|
---|
456 |
|
---|
457 | return;
|
---|
458 | }
|
---|
459 |
|
---|
460 | /***********************************************************
|
---|
461 | SMB signing - Simple implementation - setup the MAC key.
|
---|
462 | ************************************************************/
|
---|
463 |
|
---|
464 | BOOL cli_simple_set_signing(struct cli_state *cli,
|
---|
465 | const DATA_BLOB user_session_key,
|
---|
466 | const DATA_BLOB response)
|
---|
467 | {
|
---|
468 | struct smb_basic_signing_context *data;
|
---|
469 |
|
---|
470 | if (!user_session_key.length)
|
---|
471 | return False;
|
---|
472 |
|
---|
473 | if (!cli_set_smb_signing_common(cli)) {
|
---|
474 | return False;
|
---|
475 | }
|
---|
476 |
|
---|
477 | if (!set_smb_signing_real_common(&cli->sign_info)) {
|
---|
478 | return False;
|
---|
479 | }
|
---|
480 |
|
---|
481 | data = SMB_XMALLOC_P(struct smb_basic_signing_context);
|
---|
482 | memset(data, '\0', sizeof(*data));
|
---|
483 |
|
---|
484 | cli->sign_info.signing_context = data;
|
---|
485 |
|
---|
486 | data->mac_key = data_blob(NULL, response.length + user_session_key.length);
|
---|
487 |
|
---|
488 | memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length);
|
---|
489 |
|
---|
490 | DEBUG(10, ("cli_simple_set_signing: user_session_key\n"));
|
---|
491 | dump_data(10, (const char *)user_session_key.data, user_session_key.length);
|
---|
492 |
|
---|
493 | if (response.length) {
|
---|
494 | memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
|
---|
495 | DEBUG(10, ("cli_simple_set_signing: response_data\n"));
|
---|
496 | dump_data(10, (const char *)response.data, response.length);
|
---|
497 | } else {
|
---|
498 | DEBUG(10, ("cli_simple_set_signing: NULL response_data\n"));
|
---|
499 | }
|
---|
500 |
|
---|
501 | dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length);
|
---|
502 |
|
---|
503 | /* Initialise the sequence number */
|
---|
504 | data->send_seq_num = 0;
|
---|
505 |
|
---|
506 | /* Initialise the list of outstanding packets */
|
---|
507 | data->outstanding_packet_list = NULL;
|
---|
508 |
|
---|
509 | cli->sign_info.sign_outgoing_message = client_sign_outgoing_message;
|
---|
510 | cli->sign_info.check_incoming_message = client_check_incoming_message;
|
---|
511 | cli->sign_info.free_signing_context = simple_free_signing_context;
|
---|
512 |
|
---|
513 | return True;
|
---|
514 | }
|
---|
515 |
|
---|
516 | /***********************************************************
|
---|
517 | SMB signing - TEMP implementation - calculate a MAC to send.
|
---|
518 | ************************************************************/
|
---|
519 |
|
---|
520 | static void temp_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
|
---|
521 | {
|
---|
522 | /* mark the packet as signed - BEFORE we sign it...*/
|
---|
523 | mark_packet_signed(outbuf);
|
---|
524 |
|
---|
525 | /* I wonder what BSRSPYL stands for - but this is what MS
|
---|
526 | actually sends! */
|
---|
527 | memcpy(&outbuf[smb_ss_field], "BSRSPYL ", 8);
|
---|
528 | return;
|
---|
529 | }
|
---|
530 |
|
---|
531 | /***********************************************************
|
---|
532 | SMB signing - TEMP implementation - check a MAC sent by server.
|
---|
533 | ************************************************************/
|
---|
534 |
|
---|
535 | static BOOL temp_check_incoming_message(char *inbuf, struct smb_sign_info *si, BOOL foo)
|
---|
536 | {
|
---|
537 | return True;
|
---|
538 | }
|
---|
539 |
|
---|
540 | /***********************************************************
|
---|
541 | SMB signing - TEMP implementation - free signing context
|
---|
542 | ************************************************************/
|
---|
543 |
|
---|
544 | static void temp_free_signing_context(struct smb_sign_info *si)
|
---|
545 | {
|
---|
546 | return;
|
---|
547 | }
|
---|
548 |
|
---|
549 | /***********************************************************
|
---|
550 | SMB signing - NULL implementation - setup the MAC key.
|
---|
551 | ************************************************************/
|
---|
552 |
|
---|
553 | BOOL cli_null_set_signing(struct cli_state *cli)
|
---|
554 | {
|
---|
555 | return null_set_signing(&cli->sign_info);
|
---|
556 | }
|
---|
557 |
|
---|
558 | /***********************************************************
|
---|
559 | SMB signing - temp implementation - setup the MAC key.
|
---|
560 | ************************************************************/
|
---|
561 |
|
---|
562 | BOOL cli_temp_set_signing(struct cli_state *cli)
|
---|
563 | {
|
---|
564 | if (!cli_set_smb_signing_common(cli)) {
|
---|
565 | return False;
|
---|
566 | }
|
---|
567 |
|
---|
568 | cli->sign_info.signing_context = NULL;
|
---|
569 |
|
---|
570 | cli->sign_info.sign_outgoing_message = temp_sign_outgoing_message;
|
---|
571 | cli->sign_info.check_incoming_message = temp_check_incoming_message;
|
---|
572 | cli->sign_info.free_signing_context = temp_free_signing_context;
|
---|
573 |
|
---|
574 | return True;
|
---|
575 | }
|
---|
576 |
|
---|
577 | void cli_free_signing_context(struct cli_state *cli)
|
---|
578 | {
|
---|
579 | free_signing_context(&cli->sign_info);
|
---|
580 | }
|
---|
581 |
|
---|
582 | /**
|
---|
583 | * Sign a packet with the current mechanism
|
---|
584 | */
|
---|
585 |
|
---|
586 | void cli_calculate_sign_mac(struct cli_state *cli)
|
---|
587 | {
|
---|
588 | cli->sign_info.sign_outgoing_message(cli->outbuf, &cli->sign_info);
|
---|
589 | }
|
---|
590 |
|
---|
591 | /**
|
---|
592 | * Check a packet with the current mechanism
|
---|
593 | * @return False if we had an established signing connection
|
---|
594 | * which had a bad checksum, True otherwise.
|
---|
595 | */
|
---|
596 |
|
---|
597 | BOOL cli_check_sign_mac(struct cli_state *cli)
|
---|
598 | {
|
---|
599 | if (!cli->sign_info.check_incoming_message(cli->inbuf, &cli->sign_info, True)) {
|
---|
600 | free_signing_context(&cli->sign_info);
|
---|
601 | return False;
|
---|
602 | }
|
---|
603 | return True;
|
---|
604 | }
|
---|
605 |
|
---|
606 | /***********************************************************
|
---|
607 | Enter trans/trans2/nttrans state.
|
---|
608 | ************************************************************/
|
---|
609 |
|
---|
610 | BOOL client_set_trans_sign_state_on(struct cli_state *cli, uint16 mid)
|
---|
611 | {
|
---|
612 | struct smb_sign_info *si = &cli->sign_info;
|
---|
613 | struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context;
|
---|
614 |
|
---|
615 | if (!si->doing_signing) {
|
---|
616 | return True;
|
---|
617 | }
|
---|
618 |
|
---|
619 | if (!data) {
|
---|
620 | return False;
|
---|
621 | }
|
---|
622 |
|
---|
623 | if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, False)) {
|
---|
624 | return False;
|
---|
625 | }
|
---|
626 |
|
---|
627 | return True;
|
---|
628 | }
|
---|
629 |
|
---|
630 | /***********************************************************
|
---|
631 | Leave trans/trans2/nttrans state.
|
---|
632 | ************************************************************/
|
---|
633 |
|
---|
634 | BOOL client_set_trans_sign_state_off(struct cli_state *cli, uint16 mid)
|
---|
635 | {
|
---|
636 | uint32 reply_seq_num;
|
---|
637 | struct smb_sign_info *si = &cli->sign_info;
|
---|
638 | struct smb_basic_signing_context *data = (struct smb_basic_signing_context *)si->signing_context;
|
---|
639 |
|
---|
640 | if (!si->doing_signing) {
|
---|
641 | return True;
|
---|
642 | }
|
---|
643 |
|
---|
644 | if (!data) {
|
---|
645 | return False;
|
---|
646 | }
|
---|
647 |
|
---|
648 | if (!set_sequence_can_delete_flag(&data->outstanding_packet_list, mid, True)) {
|
---|
649 | return False;
|
---|
650 | }
|
---|
651 |
|
---|
652 | /* Now delete the stored mid entry. */
|
---|
653 | if (!get_sequence_for_reply(&data->outstanding_packet_list, mid, &reply_seq_num)) {
|
---|
654 | return False;
|
---|
655 | }
|
---|
656 |
|
---|
657 | return True;
|
---|
658 | }
|
---|
659 |
|
---|
660 | /***********************************************************
|
---|
661 | SMB signing - Server implementation - send the MAC.
|
---|
662 | ************************************************************/
|
---|
663 |
|
---|
664 | static void srv_sign_outgoing_message(char *outbuf, struct smb_sign_info *si)
|
---|
665 | {
|
---|
666 | unsigned char calc_md5_mac[16];
|
---|
667 | struct smb_basic_signing_context *data =
|
---|
668 | (struct smb_basic_signing_context *)si->signing_context;
|
---|
669 | uint32 send_seq_number = data->send_seq_num-1;
|
---|
670 | uint16 mid;
|
---|
671 |
|
---|
672 | if (!si->doing_signing) {
|
---|
673 | return;
|
---|
674 | }
|
---|
675 |
|
---|
676 | /* JRA Paranioa test - we should be able to get rid of this... */
|
---|
677 | if (smb_len(outbuf) < (smb_ss_field + 8 - 4)) {
|
---|
678 | DEBUG(1, ("srv_sign_outgoing_message: Logic error. Can't send signature on short packet! smb_len = %u\n",
|
---|
679 | smb_len(outbuf) ));
|
---|
680 | abort();
|
---|
681 | }
|
---|
682 |
|
---|
683 | /* mark the packet as signed - BEFORE we sign it...*/
|
---|
684 | mark_packet_signed(outbuf);
|
---|
685 |
|
---|
686 | mid = SVAL(outbuf, smb_mid);
|
---|
687 |
|
---|
688 | /* See if this is a reply for a deferred packet. */
|
---|
689 | get_sequence_for_reply(&data->outstanding_packet_list, mid, &send_seq_number);
|
---|
690 |
|
---|
691 | simple_packet_signature(data, (const unsigned char *)outbuf, send_seq_number, calc_md5_mac);
|
---|
692 |
|
---|
693 | DEBUG(10, ("srv_sign_outgoing_message: seq %u: sent SMB signature of\n", (unsigned int)send_seq_number));
|
---|
694 | dump_data(10, (const char *)calc_md5_mac, 8);
|
---|
695 |
|
---|
696 | memcpy(&outbuf[smb_ss_field], calc_md5_mac, 8);
|
---|
697 |
|
---|
698 | /* cli->outbuf[smb_ss_field+2]=0;
|
---|
699 | Uncomment this to test if the remote client actually verifies signatures...*/
|
---|
700 | }
|
---|
701 |
|
---|
702 | /***********************************************************
|
---|
703 | SMB signing - Server implementation - check a MAC sent by server.
|
---|
704 | ************************************************************/
|
---|
705 |
|
---|
706 | static BOOL srv_check_incoming_message(char *inbuf, struct smb_sign_info *si, BOOL must_be_ok)
|
---|
707 | {
|
---|
708 | BOOL good;
|
---|
709 | struct smb_basic_signing_context *data =
|
---|
710 | (struct smb_basic_signing_context *)si->signing_context;
|
---|
711 | uint32 reply_seq_number = data->send_seq_num;
|
---|
712 | uint32 saved_seq;
|
---|
713 | unsigned char calc_md5_mac[16];
|
---|
714 | unsigned char *server_sent_mac;
|
---|
715 |
|
---|
716 | if (!si->doing_signing)
|
---|
717 | return True;
|
---|
718 |
|
---|
719 | if (smb_len(inbuf) < (smb_ss_field + 8 - 4)) {
|
---|
720 | DEBUG(1, ("srv_check_incoming_message: Can't check signature on short packet! smb_len = %u\n", smb_len(inbuf)));
|
---|
721 | return False;
|
---|
722 | }
|
---|
723 |
|
---|
724 | /* We always increment the sequence number. */
|
---|
725 | data->send_seq_num += 2;
|
---|
726 |
|
---|
727 | saved_seq = reply_seq_number;
|
---|
728 | simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
|
---|
729 |
|
---|
730 | server_sent_mac = (unsigned char *)&inbuf[smb_ss_field];
|
---|
731 | good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
|
---|
732 |
|
---|
733 | if (!good) {
|
---|
734 |
|
---|
735 | if (saved_seq) {
|
---|
736 | DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u wanted SMB signature of\n",
|
---|
737 | (unsigned int)saved_seq));
|
---|
738 | dump_data(5, (const char *)calc_md5_mac, 8);
|
---|
739 |
|
---|
740 | DEBUG(0, ("srv_check_incoming_message: BAD SIG: seq %u got SMB signature of\n",
|
---|
741 | (unsigned int)reply_seq_number));
|
---|
742 | dump_data(5, (const char *)server_sent_mac, 8);
|
---|
743 | }
|
---|
744 |
|
---|
745 | #if 1 /* JRATEST */
|
---|
746 | {
|
---|
747 | int i;
|
---|
748 | reply_seq_number -= 5;
|
---|
749 | for (i = 0; i < 10; i++, reply_seq_number++) {
|
---|
750 | simple_packet_signature(data, (const unsigned char *)inbuf, reply_seq_number, calc_md5_mac);
|
---|
751 | if (memcmp(server_sent_mac, calc_md5_mac, 8) == 0) {
|
---|
752 | DEBUG(0,("srv_check_incoming_message: out of seq. seq num %u matches. \
|
---|
753 | We were expecting seq %u\n", reply_seq_number, saved_seq ));
|
---|
754 | break;
|
---|
755 | }
|
---|
756 | }
|
---|
757 | }
|
---|
758 | #endif /* JRATEST */
|
---|
759 |
|
---|
760 | } else {
|
---|
761 | DEBUG(10, ("srv_check_incoming_message: seq %u: (current is %u) got good SMB signature of\n", (unsigned int)reply_seq_number, (unsigned int)data->send_seq_num));
|
---|
762 | dump_data(10, (const char *)server_sent_mac, 8);
|
---|
763 | }
|
---|
764 |
|
---|
765 | return (signing_good(inbuf, si, good, saved_seq, must_be_ok));
|
---|
766 | }
|
---|
767 |
|
---|
768 | /***********************************************************
|
---|
769 | SMB signing - server API's.
|
---|
770 | ************************************************************/
|
---|
771 |
|
---|
772 | static struct smb_sign_info srv_sign_info = {
|
---|
773 | null_sign_outgoing_message,
|
---|
774 | null_check_incoming_message,
|
---|
775 | null_free_signing_context,
|
---|
776 | NULL,
|
---|
777 | False,
|
---|
778 | False,
|
---|
779 | False,
|
---|
780 | False
|
---|
781 | };
|
---|
782 |
|
---|
783 | /***********************************************************
|
---|
784 | Turn signing off or on for oplock break code.
|
---|
785 | ************************************************************/
|
---|
786 |
|
---|
787 | BOOL srv_oplock_set_signing(BOOL onoff)
|
---|
788 | {
|
---|
789 | BOOL ret = srv_sign_info.doing_signing;
|
---|
790 | srv_sign_info.doing_signing = onoff;
|
---|
791 | return ret;
|
---|
792 | }
|
---|
793 |
|
---|
794 | /***********************************************************
|
---|
795 | Called to validate an incoming packet from the client.
|
---|
796 | ************************************************************/
|
---|
797 |
|
---|
798 | BOOL srv_check_sign_mac(char *inbuf, BOOL must_be_ok)
|
---|
799 | {
|
---|
800 | /* Check if it's a session keepalive. */
|
---|
801 | if(CVAL(inbuf,0) == SMBkeepalive)
|
---|
802 | return True;
|
---|
803 |
|
---|
804 | return srv_sign_info.check_incoming_message(inbuf, &srv_sign_info, must_be_ok);
|
---|
805 | }
|
---|
806 |
|
---|
807 | /***********************************************************
|
---|
808 | Called to sign an outgoing packet to the client.
|
---|
809 | ************************************************************/
|
---|
810 |
|
---|
811 | void srv_calculate_sign_mac(char *outbuf)
|
---|
812 | {
|
---|
813 | /* Check if it's a session keepalive. */
|
---|
814 | /* JRA Paranioa test - do we ever generate these in the server ? */
|
---|
815 | if(CVAL(outbuf,0) == SMBkeepalive)
|
---|
816 | return;
|
---|
817 |
|
---|
818 | srv_sign_info.sign_outgoing_message(outbuf, &srv_sign_info);
|
---|
819 | }
|
---|
820 |
|
---|
821 | /***********************************************************
|
---|
822 | Called by server to defer an outgoing packet.
|
---|
823 | ************************************************************/
|
---|
824 |
|
---|
825 | void srv_defer_sign_response(uint16 mid)
|
---|
826 | {
|
---|
827 | struct smb_basic_signing_context *data;
|
---|
828 |
|
---|
829 | if (!srv_sign_info.doing_signing)
|
---|
830 | return;
|
---|
831 |
|
---|
832 | data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
|
---|
833 |
|
---|
834 | if (!data)
|
---|
835 | return;
|
---|
836 |
|
---|
837 | /*
|
---|
838 | * Ensure we only store this mid reply once...
|
---|
839 | */
|
---|
840 |
|
---|
841 | store_sequence_for_reply(&data->outstanding_packet_list, mid,
|
---|
842 | data->send_seq_num-1);
|
---|
843 | }
|
---|
844 |
|
---|
845 | /***********************************************************
|
---|
846 | Called to remove sequence records when a deferred packet is
|
---|
847 | cancelled by mid. This should never find one....
|
---|
848 | ************************************************************/
|
---|
849 |
|
---|
850 | void srv_cancel_sign_response(uint16 mid)
|
---|
851 | {
|
---|
852 | struct smb_basic_signing_context *data;
|
---|
853 | uint32 dummy_seq;
|
---|
854 |
|
---|
855 | if (!srv_sign_info.doing_signing)
|
---|
856 | return;
|
---|
857 |
|
---|
858 | data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
|
---|
859 |
|
---|
860 | if (!data)
|
---|
861 | return;
|
---|
862 |
|
---|
863 | DEBUG(10,("srv_cancel_sign_response: for mid %u\n", (unsigned int)mid ));
|
---|
864 |
|
---|
865 | while (get_sequence_for_reply(&data->outstanding_packet_list, mid, &dummy_seq))
|
---|
866 | ;
|
---|
867 |
|
---|
868 | /* cancel doesn't send a reply so doesn't burn a sequence number. */
|
---|
869 | data->send_seq_num -= 1;
|
---|
870 | }
|
---|
871 |
|
---|
872 | /***********************************************************
|
---|
873 | Called by server negprot when signing has been negotiated.
|
---|
874 | ************************************************************/
|
---|
875 |
|
---|
876 | void srv_set_signing_negotiated(void)
|
---|
877 | {
|
---|
878 | srv_sign_info.allow_smb_signing = True;
|
---|
879 | srv_sign_info.negotiated_smb_signing = True;
|
---|
880 | if (lp_server_signing() == Required)
|
---|
881 | srv_sign_info.mandatory_signing = True;
|
---|
882 |
|
---|
883 | srv_sign_info.sign_outgoing_message = temp_sign_outgoing_message;
|
---|
884 | srv_sign_info.check_incoming_message = temp_check_incoming_message;
|
---|
885 | srv_sign_info.free_signing_context = temp_free_signing_context;
|
---|
886 | }
|
---|
887 |
|
---|
888 | /***********************************************************
|
---|
889 | Returns whether signing is active. We can't use sendfile or raw
|
---|
890 | reads/writes if it is.
|
---|
891 | ************************************************************/
|
---|
892 |
|
---|
893 | BOOL srv_is_signing_active(void)
|
---|
894 | {
|
---|
895 | return srv_sign_info.doing_signing;
|
---|
896 | }
|
---|
897 |
|
---|
898 |
|
---|
899 | /***********************************************************
|
---|
900 | Returns whether signing is negotiated. We can't use it unless it was
|
---|
901 | in the negprot.
|
---|
902 | ************************************************************/
|
---|
903 |
|
---|
904 | BOOL srv_is_signing_negotiated(void)
|
---|
905 | {
|
---|
906 | return srv_sign_info.negotiated_smb_signing;
|
---|
907 | }
|
---|
908 |
|
---|
909 | /***********************************************************
|
---|
910 | Returns whether signing is actually happening
|
---|
911 | ************************************************************/
|
---|
912 |
|
---|
913 | BOOL srv_signing_started(void)
|
---|
914 | {
|
---|
915 | struct smb_basic_signing_context *data;
|
---|
916 |
|
---|
917 | if (!srv_sign_info.doing_signing) {
|
---|
918 | return False;
|
---|
919 | }
|
---|
920 |
|
---|
921 | data = (struct smb_basic_signing_context *)srv_sign_info.signing_context;
|
---|
922 | if (!data)
|
---|
923 | return False;
|
---|
924 |
|
---|
925 | if (data->send_seq_num == 0) {
|
---|
926 | return False;
|
---|
927 | }
|
---|
928 |
|
---|
929 | return True;
|
---|
930 | }
|
---|
931 |
|
---|
932 | /***********************************************************
|
---|
933 | Turn on signing from this packet onwards.
|
---|
934 | ************************************************************/
|
---|
935 |
|
---|
936 | void srv_set_signing(const DATA_BLOB user_session_key, const DATA_BLOB response)
|
---|
937 | {
|
---|
938 | struct smb_basic_signing_context *data;
|
---|
939 |
|
---|
940 | if (!user_session_key.length)
|
---|
941 | return;
|
---|
942 |
|
---|
943 | if (!srv_sign_info.negotiated_smb_signing && !srv_sign_info.mandatory_signing) {
|
---|
944 | DEBUG(5,("srv_set_signing: signing negotiated = %u, mandatory_signing = %u. Not allowing smb signing.\n",
|
---|
945 | (unsigned int)srv_sign_info.negotiated_smb_signing,
|
---|
946 | (unsigned int)srv_sign_info.mandatory_signing ));
|
---|
947 | return;
|
---|
948 | }
|
---|
949 |
|
---|
950 | /* Once we've turned on, ignore any more sessionsetups. */
|
---|
951 | if (srv_sign_info.doing_signing) {
|
---|
952 | return;
|
---|
953 | }
|
---|
954 |
|
---|
955 | if (srv_sign_info.free_signing_context)
|
---|
956 | srv_sign_info.free_signing_context(&srv_sign_info);
|
---|
957 |
|
---|
958 | srv_sign_info.doing_signing = True;
|
---|
959 |
|
---|
960 | data = SMB_XMALLOC_P(struct smb_basic_signing_context);
|
---|
961 | memset(data, '\0', sizeof(*data));
|
---|
962 |
|
---|
963 | srv_sign_info.signing_context = data;
|
---|
964 |
|
---|
965 | data->mac_key = data_blob(NULL, response.length + user_session_key.length);
|
---|
966 |
|
---|
967 | memcpy(&data->mac_key.data[0], user_session_key.data, user_session_key.length);
|
---|
968 | if (response.length)
|
---|
969 | memcpy(&data->mac_key.data[user_session_key.length],response.data, response.length);
|
---|
970 |
|
---|
971 | dump_data_pw("MAC ssession key is:\n", data->mac_key.data, data->mac_key.length);
|
---|
972 |
|
---|
973 | DEBUG(3,("srv_set_signing: turning on SMB signing: signing negotiated = %s, mandatory_signing = %s.\n",
|
---|
974 | BOOLSTR(srv_sign_info.negotiated_smb_signing),
|
---|
975 | BOOLSTR(srv_sign_info.mandatory_signing) ));
|
---|
976 |
|
---|
977 | /* Initialise the sequence number */
|
---|
978 | data->send_seq_num = 0;
|
---|
979 |
|
---|
980 | /* Initialise the list of outstanding packets */
|
---|
981 | data->outstanding_packet_list = NULL;
|
---|
982 |
|
---|
983 | srv_sign_info.sign_outgoing_message = srv_sign_outgoing_message;
|
---|
984 | srv_sign_info.check_incoming_message = srv_check_incoming_message;
|
---|
985 | srv_sign_info.free_signing_context = simple_free_signing_context;
|
---|
986 | }
|
---|