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 SIVAL(cli->outbuf, smb_ss_field,
117 SIVAL(cli->outbuf, smb_ss_field + 4, 0);
119 /* mark the packet as signed - BEFORE we sign it...*/
120 mark_packet_signed(cli);
122 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
124 MD5Update(&md5_ctx, data->mac_key.data,
125 data->mac_key.length);
126 MD5Update(&md5_ctx, cli->outbuf + 4, smb_len(cli->outbuf));
127 MD5Final(calc_md5_mac, &md5_ctx);
129 DEBUG(10, ("sent SMB signature of\n"));
130 dump_data(10, calc_md5_mac, 8);
132 memcpy(&cli->outbuf[smb_ss_field], calc_md5_mac, 8);
134 /* cli->outbuf[smb_ss_field+2]=0;
135 Uncomment this to test if the remote server actually verifies signitures...*/
136 data->send_seq_num++;
137 data->reply_seq_num = data->send_seq_num;
138 data->send_seq_num++;
141 /***********************************************************
142 SMB signing - Simple implementation - check a MAC sent by server.
143 ************************************************************/
145 static BOOL cli_simple_check_incoming_message(struct cli_state *cli)
148 unsigned char calc_md5_mac[16];
149 unsigned char server_sent_mac[8];
150 unsigned char sequence_buf[8];
151 struct MD5Context md5_ctx;
152 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
153 const size_t offset_end_of_sig = (smb_ss_field + 8);
156 * Firstly put the sequence number into the first 4 bytes.
157 * and zero out the next 4 bytes.
160 SIVAL(sequence_buf, 0, data->reply_seq_num);
161 SIVAL(sequence_buf, 4, 0);
163 /* get a copy of the server-sent mac */
164 memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
166 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
168 MD5Update(&md5_ctx, data->mac_key.data,
169 data->mac_key.length);
170 MD5Update(&md5_ctx, cli->inbuf + 4, smb_ss_field - 4);
171 MD5Update(&md5_ctx, sequence_buf, sizeof(sequence_buf));
173 MD5Update(&md5_ctx, cli->inbuf + offset_end_of_sig,
174 smb_len(cli->inbuf) - (offset_end_of_sig - 4));
175 MD5Final(calc_md5_mac, &md5_ctx);
177 good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
180 DEBUG(5, ("BAD SIG: wanted SMB signature of\n"));
181 dump_data(5, calc_md5_mac, 8);
183 DEBUG(5, ("BAD SIG: got SMB signature of\n"));
184 dump_data(5, server_sent_mac, 8);
186 return signing_good(cli, good);
189 /***********************************************************
190 SMB signing - Simple implementation - free signing context
191 ************************************************************/
193 static void cli_simple_free_signing_context(struct cli_state *cli)
195 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
197 data_blob_free(&data->mac_key);
198 SAFE_FREE(cli->sign_info.signing_context);
203 /***********************************************************
204 SMB signing - Simple implementation - setup the MAC key.
205 ************************************************************/
207 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
209 struct smb_basic_signing_context *data;
211 if (!set_smb_signing_common(cli)) {
215 if (!set_smb_signing_real_common(cli)) {
219 data = smb_xmalloc(sizeof(*data));
220 cli->sign_info.signing_context = data;
222 data->mac_key = data_blob(NULL, MIN(response.length + 16, 40));
224 memcpy(&data->mac_key.data[0], user_session_key, 16);
225 memcpy(&data->mac_key.data[16],response.data, MIN(response.length, 40 - 16));
227 /* Initialise the sequence number */
228 data->send_seq_num = 0;
230 cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
231 cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
232 cli->sign_info.free_signing_context = cli_simple_free_signing_context;
237 /***********************************************************
238 SMB signing - NTLMSSP implementation - calculate a MAC to send.
239 ************************************************************/
241 static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
245 NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
247 /* mark the packet as signed - BEFORE we sign it...*/
248 mark_packet_signed(cli);
250 nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4,
251 smb_len(cli->outbuf), &sig);
253 if (!NT_STATUS_IS_OK(nt_status)) {
254 DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
258 DEBUG(10, ("sent SMB signature of\n"));
259 dump_data(10, sig.data, MIN(sig.length, 8));
260 memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
262 data_blob_free(&sig);
265 /***********************************************************
266 SMB signing - NTLMSSP implementation - check a MAC sent by server.
267 ************************************************************/
269 static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
273 DATA_BLOB sig = data_blob(&cli->inbuf[smb_ss_field], 8);
275 NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
277 nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4,
278 smb_len(cli->outbuf), &sig);
280 data_blob_free(&sig);
282 good = NT_STATUS_IS_OK(nt_status);
283 if (!NT_STATUS_IS_OK(nt_status)) {
284 DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
287 return signing_good(cli, good);
290 /***********************************************************
291 SMB signing - NTLMSSP implementation - free signing context
292 ************************************************************/
294 static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
296 ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
299 /***********************************************************
300 SMB signing - NTLMSSP implementation - setup the MAC key.
301 ************************************************************/
303 BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
304 NTLMSSP_CLIENT_STATE *ntlmssp_state)
306 if (!set_smb_signing_common(cli)) {
310 if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
314 if (!set_smb_signing_real_common(cli)) {
318 cli->sign_info.signing_context = ntlmssp_state;
319 ntlmssp_state->ref_count++;
321 cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
322 cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
323 cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
328 /***********************************************************
329 SMB signing - NULL implementation - calculate a MAC to send.
330 ************************************************************/
332 static void cli_null_sign_outgoing_message(struct cli_state *cli)
334 /* we can't zero out the sig, as we might be trying to send a
335 session request - which is NBT-level, not SMB level and doesn't
340 /***********************************************************
341 SMB signing - NULL implementation - check a MAC sent by server.
342 ************************************************************/
344 static BOOL cli_null_check_incoming_message(struct cli_state *cli)
349 /***********************************************************
350 SMB signing - NULL implementation - free signing context
351 ************************************************************/
353 static void cli_null_free_signing_context(struct cli_state *cli)
359 SMB signing - NULL implementation - setup the MAC key.
361 @note Used as an initialisation only - it will not correctly
362 shut down a real signing mechanism
365 BOOL cli_null_set_signing(struct cli_state *cli)
367 cli->sign_info.signing_context = NULL;
369 cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
370 cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
371 cli->sign_info.free_signing_context = cli_null_free_signing_context;
376 /***********************************************************
377 SMB signing - TEMP implementation - calculate a MAC to send.
378 ************************************************************/
380 static void cli_temp_sign_outgoing_message(struct cli_state *cli)
382 /* mark the packet as signed - BEFORE we sign it...*/
383 mark_packet_signed(cli);
385 /* I wonder what BSRSPYL stands for - but this is what MS
387 memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
391 /***********************************************************
392 SMB signing - TEMP implementation - check a MAC sent by server.
393 ************************************************************/
395 static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
400 /***********************************************************
401 SMB signing - TEMP implementation - free signing context
402 ************************************************************/
404 static void cli_temp_free_signing_context(struct cli_state *cli)
409 /***********************************************************
410 SMB signing - NULL implementation - setup the MAC key.
411 ************************************************************/
413 BOOL cli_temp_set_signing(struct cli_state *cli)
415 if (!set_smb_signing_common(cli)) {
419 cli->sign_info.signing_context = NULL;
421 cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
422 cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
423 cli->sign_info.free_signing_context = cli_temp_free_signing_context;
429 * Free the signing context
432 void cli_free_signing_context(struct cli_state *cli)
434 if (cli->sign_info.free_signing_context)
435 cli->sign_info.free_signing_context(cli);
437 cli_null_set_signing(cli);
441 * Sign a packet with the current mechanism
444 void cli_caclulate_sign_mac(struct cli_state *cli)
446 cli->sign_info.sign_outgoing_message(cli);
450 * Check a packet with the current mechanism
451 * @return False if we had an established signing connection
452 * which had a back checksum, True otherwise
455 BOOL cli_check_sign_mac(struct cli_state *cli)
459 if (smb_len(cli->inbuf) < (smb_ss_field + 8 - 4)) {
460 DEBUG(1, ("Can't check signature on short packet! smb_len = %u\n", smb_len(cli->inbuf)));
463 good = cli->sign_info.check_incoming_message(cli);
467 if (cli->sign_info.doing_signing) {
470 cli_free_signing_context(cli);