2 Unix SMB/CIFS implementation.
5 Copyright (C) Andrew Tridgell 2003-2005
6 Copyright (C) Jelmer Vernooij 2004-2005
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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "system/network.h"
25 #include "lib/util/talloc_stack.h"
26 #include "lib/util/debug.h"
27 #include "lib/util/byteorder.h"
28 #include "lib/util/samba_util.h"
29 #include "librpc/rpc/dcerpc.h"
30 #include "librpc/rpc/dcerpc_util.h"
31 #include "librpc/rpc/dcerpc_pkt_auth.h"
32 #include "librpc/gen_ndr/ndr_dcerpc.h"
33 #include "rpc_common.h"
34 #include "lib/util/bitmap.h"
35 #include "auth/gensec/gensec.h"
36 #include "lib/util/mkdir_p.h"
37 #include "lib/crypto/gnutls_helpers.h"
38 #include <gnutls/crypto.h>
40 NTSTATUS
dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth
*auth_state
,
41 struct gensec_security
*gensec
,
42 bool check_pkt_auth_fields
,
44 enum dcerpc_pkt_type ptype
,
45 uint8_t required_flags
,
46 uint8_t optional_flags
,
47 uint8_t payload_offset
,
48 DATA_BLOB
*payload_and_verifier
,
49 DATA_BLOB
*raw_packet
,
50 const struct ncacn_packet
*pkt
)
53 struct dcerpc_auth auth
;
56 if (auth_state
== NULL
) {
57 return NT_STATUS_INTERNAL_ERROR
;
60 status
= dcerpc_verify_ncacn_packet_header(pkt
, ptype
,
61 payload_and_verifier
->length
,
62 required_flags
, optional_flags
);
63 if (!NT_STATUS_IS_OK(status
)) {
67 switch (auth_state
->auth_level
) {
68 case DCERPC_AUTH_LEVEL_PRIVACY
:
69 case DCERPC_AUTH_LEVEL_INTEGRITY
:
70 case DCERPC_AUTH_LEVEL_PACKET
:
73 case DCERPC_AUTH_LEVEL_CONNECT
:
74 if (pkt
->auth_length
!= 0) {
78 case DCERPC_AUTH_LEVEL_NONE
:
79 if (pkt
->auth_length
!= 0) {
80 return NT_STATUS_ACCESS_DENIED
;
85 return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL
;
88 if (pkt
->auth_length
== 0) {
89 return NT_STATUS_RPC_PROTOCOL_ERROR
;
93 return NT_STATUS_INTERNAL_ERROR
;
96 status
= dcerpc_pull_auth_trailer(pkt
, mem_ctx
,
98 &auth
, &auth_length
, false);
99 if (!NT_STATUS_IS_OK(status
)) {
103 if (payload_and_verifier
->length
< auth_length
) {
105 * should be checked in dcerpc_pull_auth_trailer()
107 return NT_STATUS_INTERNAL_ERROR
;
110 payload_and_verifier
->length
-= auth_length
;
112 if (payload_and_verifier
->length
< auth
.auth_pad_length
) {
114 * should be checked in dcerpc_pull_auth_trailer()
116 return NT_STATUS_INTERNAL_ERROR
;
119 if (check_pkt_auth_fields
) {
120 if (auth
.auth_type
!= auth_state
->auth_type
) {
121 return NT_STATUS_ACCESS_DENIED
;
124 if (auth
.auth_level
!= auth_state
->auth_level
) {
125 return NT_STATUS_ACCESS_DENIED
;
128 if (auth
.auth_context_id
!= auth_state
->auth_context_id
) {
129 return NT_STATUS_ACCESS_DENIED
;
133 /* check signature or unseal the packet */
134 switch (auth_state
->auth_level
) {
135 case DCERPC_AUTH_LEVEL_PRIVACY
:
136 status
= gensec_unseal_packet(gensec
,
137 raw_packet
->data
+ payload_offset
,
138 payload_and_verifier
->length
,
141 auth
.credentials
.length
,
143 if (!NT_STATUS_IS_OK(status
)) {
144 return NT_STATUS_RPC_SEC_PKG_ERROR
;
146 memcpy(payload_and_verifier
->data
,
147 raw_packet
->data
+ payload_offset
,
148 payload_and_verifier
->length
);
151 case DCERPC_AUTH_LEVEL_INTEGRITY
:
152 case DCERPC_AUTH_LEVEL_PACKET
:
153 status
= gensec_check_packet(gensec
,
154 payload_and_verifier
->data
,
155 payload_and_verifier
->length
,
158 auth
.credentials
.length
,
160 if (!NT_STATUS_IS_OK(status
)) {
161 return NT_STATUS_RPC_SEC_PKG_ERROR
;
165 case DCERPC_AUTH_LEVEL_CONNECT
:
166 /* for now we ignore possible signatures here */
170 return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL
;
174 * remove the indicated amount of padding
176 * A possible overflow is checked above.
178 payload_and_verifier
->length
-= auth
.auth_pad_length
;
183 NTSTATUS
dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth
*auth_state
,
184 struct gensec_security
*gensec
,
186 DATA_BLOB
*raw_packet
,
188 uint8_t payload_offset
,
189 const DATA_BLOB
*payload
,
190 const struct ncacn_packet
*pkt
)
192 TALLOC_CTX
*frame
= talloc_stackframe();
194 enum ndr_err_code ndr_err
;
195 struct ndr_push
*ndr
= NULL
;
196 uint32_t payload_length
;
197 uint32_t whole_length
;
198 DATA_BLOB blob
= data_blob_null
;
199 DATA_BLOB sig
= data_blob_null
;
200 struct dcerpc_auth _out_auth_info
;
201 struct dcerpc_auth
*out_auth_info
= NULL
;
203 *raw_packet
= data_blob_null
;
205 if (auth_state
== NULL
) {
207 return NT_STATUS_INTERNAL_ERROR
;
210 switch (auth_state
->auth_level
) {
211 case DCERPC_AUTH_LEVEL_PRIVACY
:
212 case DCERPC_AUTH_LEVEL_INTEGRITY
:
213 case DCERPC_AUTH_LEVEL_PACKET
:
216 return NT_STATUS_INTERNAL_ERROR
;
219 if (gensec
== NULL
) {
221 return NT_STATUS_INTERNAL_ERROR
;
224 _out_auth_info
= (struct dcerpc_auth
) {
225 .auth_type
= auth_state
->auth_type
,
226 .auth_level
= auth_state
->auth_level
,
227 .auth_context_id
= auth_state
->auth_context_id
,
229 out_auth_info
= &_out_auth_info
;
232 case DCERPC_AUTH_LEVEL_CONNECT
:
234 * TODO: let the gensec mech decide if it wants to generate a
235 * signature that might be needed for schannel...
239 return NT_STATUS_INTERNAL_ERROR
;
242 if (gensec
== NULL
) {
244 return NT_STATUS_INTERNAL_ERROR
;
248 case DCERPC_AUTH_LEVEL_NONE
:
251 return NT_STATUS_INTERNAL_ERROR
;
257 return NT_STATUS_INTERNAL_ERROR
;
260 ndr
= ndr_push_init_ctx(frame
);
263 return NT_STATUS_NO_MEMORY
;
266 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
267 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
269 return ndr_map_error2ntstatus(ndr_err
);
272 if (out_auth_info
!= NULL
) {
274 * pad to 16 byte multiple in the payload portion of the
275 * packet. This matches what w2k3 does. Note that we can't use
276 * ndr_push_align() as that is relative to the start of the
277 * whole packet, whereas w2k8 wants it relative to the start
280 out_auth_info
->auth_pad_length
=
281 DCERPC_AUTH_PAD_LENGTH(payload
->length
);
282 ndr_err
= ndr_push_zero(ndr
, out_auth_info
->auth_pad_length
);
283 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
285 return ndr_map_error2ntstatus(ndr_err
);
288 payload_length
= payload
->length
+
289 out_auth_info
->auth_pad_length
;
291 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
,
293 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
295 return ndr_map_error2ntstatus(ndr_err
);
298 whole_length
= ndr
->offset
;
300 ndr_err
= ndr_push_zero(ndr
, sig_size
);
301 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
303 return ndr_map_error2ntstatus(ndr_err
);
306 payload_length
= payload
->length
;
307 whole_length
= ndr
->offset
;
310 /* extract the whole packet as a blob */
311 blob
= ndr_push_blob(ndr
);
314 * Setup the frag and auth length in the packet buffer.
315 * This is needed if the GENSEC mech does AEAD signing
316 * of the packet headers. The signature itself will be
319 dcerpc_set_frag_length(&blob
, blob
.length
);
320 dcerpc_set_auth_length(&blob
, sig_size
);
322 /* sign or seal the packet */
323 switch (auth_state
->auth_level
) {
324 case DCERPC_AUTH_LEVEL_PRIVACY
:
325 status
= gensec_seal_packet(gensec
,
327 blob
.data
+ payload_offset
,
332 if (!NT_STATUS_IS_OK(status
)) {
338 case DCERPC_AUTH_LEVEL_INTEGRITY
:
339 case DCERPC_AUTH_LEVEL_PACKET
:
340 status
= gensec_sign_packet(gensec
,
342 blob
.data
+ payload_offset
,
347 if (!NT_STATUS_IS_OK(status
)) {
353 case DCERPC_AUTH_LEVEL_CONNECT
:
354 case DCERPC_AUTH_LEVEL_NONE
:
359 return NT_STATUS_INTERNAL_ERROR
;
362 if (sig
.length
!= sig_size
) {
364 return NT_STATUS_RPC_SEC_PKG_ERROR
;
368 memcpy(blob
.data
+ whole_length
, sig
.data
, sig_size
);
372 talloc_steal(mem_ctx
, raw_packet
->data
);
380 * Save valid, well-formed DCE/RPC stubs to use as a seed for
383 void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX
*mem_ctx
,
385 const char *dump_dir
,
386 const char *iface_name
,
387 ndr_flags_type flags
,
392 const char *sub_dir
= NULL
;
393 TALLOC_CTX
*temp_ctx
= talloc_new(mem_ctx
);
397 DATA_BLOB digest_blob
;
399 uint16_t fuzz_flags
= 0;
402 * We want to save the 'stub' in a per-pipe subdirectory, with
403 * the ndr_fuzz_X header 4 byte header. For the sake of
404 * convenience (this is a developer only function), we mkdir
405 * -p the sub-directories when they are needed.
408 if (dump_dir
== NULL
) {
412 temp_ctx
= talloc_stackframe();
414 sub_dir
= talloc_asprintf(temp_ctx
, "%s/%s",
417 if (sub_dir
== NULL
) {
418 talloc_free(temp_ctx
);
421 ret
= mkdir_p(sub_dir
, 0755);
422 if (ret
&& errno
!= EEXIST
) {
423 DBG_ERR("could not create %s\n", sub_dir
);
424 talloc_free(temp_ctx
);
428 blob
.length
= raw_blob
.length
+ 4;
429 blob
.data
= talloc_array(sub_dir
,
432 if (blob
.data
== NULL
) {
433 DBG_ERR("could not allocate for fuzz seeds! (%s)\n",
435 talloc_free(temp_ctx
);
442 if (flags
& NDR_IN
) {
444 } else if (flags
& NDR_OUT
) {
448 SSVAL(blob
.data
, 0, fuzz_flags
);
449 SSVAL(blob
.data
, 2, opnum
);
451 memcpy(&blob
.data
[4],
456 * This matches how oss-fuzz names the corpus input files, due
457 * to a preference from libFuzzer
459 rc
= gnutls_hash_fast(GNUTLS_DIG_SHA1
,
465 * This prints a better error message, eg if SHA1 is
468 NTSTATUS status
= gnutls_error_to_ntstatus(rc
,
469 NT_STATUS_HASH_NOT_SUPPORTED
);
470 DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s\n",
472 talloc_free(temp_ctx
);
476 digest_blob
.data
= digest
;
477 digest_blob
.length
= sizeof(digest
);
478 digest_hex
= data_blob_hex_string_lower(temp_ctx
, &digest_blob
);
480 fname
= talloc_asprintf(temp_ctx
, "%s/%s",
484 talloc_free(temp_ctx
);
489 * If this fails, it is most likely because that file already
490 * exists. This is fine, it means we already have this
497 talloc_free(temp_ctx
);
500 #endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */