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/util_file.h"
26 #include "lib/util/talloc_stack.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/byteorder.h"
29 #include "lib/util/samba_util.h"
30 #include "librpc/rpc/dcerpc.h"
31 #include "librpc/rpc/dcerpc_util.h"
32 #include "librpc/rpc/dcerpc_pkt_auth.h"
33 #include "librpc/gen_ndr/ndr_dcerpc.h"
34 #include "rpc_common.h"
35 #include "lib/util/bitmap.h"
36 #include "auth/gensec/gensec.h"
37 #include "lib/util/mkdir_p.h"
38 #include "lib/crypto/gnutls_helpers.h"
39 #include <gnutls/crypto.h>
41 NTSTATUS
dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth
*auth_state
,
42 struct gensec_security
*gensec
,
43 bool check_pkt_auth_fields
,
45 enum dcerpc_pkt_type ptype
,
46 uint8_t required_flags
,
47 uint8_t optional_flags
,
48 uint8_t payload_offset
,
49 DATA_BLOB
*payload_and_verifier
,
50 DATA_BLOB
*raw_packet
,
51 const struct ncacn_packet
*pkt
)
54 struct dcerpc_auth auth
;
57 if (auth_state
== NULL
) {
58 return NT_STATUS_INTERNAL_ERROR
;
61 status
= dcerpc_verify_ncacn_packet_header(pkt
, ptype
,
62 payload_and_verifier
->length
,
63 required_flags
, optional_flags
);
64 if (!NT_STATUS_IS_OK(status
)) {
68 switch (auth_state
->auth_level
) {
69 case DCERPC_AUTH_LEVEL_PRIVACY
:
70 case DCERPC_AUTH_LEVEL_INTEGRITY
:
71 case DCERPC_AUTH_LEVEL_PACKET
:
74 case DCERPC_AUTH_LEVEL_CONNECT
:
75 if (pkt
->auth_length
!= 0) {
79 case DCERPC_AUTH_LEVEL_NONE
:
80 if (pkt
->auth_length
!= 0) {
81 return NT_STATUS_ACCESS_DENIED
;
86 return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL
;
89 if (pkt
->auth_length
== 0) {
90 return NT_STATUS_RPC_PROTOCOL_ERROR
;
94 return NT_STATUS_INTERNAL_ERROR
;
97 status
= dcerpc_pull_auth_trailer(pkt
, mem_ctx
,
99 &auth
, &auth_length
, false);
100 if (!NT_STATUS_IS_OK(status
)) {
104 if (payload_and_verifier
->length
< auth_length
) {
106 * should be checked in dcerpc_pull_auth_trailer()
108 return NT_STATUS_INTERNAL_ERROR
;
111 payload_and_verifier
->length
-= auth_length
;
113 if (payload_and_verifier
->length
< auth
.auth_pad_length
) {
115 * should be checked in dcerpc_pull_auth_trailer()
117 return NT_STATUS_INTERNAL_ERROR
;
120 if (check_pkt_auth_fields
) {
121 if (auth
.auth_type
!= auth_state
->auth_type
) {
122 return NT_STATUS_ACCESS_DENIED
;
125 if (auth
.auth_level
!= auth_state
->auth_level
) {
126 return NT_STATUS_ACCESS_DENIED
;
129 if (auth
.auth_context_id
!= auth_state
->auth_context_id
) {
130 return NT_STATUS_ACCESS_DENIED
;
134 /* check signature or unseal the packet */
135 switch (auth_state
->auth_level
) {
136 case DCERPC_AUTH_LEVEL_PRIVACY
:
137 status
= gensec_unseal_packet(gensec
,
138 raw_packet
->data
+ payload_offset
,
139 payload_and_verifier
->length
,
142 auth
.credentials
.length
,
144 if (!NT_STATUS_IS_OK(status
)) {
145 return NT_STATUS_RPC_SEC_PKG_ERROR
;
147 memcpy(payload_and_verifier
->data
,
148 raw_packet
->data
+ payload_offset
,
149 payload_and_verifier
->length
);
152 case DCERPC_AUTH_LEVEL_INTEGRITY
:
153 case DCERPC_AUTH_LEVEL_PACKET
:
154 status
= gensec_check_packet(gensec
,
155 payload_and_verifier
->data
,
156 payload_and_verifier
->length
,
159 auth
.credentials
.length
,
161 if (!NT_STATUS_IS_OK(status
)) {
162 return NT_STATUS_RPC_SEC_PKG_ERROR
;
166 case DCERPC_AUTH_LEVEL_CONNECT
:
167 /* for now we ignore possible signatures here */
171 return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL
;
175 * remove the indicated amount of padding
177 * A possible overflow is checked above.
179 payload_and_verifier
->length
-= auth
.auth_pad_length
;
184 NTSTATUS
dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth
*auth_state
,
185 struct gensec_security
*gensec
,
187 DATA_BLOB
*raw_packet
,
189 uint8_t payload_offset
,
190 const DATA_BLOB
*payload
,
191 const struct ncacn_packet
*pkt
)
193 TALLOC_CTX
*frame
= talloc_stackframe();
195 enum ndr_err_code ndr_err
;
196 struct ndr_push
*ndr
= NULL
;
197 uint32_t payload_length
;
198 uint32_t whole_length
;
199 DATA_BLOB blob
= data_blob_null
;
200 DATA_BLOB sig
= data_blob_null
;
201 struct dcerpc_auth _out_auth_info
;
202 struct dcerpc_auth
*out_auth_info
= NULL
;
204 *raw_packet
= data_blob_null
;
206 if (auth_state
== NULL
) {
208 return NT_STATUS_INTERNAL_ERROR
;
211 switch (auth_state
->auth_level
) {
212 case DCERPC_AUTH_LEVEL_PRIVACY
:
213 case DCERPC_AUTH_LEVEL_INTEGRITY
:
214 case DCERPC_AUTH_LEVEL_PACKET
:
217 return NT_STATUS_INTERNAL_ERROR
;
220 if (gensec
== NULL
) {
222 return NT_STATUS_INTERNAL_ERROR
;
225 _out_auth_info
= (struct dcerpc_auth
) {
226 .auth_type
= auth_state
->auth_type
,
227 .auth_level
= auth_state
->auth_level
,
228 .auth_context_id
= auth_state
->auth_context_id
,
230 out_auth_info
= &_out_auth_info
;
233 case DCERPC_AUTH_LEVEL_CONNECT
:
235 * TODO: let the gensec mech decide if it wants to generate a
236 * signature that might be needed for schannel...
240 return NT_STATUS_INTERNAL_ERROR
;
243 if (gensec
== NULL
) {
245 return NT_STATUS_INTERNAL_ERROR
;
249 case DCERPC_AUTH_LEVEL_NONE
:
252 return NT_STATUS_INTERNAL_ERROR
;
258 return NT_STATUS_INTERNAL_ERROR
;
261 ndr
= ndr_push_init_ctx(frame
);
264 return NT_STATUS_NO_MEMORY
;
267 ndr_err
= ndr_push_ncacn_packet(ndr
, NDR_SCALARS
|NDR_BUFFERS
, pkt
);
268 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
270 return ndr_map_error2ntstatus(ndr_err
);
273 if (out_auth_info
!= NULL
) {
275 * pad to 16 byte multiple in the payload portion of the
276 * packet. This matches what w2k3 does. Note that we can't use
277 * ndr_push_align() as that is relative to the start of the
278 * whole packet, whereas w2k8 wants it relative to the start
281 out_auth_info
->auth_pad_length
=
282 DCERPC_AUTH_PAD_LENGTH(payload
->length
);
283 ndr_err
= ndr_push_zero(ndr
, out_auth_info
->auth_pad_length
);
284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
286 return ndr_map_error2ntstatus(ndr_err
);
289 payload_length
= payload
->length
+
290 out_auth_info
->auth_pad_length
;
292 ndr_err
= ndr_push_dcerpc_auth(ndr
, NDR_SCALARS
|NDR_BUFFERS
,
294 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
296 return ndr_map_error2ntstatus(ndr_err
);
299 whole_length
= ndr
->offset
;
301 ndr_err
= ndr_push_zero(ndr
, sig_size
);
302 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
304 return ndr_map_error2ntstatus(ndr_err
);
307 payload_length
= payload
->length
;
308 whole_length
= ndr
->offset
;
311 /* extract the whole packet as a blob */
312 blob
= ndr_push_blob(ndr
);
315 * Setup the frag and auth length in the packet buffer.
316 * This is needed if the GENSEC mech does AEAD signing
317 * of the packet headers. The signature itself will be
320 dcerpc_set_frag_length(&blob
, blob
.length
);
321 dcerpc_set_auth_length(&blob
, sig_size
);
323 /* sign or seal the packet */
324 switch (auth_state
->auth_level
) {
325 case DCERPC_AUTH_LEVEL_PRIVACY
:
326 status
= gensec_seal_packet(gensec
,
328 blob
.data
+ payload_offset
,
333 if (!NT_STATUS_IS_OK(status
)) {
339 case DCERPC_AUTH_LEVEL_INTEGRITY
:
340 case DCERPC_AUTH_LEVEL_PACKET
:
341 status
= gensec_sign_packet(gensec
,
343 blob
.data
+ payload_offset
,
348 if (!NT_STATUS_IS_OK(status
)) {
354 case DCERPC_AUTH_LEVEL_CONNECT
:
355 case DCERPC_AUTH_LEVEL_NONE
:
360 return NT_STATUS_INTERNAL_ERROR
;
363 if (sig
.length
!= sig_size
) {
365 return NT_STATUS_RPC_SEC_PKG_ERROR
;
369 memcpy(blob
.data
+ whole_length
, sig
.data
, sig_size
);
373 talloc_steal(mem_ctx
, raw_packet
->data
);
381 * Save valid, well-formed DCE/RPC stubs to use as a seed for
384 void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX
*mem_ctx
,
386 const char *dump_dir
,
387 const char *iface_name
,
388 ndr_flags_type flags
,
393 const char *sub_dir
= NULL
;
394 TALLOC_CTX
*temp_ctx
= talloc_new(mem_ctx
);
398 DATA_BLOB digest_blob
;
400 uint16_t fuzz_flags
= 0;
403 * We want to save the 'stub' in a per-pipe subdirectory, with
404 * the ndr_fuzz_X header 4 byte header. For the sake of
405 * convenience (this is a developer only function), we mkdir
406 * -p the sub-directories when they are needed.
409 if (dump_dir
== NULL
) {
413 temp_ctx
= talloc_stackframe();
415 sub_dir
= talloc_asprintf(temp_ctx
, "%s/%s",
418 if (sub_dir
== NULL
) {
419 talloc_free(temp_ctx
);
422 ret
= mkdir_p(sub_dir
, 0755);
423 if (ret
&& errno
!= EEXIST
) {
424 DBG_ERR("could not create %s\n", sub_dir
);
425 talloc_free(temp_ctx
);
429 blob
.length
= raw_blob
.length
+ 4;
430 blob
.data
= talloc_array(sub_dir
,
433 if (blob
.data
== NULL
) {
434 DBG_ERR("could not allocate for fuzz seeds! (%s)\n",
436 talloc_free(temp_ctx
);
443 if (flags
& NDR_IN
) {
445 } else if (flags
& NDR_OUT
) {
449 SSVAL(blob
.data
, 0, fuzz_flags
);
450 SSVAL(blob
.data
, 2, opnum
);
452 memcpy(&blob
.data
[4],
457 * This matches how oss-fuzz names the corpus input files, due
458 * to a preference from libFuzzer
460 rc
= gnutls_hash_fast(GNUTLS_DIG_SHA1
,
466 * This prints a better error message, eg if SHA1 is
469 NTSTATUS status
= gnutls_error_to_ntstatus(rc
,
470 NT_STATUS_HASH_NOT_SUPPORTED
);
471 DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s\n",
473 talloc_free(temp_ctx
);
477 digest_blob
.data
= digest
;
478 digest_blob
.length
= sizeof(digest
);
479 digest_hex
= data_blob_hex_string_lower(temp_ctx
, &digest_blob
);
481 fname
= talloc_asprintf(temp_ctx
, "%s/%s",
485 talloc_free(temp_ctx
);
490 * If this fails, it is most likely because that file already
491 * exists. This is fine, it means we already have this
498 talloc_free(temp_ctx
);
501 #endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */