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 struct smb_basic_signing_context {
30 /***********************************************************
31 SMB signing - Common code before we set a new signing implementation
32 ************************************************************/
34 static BOOL set_smb_signing_common(struct cli_state *cli)
36 if (!cli->sign_info.negotiated_smb_signing
37 && !cli->sign_info.mandetory_signing) {
41 if (cli->sign_info.doing_signing) {
45 if (cli->sign_info.free_signing_context)
46 cli->sign_info.free_signing_context(cli);
48 /* These calls are INCOMPATIBLE with SMB signing */
49 cli->readbraw_supported = False;
50 cli->writebraw_supported = False;
55 /***********************************************************
56 SMB signing - Common code for 'real' implementations
57 ************************************************************/
59 static BOOL set_smb_signing_real_common(struct cli_state *cli)
61 if (cli->sign_info.mandetory_signing) {
62 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
63 cli->sign_info.doing_signing = True;
66 DEBUG(5, ("SMB signing enabled!\n"));
71 static void mark_packet_signed(struct cli_state *cli)
74 flags2 = SVAL(cli->outbuf,smb_flg2);
75 flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
76 SSVAL(cli->outbuf,smb_flg2, flags2);
79 static BOOL signing_good(struct cli_state *cli, BOOL good)
81 DEBUG(10, ("got SMB signature of\n"));
82 dump_data(10,&cli->inbuf[smb_ss_field] , 8);
84 if (good && !cli->sign_info.doing_signing) {
85 cli->sign_info.doing_signing = True;
89 if (cli->sign_info.doing_signing) {
90 DEBUG(1, ("SMB signature check failed!\n"));
93 DEBUG(3, ("Server did not sign reply correctly\n"));
94 cli_free_signing_context(cli);
101 /***********************************************************
102 SMB signing - Simple implementation - calculate a MAC to send.
103 ************************************************************/
105 static void cli_simple_sign_outgoing_message(struct cli_state *cli)
107 unsigned char calc_md5_mac[16];
108 struct MD5Context md5_ctx;
109 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
112 * Firstly put the sequence number into the first 4 bytes.
113 * and zero out the next 4 bytes.
115 * We put the sequence into the packet, becouse we are going
116 * to copy over it anyway.
118 SIVAL(cli->outbuf, smb_ss_field,
120 SIVAL(cli->outbuf, smb_ss_field + 4, 0);
122 /* mark the packet as signed - BEFORE we sign it...*/
123 mark_packet_signed(cli);
125 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
127 MD5Update(&md5_ctx, data->mac_key.data,
128 data->mac_key.length);
129 MD5Update(&md5_ctx, cli->outbuf + 4, smb_len(cli->outbuf));
130 MD5Final(calc_md5_mac, &md5_ctx);
132 DEBUG(10, ("sent SMB signature of\n"));
133 dump_data(10, calc_md5_mac, 8);
135 memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8);
137 /* cli->outbuf[smb_ss_field+2]=0;
138 Uncomment this to test if the remote server actually verifies signatures...*/
139 data->send_seq_num++;
140 data->reply_seq_num = data->send_seq_num;
141 data->send_seq_num++;
144 /***********************************************************
145 SMB signing - Simple implementation - check a MAC sent by server.
146 ************************************************************/
148 static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
151 unsigned char calc_md5_mac[16];
152 unsigned char server_sent_mac[8];
153 unsigned char sequence_buf[8];
154 struct MD5Context md5_ctx;
155 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
156 const size_t offset_end_of_sig = (smb_ss_field + 8);
159 * Firstly put the sequence number into the first 4 bytes.
160 * and zero out the next 4 bytes.
162 * We do this here, to avoid modifying the packet.
165 SIVAL(sequence_buf, 0, data->reply_seq_num);
166 SIVAL(sequence_buf, 4, 0);
168 /* get a copy of the server-sent mac */
169 memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
171 /* Calculate the 16 byte MAC - but don't alter the data in the
174 This makes for a bit for fussing about, but it's not too bad.
178 /* intialise with the key */
179 MD5Update(&md5_ctx, data->mac_key.data,
180 data->mac_key.length);
182 /* copy in the first bit of the SMB header */
183 MD5Update(&md5_ctx, cli->inbuf + 4, smb_ss_field - 4);
185 /* copy in the sequence number, instead of the signature */
186 MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
188 /* copy in the rest of the packet in, skipping the signature */
189 MD5Update(&md5_ctx, cli->inbuf + offset_end_of_sig,
190 smb_len(cli->inbuf) - (offset_end_of_sig - 4));
192 /* caclulate the MD5 sig */
193 MD5Final(calc_md5_mac, &md5_ctx);
195 good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
198 DEBUG(5, ("BAD SIG: wanted SMB signature of\n"));
199 dump_data(5, calc_md5_mac, 8);
201 DEBUG(5, ("BAD SIG: got SMB signature of\n"));
202 dump_data(5, server_sent_mac, 8);
204 return signing_good(cli, good);
207 /***********************************************************
208 SMB signing - Simple implementation - free signing context
209 ************************************************************/
211 static void cli_simple_free_signing_context(struct cli_state *cli)
213 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
215 data_blob_free(&data->mac_key);
216 SAFE_FREE(cli->sign_info.signing_context);
221 /***********************************************************
222 SMB signing - Simple implementation - setup the MAC key.
223 ************************************************************/
225 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
227 struct smb_basic_signing_context *data;
229 if (!set_smb_signing_common(cli)) {
233 if (!set_smb_signing_real_common(cli)) {
237 data = smb_xmalloc(sizeof(*data));
238 cli->sign_info.signing_context = data;
240 data->mac_key = data_blob(NULL, response.length + 16);
242 memcpy(&data->mac_key.data[0], user_session_key, 16);
243 memcpy(&data->mac_key.data[16],response.data, response.length);
245 /* Initialise the sequence number */
246 data->send_seq_num = 0;
248 cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
249 cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
250 cli->sign_info.free_signing_context = cli_simple_free_signing_context;
255 /***********************************************************
256 SMB signing - NTLMSSP implementation - calculate a MAC to send.
257 ************************************************************/
259 static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
263 NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
265 /* mark the packet as signed - BEFORE we sign it...*/
266 mark_packet_signed(cli);
268 nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4,
269 smb_len(cli->outbuf), &sig);
271 if (!NT_STATUS_IS_OK(nt_status)) {
272 DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
276 DEBUG(10, ("sent SMB signature of\n"));
277 dump_data(10, sig.data, MIN(sig.length, 8));
278 memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
280 data_blob_free(&sig);
283 /***********************************************************
284 SMB signing - NTLMSSP implementation - check a MAC sent by server.
285 ************************************************************/
287 static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
291 DATA_BLOB sig = data_blob(&cli->inbuf[smb_ss_field], 8);
293 NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
295 nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4,
296 smb_len(cli->outbuf), &sig);
298 data_blob_free(&sig);
300 good = NT_STATUS_IS_OK(nt_status);
301 if (!NT_STATUS_IS_OK(nt_status)) {
302 DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
305 return signing_good(cli, good);
308 /***********************************************************
309 SMB signing - NTLMSSP implementation - free signing context
310 ************************************************************/
312 static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
314 ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
317 /***********************************************************
318 SMB signing - NTLMSSP implementation - setup the MAC key.
319 ************************************************************/
321 BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
322 NTLMSSP_CLIENT_STATE *ntlmssp_state)
324 if (!set_smb_signing_common(cli)) {
328 if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
332 if (!set_smb_signing_real_common(cli)) {
336 cli->sign_info.signing_context = ntlmssp_state;
337 ntlmssp_state->ref_count++;
339 cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
340 cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
341 cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
346 /***********************************************************
347 SMB signing - NULL implementation - calculate a MAC to send.
348 ************************************************************/
350 static void cli_null_sign_outgoing_message(struct cli_state *cli)
352 /* we can't zero out the sig, as we might be trying to send a
353 session request - which is NBT-level, not SMB level and doesn't
358 /***********************************************************
359 SMB signing - NULL implementation - check a MAC sent by server.
360 ************************************************************/
362 static BOOL cli_null_check_incoming_message(struct cli_state *cli)
367 /***********************************************************
368 SMB signing - NULL implementation - free signing context
369 ************************************************************/
371 static void cli_null_free_signing_context(struct cli_state *cli)
377 SMB signing - NULL implementation - setup the MAC key.
379 @note Used as an initialisation only - it will not correctly
380 shut down a real signing mechanism
383 BOOL cli_null_set_signing(struct cli_state *cli)
385 cli->sign_info.signing_context = NULL;
387 cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
388 cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
389 cli->sign_info.free_signing_context = cli_null_free_signing_context;
394 /***********************************************************
395 SMB signing - TEMP implementation - calculate a MAC to send.
396 ************************************************************/
398 static void cli_temp_sign_outgoing_message(struct cli_state *cli)
400 /* mark the packet as signed - BEFORE we sign it...*/
401 mark_packet_signed(cli);
403 /* I wonder what BSRSPYL stands for - but this is what MS
405 memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
409 /***********************************************************
410 SMB signing - TEMP implementation - check a MAC sent by server.
411 ************************************************************/
413 static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
418 /***********************************************************
419 SMB signing - TEMP implementation - free signing context
420 ************************************************************/
422 static void cli_temp_free_signing_context(struct cli_state *cli)
427 /***********************************************************
428 SMB signing - NULL implementation - setup the MAC key.
429 ************************************************************/
431 BOOL cli_temp_set_signing(struct cli_state *cli)
433 if (!set_smb_signing_common(cli)) {
437 cli->sign_info.signing_context = NULL;
439 cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
440 cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
441 cli->sign_info.free_signing_context = cli_temp_free_signing_context;
447 * Free the signing context
450 void cli_free_signing_context(struct cli_state *cli)
452 if (cli->sign_info.free_signing_context)
453 cli->sign_info.free_signing_context(cli);
455 cli_null_set_signing(cli);
459 * Sign a packet with the current mechanism
462 void cli_caclulate_sign_mac(struct cli_state *cli)
464 cli->sign_info.sign_outgoing_message(cli);
468 * Check a packet with the current mechanism
469 * @return False if we had an established signing connection
470 * which had a back checksum, True otherwise
473 BOOL cli_check_sign_mac(struct cli_state *cli)
477 if (smb_len(cli->inbuf) < (smb_ss_field + 8 - 4)) {
478 DEBUG(cli->sign_info.doing_signing ? 1 : 10, ("Can't check signature on short packet! smb_len = %u\n", smb_len(cli->inbuf)));
481 good = cli->sign_info.check_incoming_message(cli);
485 if (cli->sign_info.doing_signing) {
488 cli_free_signing_context(cli);