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 if (smb_len(cli
->inbuf
) < (offset_end_of_sig
- 4)) {
164 DEBUG(1, ("Can't check signature on short packet! smb_len = %u\n", smb_len(cli
->inbuf
)));
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 and place first 8 bytes into the field. */
173 MD5Update(&md5_ctx
, data
->mac_key
.data
,
174 data
->mac_key
.length
);
175 MD5Update(&md5_ctx
, cli
->inbuf
+ 4, smb_ss_field
- 4);
176 MD5Update(&md5_ctx
, sequence_buf
, sizeof(sequence_buf
));
178 MD5Update(&md5_ctx
, cli
->inbuf
+ offset_end_of_sig
,
179 smb_len(cli
->inbuf
) - (offset_end_of_sig
- 4));
180 MD5Final(calc_md5_mac
, &md5_ctx
);
182 good
= (memcmp(server_sent_mac
, calc_md5_mac
, 8) == 0);
185 DEBUG(5, ("BAD SIG: wanted SMB signature of\n"));
186 dump_data(5, calc_md5_mac
, 8);
188 DEBUG(5, ("BAD SIG: got SMB signature of\n"));
189 dump_data(5, server_sent_mac
, 8);
191 return signing_good(cli
, good
);
194 /***********************************************************
195 SMB signing - Simple implementation - free signing context
196 ************************************************************/
198 static void cli_simple_free_signing_context(struct cli_state
*cli
)
200 struct smb_basic_signing_context
*data
= cli
->sign_info
.signing_context
;
202 data_blob_free(&data
->mac_key
);
203 SAFE_FREE(cli
->sign_info
.signing_context
);
208 /***********************************************************
209 SMB signing - Simple implementation - setup the MAC key.
210 ************************************************************/
212 BOOL
cli_simple_set_signing(struct cli_state
*cli
, const uchar user_session_key
[16], const DATA_BLOB response
)
214 struct smb_basic_signing_context
*data
;
216 if (!set_smb_signing_common(cli
)) {
220 if (!set_smb_signing_real_common(cli
)) {
224 data
= smb_xmalloc(sizeof(*data
));
225 cli
->sign_info
.signing_context
= data
;
227 data
->mac_key
= data_blob(NULL
, MIN(response
.length
+ 16, 40));
229 memcpy(&data
->mac_key
.data
[0], user_session_key
, 16);
230 memcpy(&data
->mac_key
.data
[16],response
.data
, MIN(response
.length
, 40 - 16));
232 /* Initialise the sequence number */
233 data
->send_seq_num
= 0;
235 cli
->sign_info
.sign_outgoing_message
= cli_simple_sign_outgoing_message
;
236 cli
->sign_info
.check_incoming_message
= cli_simple_check_incoming_message
;
237 cli
->sign_info
.free_signing_context
= cli_simple_free_signing_context
;
242 /***********************************************************
243 SMB signing - NTLMSSP implementation - calculate a MAC to send.
244 ************************************************************/
246 static void cli_ntlmssp_sign_outgoing_message(struct cli_state
*cli
)
250 NTLMSSP_CLIENT_STATE
*ntlmssp_state
= cli
->sign_info
.signing_context
;
252 /* mark the packet as signed - BEFORE we sign it...*/
253 mark_packet_signed(cli
);
255 nt_status
= ntlmssp_client_sign_packet(ntlmssp_state
, cli
->outbuf
+ 4,
256 smb_len(cli
->outbuf
), &sig
);
258 if (!NT_STATUS_IS_OK(nt_status
)) {
259 DEBUG(0, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status
)));
263 DEBUG(10, ("sent SMB signature of\n"));
264 dump_data(10, sig
.data
, MIN(sig
.length
, 8));
265 memcpy(&cli
->outbuf
[smb_ss_field
], sig
.data
, MIN(sig
.length
, 8));
267 data_blob_free(&sig
);
270 /***********************************************************
271 SMB signing - NTLMSSP implementation - check a MAC sent by server.
272 ************************************************************/
274 static BOOL
cli_ntlmssp_check_incoming_message(struct cli_state
*cli
)
278 DATA_BLOB sig
= data_blob(&cli
->inbuf
[smb_ss_field
], 8);
280 NTLMSSP_CLIENT_STATE
*ntlmssp_state
= cli
->sign_info
.signing_context
;
282 nt_status
= ntlmssp_client_check_packet(ntlmssp_state
, cli
->outbuf
+ 4,
283 smb_len(cli
->outbuf
), &sig
);
285 data_blob_free(&sig
);
287 good
= NT_STATUS_IS_OK(nt_status
);
288 if (!NT_STATUS_IS_OK(nt_status
)) {
289 DEBUG(5, ("NTLMSSP signing failed with %s\n", nt_errstr(nt_status
)));
292 return signing_good(cli
, good
);
295 /***********************************************************
296 SMB signing - NTLMSSP implementation - free signing context
297 ************************************************************/
299 static void cli_ntlmssp_free_signing_context(struct cli_state
*cli
)
301 ntlmssp_client_end((NTLMSSP_CLIENT_STATE
**)&cli
->sign_info
.signing_context
);
304 /***********************************************************
305 SMB signing - NTLMSSP implementation - setup the MAC key.
306 ************************************************************/
308 BOOL
cli_ntlmssp_set_signing(struct cli_state
*cli
,
309 NTLMSSP_CLIENT_STATE
*ntlmssp_state
)
311 if (!set_smb_signing_common(cli
)) {
315 if (!NT_STATUS_IS_OK(ntlmssp_client_sign_init(ntlmssp_state
))) {
319 if (!set_smb_signing_real_common(cli
)) {
323 cli
->sign_info
.signing_context
= ntlmssp_state
;
324 ntlmssp_state
->ref_count
++;
326 cli
->sign_info
.sign_outgoing_message
= cli_ntlmssp_sign_outgoing_message
;
327 cli
->sign_info
.check_incoming_message
= cli_ntlmssp_check_incoming_message
;
328 cli
->sign_info
.free_signing_context
= cli_ntlmssp_free_signing_context
;
333 /***********************************************************
334 SMB signing - NULL implementation - calculate a MAC to send.
335 ************************************************************/
337 static void cli_null_sign_outgoing_message(struct cli_state
*cli
)
339 /* we can't zero out the sig, as we might be trying to send a
340 session request - which is NBT-level, not SMB level and doesn't
345 /***********************************************************
346 SMB signing - NULL implementation - check a MAC sent by server.
347 ************************************************************/
349 static BOOL
cli_null_check_incoming_message(struct cli_state
*cli
)
354 /***********************************************************
355 SMB signing - NULL implementation - free signing context
356 ************************************************************/
358 static void cli_null_free_signing_context(struct cli_state
*cli
)
364 SMB signing - NULL implementation - setup the MAC key.
366 @note Used as an initialisation only - it will not correctly
367 shut down a real signing mechanism
370 BOOL
cli_null_set_signing(struct cli_state
*cli
)
372 cli
->sign_info
.signing_context
= NULL
;
374 cli
->sign_info
.sign_outgoing_message
= cli_null_sign_outgoing_message
;
375 cli
->sign_info
.check_incoming_message
= cli_null_check_incoming_message
;
376 cli
->sign_info
.free_signing_context
= cli_null_free_signing_context
;
381 /***********************************************************
382 SMB signing - TEMP implementation - calculate a MAC to send.
383 ************************************************************/
385 static void cli_temp_sign_outgoing_message(struct cli_state
*cli
)
387 /* mark the packet as signed - BEFORE we sign it...*/
388 mark_packet_signed(cli
);
390 /* I wonder what BSRSPYL stands for - but this is what MS
392 memcpy(&cli
->outbuf
[smb_ss_field
], "BSRSPYL ", 8);
396 /***********************************************************
397 SMB signing - TEMP implementation - check a MAC sent by server.
398 ************************************************************/
400 static BOOL
cli_temp_check_incoming_message(struct cli_state
*cli
)
405 /***********************************************************
406 SMB signing - TEMP implementation - free signing context
407 ************************************************************/
409 static void cli_temp_free_signing_context(struct cli_state
*cli
)
414 /***********************************************************
415 SMB signing - NULL implementation - setup the MAC key.
416 ************************************************************/
418 BOOL
cli_temp_set_signing(struct cli_state
*cli
)
420 if (!set_smb_signing_common(cli
)) {
424 cli
->sign_info
.signing_context
= NULL
;
426 cli
->sign_info
.sign_outgoing_message
= cli_temp_sign_outgoing_message
;
427 cli
->sign_info
.check_incoming_message
= cli_temp_check_incoming_message
;
428 cli
->sign_info
.free_signing_context
= cli_temp_free_signing_context
;
434 * Free the signing context
437 void cli_free_signing_context(struct cli_state
*cli
)
439 if (cli
->sign_info
.free_signing_context
)
440 cli
->sign_info
.free_signing_context(cli
);
442 cli_null_set_signing(cli
);
446 * Sign a packet with the current mechanism
449 void cli_caclulate_sign_mac(struct cli_state
*cli
)
451 cli
->sign_info
.sign_outgoing_message(cli
);
455 * Check a packet with the current mechanism
456 * @return False if we had an established signing connection
457 * which had a back checksum, True otherwise
460 BOOL
cli_check_sign_mac(struct cli_state
*cli
)
463 good
= cli
->sign_info
.check_incoming_message(cli
);
466 if (cli
->sign_info
.doing_signing
) {
469 cli_free_signing_context(cli
);