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->outbuf[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 struct MD5Context md5_ctx;
151 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
154 * Firstly put the sequence number into the first 4 bytes.
155 * and zero out the next 4 bytes.
158 memcpy(server_sent_mac, &cli->inbuf[smb_ss_field], sizeof(server_sent_mac));
160 DEBUG(10, ("got SMB signature of\n"));
161 dump_data(10, server_sent_mac, 8);
163 SIVAL(cli->inbuf, smb_ss_field, data->reply_seq_num);
164 SIVAL(cli->inbuf, smb_ss_field + 4, 0);
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_len(cli->inbuf));
171 MD5Final(calc_md5_mac, &md5_ctx);
173 good = (memcmp(server_sent_mac, calc_md5_mac, 8) == 0);
175 return signing_good(cli, good);
178 /***********************************************************
179 SMB signing - Simple implementation - free signing context
180 ************************************************************/
182 static void cli_simple_free_signing_context(struct cli_state *cli)
184 struct smb_basic_signing_context *data = cli->sign_info.signing_context;
186 data_blob_free(&data->mac_key);
187 SAFE_FREE(cli->sign_info.signing_context);
192 /***********************************************************
193 SMB signing - Simple implementation - setup the MAC key.
194 ************************************************************/
196 BOOL cli_simple_set_signing(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response)
198 struct smb_basic_signing_context *data;
200 if (!set_smb_signing_common(cli)) {
204 if (!set_smb_signing_real_common(cli)) {
208 data = smb_xmalloc(sizeof(*data));
209 cli->sign_info.signing_context = data;
211 data->mac_key = data_blob(NULL, MIN(response.length + 16, 40));
213 memcpy(&data->mac_key.data[0], user_session_key, 16);
214 memcpy(&data->mac_key.data[16],response.data, MIN(response.length, 40 - 16));
216 /* Initialize the sequence number */
217 data->send_seq_num = 0;
219 cli->sign_info.sign_outgoing_message = cli_simple_sign_outgoing_message;
220 cli->sign_info.check_incoming_message = cli_simple_check_incoming_message;
221 cli->sign_info.free_signing_context = cli_simple_free_signing_context;
226 /***********************************************************
227 SMB signing - NTLMSSP implementation - calculate a MAC to send.
228 ************************************************************/
230 static void cli_ntlmssp_sign_outgoing_message(struct cli_state *cli)
234 NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
236 /* mark the packet as signed - BEFORE we sign it...*/
237 mark_packet_signed(cli);
239 nt_status = ntlmssp_client_sign_packet(ntlmssp_state, cli->outbuf + 4,
240 smb_len(cli->outbuf), &sig);
242 if (!NT_STATUS_IS_OK(nt_status)) {
243 DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
247 DEBUG(10, ("sent SMB signature of\n"));
248 dump_data(10, sig.data, MIN(sig.length, 8));
249 memcpy(&cli->outbuf[smb_ss_field], sig.data, MIN(sig.length, 8));
251 data_blob_free(&sig);
254 /***********************************************************
255 SMB signing - NTLMSSP implementation - check a MAC sent by server.
256 ************************************************************/
258 static BOOL cli_ntlmssp_check_incoming_message(struct cli_state *cli)
262 DATA_BLOB sig = data_blob(&cli->outbuf[smb_ss_field], 8);
264 NTLMSSP_CLIENT_STATE *ntlmssp_state = cli->sign_info.signing_context;
266 nt_status = ntlmssp_client_check_packet(ntlmssp_state, cli->outbuf + 4,
267 smb_len(cli->outbuf), &sig);
269 data_blob_free(&sig);
271 good = NT_STATUS_IS_OK(nt_status);
272 if (!NT_STATUS_IS_OK(nt_status)) {
273 DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status)));
276 return signing_good(cli, good);
279 /***********************************************************
280 SMB signing - NTLMSSP implementation - free signing context
281 ************************************************************/
283 static void cli_ntlmssp_free_signing_context(struct cli_state *cli)
285 ntlmssp_client_end((NTLMSSP_CLIENT_STATE **)&cli->sign_info.signing_context);
288 /***********************************************************
289 SMB signing - NTLMSSP implementation - setup the MAC key.
290 ************************************************************/
292 BOOL cli_ntlmssp_set_signing(struct cli_state *cli,
293 NTLMSSP_CLIENT_STATE *ntlmssp_state)
295 if (!set_smb_signing_common(cli)) {
299 if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state))) {
303 if (!set_smb_signing_real_common(cli)) {
307 cli->sign_info.signing_context = ntlmssp_state;
308 ntlmssp_state->ref_count++;
310 cli->sign_info.sign_outgoing_message = cli_ntlmssp_sign_outgoing_message;
311 cli->sign_info.check_incoming_message = cli_ntlmssp_check_incoming_message;
312 cli->sign_info.free_signing_context = cli_ntlmssp_free_signing_context;
317 /***********************************************************
318 SMB signing - NULL implementation - calculate a MAC to send.
319 ************************************************************/
321 static void cli_null_sign_outgoing_message(struct cli_state *cli)
323 /* we can't zero out the sig, as we might be trying to send a
324 session request - which is NBT-level, not SMB level and doesn't
329 /***********************************************************
330 SMB signing - NULL implementation - check a MAC sent by server.
331 ************************************************************/
333 static BOOL cli_null_check_incoming_message(struct cli_state *cli)
338 /***********************************************************
339 SMB signing - NULL implementation - free signing context
340 ************************************************************/
342 static void cli_null_free_signing_context(struct cli_state *cli)
348 SMB signing - NULL implementation - setup the MAC key.
350 @note Used as an initialisation only - it will not correctly
351 shut down a real signing mechinism
354 BOOL cli_null_set_signing(struct cli_state *cli)
356 cli->sign_info.signing_context = NULL;
358 cli->sign_info.sign_outgoing_message = cli_null_sign_outgoing_message;
359 cli->sign_info.check_incoming_message = cli_null_check_incoming_message;
360 cli->sign_info.free_signing_context = cli_null_free_signing_context;
365 /***********************************************************
366 SMB signing - TEMP implementation - calculate a MAC to send.
367 ************************************************************/
369 static void cli_temp_sign_outgoing_message(struct cli_state *cli)
371 /* mark the packet as signed - BEFORE we sign it...*/
372 mark_packet_signed(cli);
374 /* I wonder what BSRSPYL stands for - but this is what MS
376 memcpy(&cli->outbuf[smb_ss_field], "BSRSPYL ", 8);
380 /***********************************************************
381 SMB signing - TEMP implementation - check a MAC sent by server.
382 ************************************************************/
384 static BOOL cli_temp_check_incoming_message(struct cli_state *cli)
389 /***********************************************************
390 SMB signing - TEMP implementation - free signing context
391 ************************************************************/
393 static void cli_temp_free_signing_context(struct cli_state *cli)
398 /***********************************************************
399 SMB signing - NULL implementation - setup the MAC key.
400 ************************************************************/
402 BOOL cli_temp_set_signing(struct cli_state *cli)
404 if (!set_smb_signing_common(cli)) {
408 cli->sign_info.signing_context = NULL;
410 cli->sign_info.sign_outgoing_message = cli_temp_sign_outgoing_message;
411 cli->sign_info.check_incoming_message = cli_temp_check_incoming_message;
412 cli->sign_info.free_signing_context = cli_temp_free_signing_context;
418 * Free the signing context
421 void cli_free_signing_context(struct cli_state *cli)
423 if (cli->sign_info.free_signing_context)
424 cli->sign_info.free_signing_context(cli);
426 cli_null_set_signing(cli);
430 * Sign a packet with the current mechanism
433 void cli_caclulate_sign_mac(struct cli_state *cli)
435 cli->sign_info.sign_outgoing_message(cli);
439 * Check a packet with the current mechanism
440 * @return False if we had an established signing connection
441 * which had a back checksum, True otherwise
444 BOOL cli_check_sign_mac(struct cli_state *cli)
447 good = cli->sign_info.check_incoming_message(cli);
450 if (cli->sign_info.doing_signing) {
453 cli_free_signing_context(cli);