2 Unix SMB/CIFS implementation.
4 Copyright (C) Jeremy Allison 2002.
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
6 Copyright (C) James J Myers <myersjj@samba.org> 2003
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 struct smb_basic_signing_context
{
30 /***********************************************************
31 SMB signing - Common code before we set a new signing implementation
32 ************************************************************/
33 static BOOL
set_smb_signing_common(struct cli_transport
*transport
)
35 if (!(transport
->negotiate
.sec_mode
&
36 (NEGOTIATE_SECURITY_SIGNATURES_REQUIRED
|NEGOTIATE_SECURITY_SIGNATURES_ENABLED
))) {
40 if (transport
->negotiate
.sign_info
.doing_signing
) {
44 if (transport
->negotiate
.sign_info
.free_signing_context
)
45 transport
->negotiate
.sign_info
.free_signing_context(transport
);
47 /* These calls are INCOMPATIBLE with SMB signing */
48 transport
->negotiate
.readbraw_supported
= False
;
49 transport
->negotiate
.writebraw_supported
= False
;
54 /***********************************************************
55 SMB signing - Common code for 'real' implementations
56 ************************************************************/
57 static BOOL
set_smb_signing_real_common(struct cli_transport
*transport
)
59 if (transport
->negotiate
.sec_mode
& NEGOTIATE_SECURITY_SIGNATURES_REQUIRED
) {
60 DEBUG(5, ("Mandatory SMB signing enabled!\n"));
61 transport
->negotiate
.sign_info
.doing_signing
= True
;
64 DEBUG(5, ("SMB signing enabled!\n"));
69 static void mark_packet_signed(struct cli_request
*req
)
72 flags2
= SVAL(req
->out
.hdr
, HDR_FLG2
);
73 flags2
|= FLAGS2_SMB_SECURITY_SIGNATURES
;
74 SSVAL(req
->out
.hdr
, HDR_FLG2
, flags2
);
77 static BOOL
signing_good(struct cli_request
*req
, BOOL good
)
79 if (good
&& !req
->transport
->negotiate
.sign_info
.doing_signing
) {
80 req
->transport
->negotiate
.sign_info
.doing_signing
= True
;
84 if (req
->transport
->negotiate
.sign_info
.doing_signing
) {
85 DEBUG(1, ("SMB signature check failed!\n"));
88 DEBUG(3, ("Server did not sign reply correctly\n"));
89 cli_transport_free_signing_context(req
->transport
);
96 /***********************************************************
97 SMB signing - Simple implementation - calculate a MAC to send.
98 ************************************************************/
99 static void cli_request_simple_sign_outgoing_message(struct cli_request
*req
)
101 unsigned char calc_md5_mac
[16];
102 struct MD5Context md5_ctx
;
103 struct smb_basic_signing_context
*data
= req
->transport
->negotiate
.sign_info
.signing_context
;
106 /* enable this when packet signing is preventing you working out why valgrind
107 says that data is uninitialised */
108 file_save("pkt.dat", req
->out
.buffer
, req
->out
.size
);
111 req
->seq_num
= data
->next_seq_num
;
113 /* some requests (eg. NTcancel) are one way, and the sequence number
114 should be increased by 1 not 2 */
115 if (req
->one_way_request
) {
116 data
->next_seq_num
+= 1;
118 data
->next_seq_num
+= 2;
122 * Firstly put the sequence number into the first 4 bytes.
123 * and zero out the next 4 bytes.
125 SIVAL(req
->out
.hdr
, HDR_SS_FIELD
, req
->seq_num
);
126 SIVAL(req
->out
.hdr
, HDR_SS_FIELD
+ 4, 0);
128 /* mark the packet as signed - BEFORE we sign it...*/
129 mark_packet_signed(req
);
131 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
133 MD5Update(&md5_ctx
, data
->mac_key
.data
,
134 data
->mac_key
.length
);
136 req
->out
.buffer
+ NBT_HDR_SIZE
,
137 req
->out
.size
- NBT_HDR_SIZE
);
138 MD5Final(calc_md5_mac
, &md5_ctx
);
140 memcpy(&req
->out
.hdr
[HDR_SS_FIELD
], calc_md5_mac
, 8);
142 /* req->out.hdr[HDR_SS_FIELD+2]=0;
143 Uncomment this to test if the remote server actually verifies signitures...*/
147 /***********************************************************
148 SMB signing - Simple implementation - check a MAC sent by server.
149 ************************************************************/
150 static BOOL
cli_request_simple_check_incoming_message(struct cli_request
*req
)
153 unsigned char calc_md5_mac
[16];
154 unsigned char server_sent_mac
[8];
155 unsigned char sequence_buf
[8];
156 struct MD5Context md5_ctx
;
157 struct smb_basic_signing_context
*data
= req
->transport
->negotiate
.sign_info
.signing_context
;
158 const size_t offset_end_of_sig
= (HDR_SS_FIELD
+ 8);
160 const int sign_range
= 0;
162 /* its quite bogus to be guessing sequence numbers, but very useful
163 when debugging signing implementations */
164 for (i
= 1-sign_range
; i
<= 1+sign_range
; i
++) {
166 * Firstly put the sequence number into the first 4 bytes.
167 * and zero out the next 4 bytes.
169 SIVAL(sequence_buf
, 0, req
->seq_num
+i
);
170 SIVAL(sequence_buf
, 4, 0);
172 /* get a copy of the server-sent mac */
173 memcpy(server_sent_mac
, &req
->in
.hdr
[HDR_SS_FIELD
], sizeof(server_sent_mac
));
175 /* Calculate the 16 byte MAC and place first 8 bytes into the field. */
177 MD5Update(&md5_ctx
, data
->mac_key
.data
,
178 data
->mac_key
.length
);
179 MD5Update(&md5_ctx
, req
->in
.hdr
, HDR_SS_FIELD
);
180 MD5Update(&md5_ctx
, sequence_buf
, sizeof(sequence_buf
));
182 MD5Update(&md5_ctx
, req
->in
.hdr
+ offset_end_of_sig
,
183 req
->in
.size
- NBT_HDR_SIZE
- (offset_end_of_sig
));
184 MD5Final(calc_md5_mac
, &md5_ctx
);
186 good
= (memcmp(server_sent_mac
, calc_md5_mac
, 8) == 0);
190 if (good
&& i
!= 1) {
191 DEBUG(0,("SIGNING OFFSET %d\n", i
));
195 DEBUG(5, ("cli_request_simple_check_incoming_message: BAD SIG: wanted SMB signature of\n"));
196 dump_data(5, calc_md5_mac
, 8);
198 DEBUG(5, ("cli_request_simple_check_incoming_message: BAD SIG: got SMB signature of\n"));
199 dump_data(5, server_sent_mac
, 8);
201 return signing_good(req
, good
);
205 /***********************************************************
206 SMB signing - Simple implementation - free signing context
207 ************************************************************/
208 static void cli_transport_simple_free_signing_context(struct cli_transport
*transport
)
210 struct smb_basic_signing_context
*data
= transport
->negotiate
.sign_info
.signing_context
;
212 data_blob_free(&data
->mac_key
);
213 SAFE_FREE(transport
->negotiate
.sign_info
.signing_context
);
219 /***********************************************************
220 SMB signing - Simple implementation - setup the MAC key.
221 ************************************************************/
222 BOOL
cli_transport_simple_set_signing(struct cli_transport
*transport
,
223 const uchar user_transport_key
[16], const DATA_BLOB response
)
225 struct smb_basic_signing_context
*data
;
227 if (!set_smb_signing_common(transport
)) {
231 if (!set_smb_signing_real_common(transport
)) {
235 data
= smb_xmalloc(sizeof(*data
));
236 transport
->negotiate
.sign_info
.signing_context
= data
;
238 data
->mac_key
= data_blob(NULL
, MIN(response
.length
+ 16, 40));
240 memcpy(&data
->mac_key
.data
[0], user_transport_key
, 16);
241 memcpy(&data
->mac_key
.data
[16],response
.data
, MIN(response
.length
, 40 - 16));
243 /* Initialise the sequence number */
244 data
->next_seq_num
= 0;
246 transport
->negotiate
.sign_info
.sign_outgoing_message
= cli_request_simple_sign_outgoing_message
;
247 transport
->negotiate
.sign_info
.check_incoming_message
= cli_request_simple_check_incoming_message
;
248 transport
->negotiate
.sign_info
.free_signing_context
= cli_transport_simple_free_signing_context
;
254 /***********************************************************
255 SMB signing - NULL implementation - calculate a MAC to send.
256 ************************************************************/
257 static void cli_request_null_sign_outgoing_message(struct cli_request
*req
)
259 /* we can't zero out the sig, as we might be trying to send a
260 transport request - which is NBT-level, not SMB level and doesn't
265 /***********************************************************
266 SMB signing - NULL implementation - check a MAC sent by server.
267 ************************************************************/
268 static BOOL
cli_request_null_check_incoming_message(struct cli_request
*req
)
274 /***********************************************************
275 SMB signing - NULL implementation - free signing context
276 ************************************************************/
277 static void cli_null_free_signing_context(struct cli_transport
*transport
)
282 SMB signing - NULL implementation - setup the MAC key.
284 @note Used as an initialisation only - it will not correctly
285 shut down a real signing mechanism
287 BOOL
cli_null_set_signing(struct cli_transport
*transport
)
289 transport
->negotiate
.sign_info
.signing_context
= NULL
;
291 transport
->negotiate
.sign_info
.sign_outgoing_message
= cli_request_null_sign_outgoing_message
;
292 transport
->negotiate
.sign_info
.check_incoming_message
= cli_request_null_check_incoming_message
;
293 transport
->negotiate
.sign_info
.free_signing_context
= cli_null_free_signing_context
;
300 * Free the signing context
302 void cli_transport_free_signing_context(struct cli_transport
*transport
)
304 if (transport
->negotiate
.sign_info
.free_signing_context
) {
305 transport
->negotiate
.sign_info
.free_signing_context(transport
);
308 cli_null_set_signing(transport
);
313 * Sign a packet with the current mechanism
315 void cli_request_calculate_sign_mac(struct cli_request
*req
)
317 req
->transport
->negotiate
.sign_info
.sign_outgoing_message(req
);
322 * Check a packet with the current mechanism
323 * @return False if we had an established signing connection
324 * which had a back checksum, True otherwise
326 BOOL
cli_request_check_sign_mac(struct cli_request
*req
)
330 if (req
->in
.size
< (HDR_SS_FIELD
+ 8)) {
333 good
= req
->transport
->negotiate
.sign_info
.check_incoming_message(req
);
336 if (!good
&& req
->transport
->negotiate
.sign_info
.doing_signing
) {