]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
CVE-2021-23192 librpc: Remove the gensec dependency from library dcerpc-binding
authorVolker Lendecke <vl@samba.org>
Fri, 2 Apr 2021 11:41:21 +0000 (13:41 +0200)
committerJule Anger <janger@samba.org>
Mon, 8 Nov 2021 09:52:13 +0000 (10:52 +0100)
This means yet another library, but having to depend on gensec just
for dcerpc_parse_binding() and basic packet parsing seems like a bit
overkill to me.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Tue Apr  6 23:33:14 UTC 2021 on sn-devel-184

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14875

(cherry picked from commit 4d3b6506d30e4bf302f832493dad00a83b73d370)

libcli/auth/wscript_build
librpc/rpc/dcerpc_pkt_auth.c [new file with mode: 0644]
librpc/rpc/dcerpc_pkt_auth.h [new file with mode: 0644]
librpc/rpc/dcerpc_util.c
librpc/rpc/dcerpc_util.h
librpc/rpc/dcesrv_auth.c
librpc/wscript_build
source3/wscript_build
source4/librpc/rpc/dcerpc.c
source4/librpc/wscript_build

index 2a6a7468e4578be36efca0eedeb66d66fd0ad6b1..24ab68fac1e3f524a298cdb630d233bd03192ffb 100644 (file)
@@ -30,7 +30,15 @@ bld.SAMBA_SUBSYSTEM('COMMON_SCHANNEL',
 
 bld.SAMBA_SUBSYSTEM('NETLOGON_CREDS_CLI',
         source='netlogon_creds_cli.c',
-        deps='dbwrap util_tdb tevent-util samba-hostconfig RPC_NDR_NETLOGON NDR_NETLOGON'
+        deps='''
+        dbwrap
+        util_tdb
+        tevent-util
+        samba-hostconfig
+        gensec
+        RPC_NDR_NETLOGON
+        NDR_NETLOGON
+        '''
         )
 
 bld.SAMBA_SUBSYSTEM('PAM_ERRORS',
diff --git a/librpc/rpc/dcerpc_pkt_auth.c b/librpc/rpc/dcerpc_pkt_auth.c
new file mode 100644 (file)
index 0000000..322d749
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+   Unix SMB/CIFS implementation.
+   raw dcerpc operations
+
+   Copyright (C) Andrew Tridgell 2003-2005
+   Copyright (C) Jelmer Vernooij 2004-2005
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/network.h"
+#include <tevent.h>
+#include "lib/util/talloc_stack.h"
+#include "lib/util/debug.h"
+#include "lib/util/byteorder.h"
+#include "lib/util/samba_util.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/rpc/dcerpc_util.h"
+#include "librpc/rpc/dcerpc_pkt_auth.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "rpc_common.h"
+#include "lib/util/bitmap.h"
+#include "auth/gensec/gensec.h"
+#include "lib/util/mkdir_p.h"
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/crypto.h>
+
+NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
+                                   struct gensec_security *gensec,
+                                   TALLOC_CTX *mem_ctx,
+                                   enum dcerpc_pkt_type ptype,
+                                   uint8_t required_flags,
+                                   uint8_t optional_flags,
+                                   uint8_t payload_offset,
+                                   DATA_BLOB *payload_and_verifier,
+                                   DATA_BLOB *raw_packet,
+                                   const struct ncacn_packet *pkt)
+{
+       NTSTATUS status;
+       struct dcerpc_auth auth;
+       uint32_t auth_length;
+
+       if (auth_state == NULL) {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       status = dcerpc_verify_ncacn_packet_header(pkt, ptype,
+                                       payload_and_verifier->length,
+                                       required_flags, optional_flags);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       switch (auth_state->auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+       case DCERPC_AUTH_LEVEL_PACKET:
+               break;
+
+       case DCERPC_AUTH_LEVEL_CONNECT:
+               if (pkt->auth_length != 0) {
+                       break;
+               }
+               return NT_STATUS_OK;
+       case DCERPC_AUTH_LEVEL_NONE:
+               if (pkt->auth_length != 0) {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+               return NT_STATUS_OK;
+
+       default:
+               return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
+       }
+
+       if (pkt->auth_length == 0) {
+               return NT_STATUS_RPC_PROTOCOL_ERROR;
+       }
+
+       if (gensec == NULL) {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
+                                         payload_and_verifier,
+                                         &auth, &auth_length, false);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (payload_and_verifier->length < auth_length) {
+               /*
+                * should be checked in dcerpc_pull_auth_trailer()
+                */
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       payload_and_verifier->length -= auth_length;
+
+       if (payload_and_verifier->length < auth.auth_pad_length) {
+               /*
+                * should be checked in dcerpc_pull_auth_trailer()
+                */
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       if (auth.auth_type != auth_state->auth_type) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       if (auth.auth_level != auth_state->auth_level) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       if (auth.auth_context_id != auth_state->auth_context_id) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       /* check signature or unseal the packet */
+       switch (auth_state->auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+               status = gensec_unseal_packet(gensec,
+                                             raw_packet->data + payload_offset,
+                                             payload_and_verifier->length,
+                                             raw_packet->data,
+                                             raw_packet->length -
+                                             auth.credentials.length,
+                                             &auth.credentials);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return NT_STATUS_RPC_SEC_PKG_ERROR;
+               }
+               memcpy(payload_and_verifier->data,
+                      raw_packet->data + payload_offset,
+                      payload_and_verifier->length);
+               break;
+
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+       case DCERPC_AUTH_LEVEL_PACKET:
+               status = gensec_check_packet(gensec,
+                                            payload_and_verifier->data,
+                                            payload_and_verifier->length,
+                                            raw_packet->data,
+                                            raw_packet->length -
+                                            auth.credentials.length,
+                                            &auth.credentials);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return NT_STATUS_RPC_SEC_PKG_ERROR;
+               }
+               break;
+
+       case DCERPC_AUTH_LEVEL_CONNECT:
+               /* for now we ignore possible signatures here */
+               break;
+
+       default:
+               return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
+       }
+
+       /*
+        * remove the indicated amount of padding
+        *
+        * A possible overflow is checked above.
+        */
+       payload_and_verifier->length -= auth.auth_pad_length;
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
+                                   struct gensec_security *gensec,
+                                   TALLOC_CTX *mem_ctx,
+                                   DATA_BLOB *raw_packet,
+                                   size_t sig_size,
+                                   uint8_t payload_offset,
+                                   const DATA_BLOB *payload,
+                                   const struct ncacn_packet *pkt)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       NTSTATUS status;
+       enum ndr_err_code ndr_err;
+       struct ndr_push *ndr = NULL;
+       uint32_t payload_length;
+       uint32_t whole_length;
+       DATA_BLOB blob = data_blob_null;
+       DATA_BLOB sig = data_blob_null;
+       struct dcerpc_auth _out_auth_info;
+       struct dcerpc_auth *out_auth_info = NULL;
+
+       *raw_packet = data_blob_null;
+
+       if (auth_state == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       switch (auth_state->auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+       case DCERPC_AUTH_LEVEL_PACKET:
+               if (sig_size == 0) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+
+               if (gensec == NULL) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+
+               _out_auth_info = (struct dcerpc_auth) {
+                       .auth_type = auth_state->auth_type,
+                       .auth_level = auth_state->auth_level,
+                       .auth_context_id = auth_state->auth_context_id,
+               };
+               out_auth_info = &_out_auth_info;
+               break;
+
+       case DCERPC_AUTH_LEVEL_CONNECT:
+               /*
+                * TODO: let the gensec mech decide if it wants to generate a
+                *       signature that might be needed for schannel...
+                */
+               if (sig_size != 0) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+
+               if (gensec == NULL) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+               break;
+
+       case DCERPC_AUTH_LEVEL_NONE:
+               if (sig_size != 0) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+               break;
+
+       default:
+               TALLOC_FREE(frame);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       ndr = ndr_push_init_ctx(frame);
+       if (ndr == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               TALLOC_FREE(frame);
+               return ndr_map_error2ntstatus(ndr_err);
+       }
+
+       if (out_auth_info != NULL) {
+               /*
+                * pad to 16 byte multiple in the payload portion of the
+                * packet. This matches what w2k3 does. Note that we can't use
+                * ndr_push_align() as that is relative to the start of the
+                * whole packet, whereas w2k8 wants it relative to the start
+                * of the stub.
+                */
+               out_auth_info->auth_pad_length =
+                       DCERPC_AUTH_PAD_LENGTH(payload->length);
+               ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       TALLOC_FREE(frame);
+                       return ndr_map_error2ntstatus(ndr_err);
+               }
+
+               payload_length = payload->length +
+                       out_auth_info->auth_pad_length;
+
+               ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
+                                              out_auth_info);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       TALLOC_FREE(frame);
+                       return ndr_map_error2ntstatus(ndr_err);
+               }
+
+               whole_length = ndr->offset;
+
+               ndr_err = ndr_push_zero(ndr, sig_size);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       TALLOC_FREE(frame);
+                       return ndr_map_error2ntstatus(ndr_err);
+               }
+       } else {
+               payload_length = payload->length;
+               whole_length = ndr->offset;
+       }
+
+       /* extract the whole packet as a blob */
+       blob = ndr_push_blob(ndr);
+
+       /*
+        * Setup the frag and auth length in the packet buffer.
+        * This is needed if the GENSEC mech does AEAD signing
+        * of the packet headers. The signature itself will be
+        * appended later.
+        */
+       dcerpc_set_frag_length(&blob, blob.length);
+       dcerpc_set_auth_length(&blob, sig_size);
+
+       /* sign or seal the packet */
+       switch (auth_state->auth_level) {
+       case DCERPC_AUTH_LEVEL_PRIVACY:
+               status = gensec_seal_packet(gensec,
+                                           frame,
+                                           blob.data + payload_offset,
+                                           payload_length,
+                                           blob.data,
+                                           whole_length,
+                                           &sig);
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+               break;
+
+       case DCERPC_AUTH_LEVEL_INTEGRITY:
+       case DCERPC_AUTH_LEVEL_PACKET:
+               status = gensec_sign_packet(gensec,
+                                           frame,
+                                           blob.data + payload_offset,
+                                           payload_length,
+                                           blob.data,
+                                           whole_length,
+                                           &sig);
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+               break;
+
+       case DCERPC_AUTH_LEVEL_CONNECT:
+       case DCERPC_AUTH_LEVEL_NONE:
+               break;
+
+       default:
+               TALLOC_FREE(frame);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       if (sig.length != sig_size) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_RPC_SEC_PKG_ERROR;
+       }
+
+       if (sig_size != 0) {
+               memcpy(blob.data + whole_length, sig.data, sig_size);
+       }
+
+       *raw_packet = blob;
+       talloc_steal(mem_ctx, raw_packet->data);
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+}
+
+#ifdef DEVELOPER
+
+/*
+ * Save valid, well-formed DCE/RPC stubs to use as a seed for
+ * ndr_fuzz_X
+ */
+void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx,
+                              DATA_BLOB raw_blob,
+                              const char *dump_dir,
+                              const char *iface_name,
+                              int flags,
+                              int opnum,
+                              bool ndr64)
+{
+       char *fname = NULL;
+       const char *sub_dir = NULL;
+       TALLOC_CTX *temp_ctx = talloc_new(mem_ctx);
+       DATA_BLOB blob;
+       int ret, rc;
+       uint8_t digest[20];
+       DATA_BLOB digest_blob;
+       char *digest_hex;
+       uint16_t fuzz_flags = 0;
+
+       /*
+        * We want to save the 'stub' in a per-pipe subdirectory, with
+        * the ndr_fuzz_X header 4 byte header. For the sake of
+        * convenience (this is a developer only function), we mkdir
+        * -p the sub-directories when they are needed.
+        */
+
+       if (dump_dir == NULL) {
+               return;
+       }
+
+       temp_ctx = talloc_stackframe();
+
+       sub_dir = talloc_asprintf(temp_ctx, "%s/%s",
+                                 dump_dir,
+                                 iface_name);
+       if (sub_dir == NULL) {
+               talloc_free(temp_ctx);
+               return;
+       }
+       ret = mkdir_p(sub_dir, 0755);
+       if (ret && errno != EEXIST) {
+               DBG_ERR("could not create %s\n", sub_dir);
+               talloc_free(temp_ctx);
+               return;
+       }
+
+       blob.length = raw_blob.length + 4;
+       blob.data = talloc_array(sub_dir,
+                                uint8_t,
+                                blob.length);
+       if (blob.data == NULL) {
+               DBG_ERR("could not allocate for fuzz seeds! (%s)\n",
+                       iface_name);
+               talloc_free(temp_ctx);
+               return;
+       }
+
+       if (ndr64) {
+               fuzz_flags = 4;
+       }
+       if (flags & NDR_IN) {
+               fuzz_flags |= 1;
+       } else if (flags & NDR_OUT) {
+               fuzz_flags |= 2;
+       }
+
+       SSVAL(blob.data, 0, fuzz_flags);
+       SSVAL(blob.data, 2, opnum);
+
+       memcpy(&blob.data[4],
+              raw_blob.data,
+              raw_blob.length);
+
+       /*
+        * This matches how oss-fuzz names the corpus input files, due
+        * to a preference from libFuzzer
+        */
+       rc = gnutls_hash_fast(GNUTLS_DIG_SHA1,
+                             blob.data,
+                             blob.length,
+                             digest);
+       if (rc < 0) {
+               /*
+                * This prints a better error message, eg if SHA1 is
+                * disabled
+                */
+               NTSTATUS status = gnutls_error_to_ntstatus(rc,
+                                                 NT_STATUS_HASH_NOT_SUPPORTED);
+               DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s",
+                       nt_errstr(status));
+               talloc_free(temp_ctx);
+               return;
+       }
+
+       digest_blob.data = digest;
+       digest_blob.length = sizeof(digest);
+       digest_hex = data_blob_hex_string_lower(temp_ctx, &digest_blob);
+
+       fname = talloc_asprintf(temp_ctx, "%s/%s",
+                               sub_dir,
+                               digest_hex);
+       if (fname == NULL) {
+               talloc_free(temp_ctx);
+               return;
+       }
+
+       /*
+        * If this fails, it is most likely because that file already
+        * exists.  This is fine, it means we already have this
+        * sample
+        */
+       file_save(fname,
+                 blob.data,
+                 blob.length);
+
+       talloc_free(temp_ctx);
+}
+
+#endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */
diff --git a/librpc/rpc/dcerpc_pkt_auth.h b/librpc/rpc/dcerpc_pkt_auth.h
new file mode 100644 (file)
index 0000000..c0d23b9
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Stefan Metzmacher 2010-2011
+   Copyright (C) Andrew Tridgell 2010-2011
+   Copyright (C) Simo Sorce 2010
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LIBRPC_RPC_DCERPC_PKT_AUTH_H__
+#define __LIBRPC_RPC_DCERPC_PKT_AUTH_H__
+
+#include "replace.h"
+#include <talloc.h>
+#include "lib/util/data_blob.h"
+#include "libcli/util/ntstatus.h"
+#include "librpc/rpc/rpc_common.h"
+#include "librpc/gen_ndr/dcerpc.h"
+
+NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
+                                   struct gensec_security *gensec,
+                                   TALLOC_CTX *mem_ctx,
+                                   enum dcerpc_pkt_type ptype,
+                                   uint8_t required_flags,
+                                   uint8_t optional_flags,
+                                   uint8_t payload_offset,
+                                   DATA_BLOB *payload_and_verifier,
+                                   DATA_BLOB *raw_packet,
+                                   const struct ncacn_packet *pkt);
+NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
+                                   struct gensec_security *gensec,
+                                   TALLOC_CTX *mem_ctx,
+                                   DATA_BLOB *raw_packet,
+                                   size_t sig_size,
+                                   uint8_t payload_offset,
+                                   const DATA_BLOB *payload,
+                                   const struct ncacn_packet *pkt);
+struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
+                                                struct tevent_context *ev,
+                                                struct tstream_context *stream);
+NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
+                                      TALLOC_CTX *mem_ctx,
+                                      struct ncacn_packet **pkt,
+                                      DATA_BLOB *buffer);
+
+#endif
index 6a160e12023255db4b273d8b28243b137cd14e39..f1b80efde69fda22f987d3265212ab4bb3cb4c60 100644 (file)
 #include "librpc/gen_ndr/ndr_dcerpc.h"
 #include "rpc_common.h"
 #include "lib/util/bitmap.h"
-#include "auth/gensec/gensec.h"
-#include "lib/util/mkdir_p.h"
-#include "lib/crypto/gnutls_helpers.h"
-#include <gnutls/crypto.h>
 
 /* we need to be able to get/set the fragment length without doing a full
    decode */
@@ -484,340 +480,6 @@ NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
        return NT_STATUS_OK;
 }
 
-NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
-                                   struct gensec_security *gensec,
-                                   TALLOC_CTX *mem_ctx,
-                                   enum dcerpc_pkt_type ptype,
-                                   uint8_t required_flags,
-                                   uint8_t optional_flags,
-                                   uint8_t payload_offset,
-                                   DATA_BLOB *payload_and_verifier,
-                                   DATA_BLOB *raw_packet,
-                                   const struct ncacn_packet *pkt)
-{
-       NTSTATUS status;
-       struct dcerpc_auth auth;
-       uint32_t auth_length;
-
-       if (auth_state == NULL) {
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       status = dcerpc_verify_ncacn_packet_header(pkt, ptype,
-                                       payload_and_verifier->length,
-                                       required_flags, optional_flags);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       switch (auth_state->auth_level) {
-       case DCERPC_AUTH_LEVEL_PRIVACY:
-       case DCERPC_AUTH_LEVEL_INTEGRITY:
-       case DCERPC_AUTH_LEVEL_PACKET:
-               break;
-
-       case DCERPC_AUTH_LEVEL_CONNECT:
-               if (pkt->auth_length != 0) {
-                       break;
-               }
-               return NT_STATUS_OK;
-       case DCERPC_AUTH_LEVEL_NONE:
-               if (pkt->auth_length != 0) {
-                       return NT_STATUS_ACCESS_DENIED;
-               }
-               return NT_STATUS_OK;
-
-       default:
-               return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
-       }
-
-       if (pkt->auth_length == 0) {
-               return NT_STATUS_RPC_PROTOCOL_ERROR;
-       }
-
-       if (gensec == NULL) {
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
-                                         payload_and_verifier,
-                                         &auth, &auth_length, false);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       if (payload_and_verifier->length < auth_length) {
-               /*
-                * should be checked in dcerpc_pull_auth_trailer()
-                */
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       payload_and_verifier->length -= auth_length;
-
-       if (payload_and_verifier->length < auth.auth_pad_length) {
-               /*
-                * should be checked in dcerpc_pull_auth_trailer()
-                */
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       if (auth.auth_type != auth_state->auth_type) {
-               return NT_STATUS_ACCESS_DENIED;
-       }
-
-       if (auth.auth_level != auth_state->auth_level) {
-               return NT_STATUS_ACCESS_DENIED;
-       }
-
-       if (auth.auth_context_id != auth_state->auth_context_id) {
-               return NT_STATUS_ACCESS_DENIED;
-       }
-
-       /* check signature or unseal the packet */
-       switch (auth_state->auth_level) {
-       case DCERPC_AUTH_LEVEL_PRIVACY:
-               status = gensec_unseal_packet(gensec,
-                                             raw_packet->data + payload_offset,
-                                             payload_and_verifier->length,
-                                             raw_packet->data,
-                                             raw_packet->length -
-                                             auth.credentials.length,
-                                             &auth.credentials);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return NT_STATUS_RPC_SEC_PKG_ERROR;
-               }
-               memcpy(payload_and_verifier->data,
-                      raw_packet->data + payload_offset,
-                      payload_and_verifier->length);
-               break;
-
-       case DCERPC_AUTH_LEVEL_INTEGRITY:
-       case DCERPC_AUTH_LEVEL_PACKET:
-               status = gensec_check_packet(gensec,
-                                            payload_and_verifier->data,
-                                            payload_and_verifier->length,
-                                            raw_packet->data,
-                                            raw_packet->length -
-                                            auth.credentials.length,
-                                            &auth.credentials);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return NT_STATUS_RPC_SEC_PKG_ERROR;
-               }
-               break;
-
-       case DCERPC_AUTH_LEVEL_CONNECT:
-               /* for now we ignore possible signatures here */
-               break;
-
-       default:
-               return NT_STATUS_RPC_UNSUPPORTED_AUTHN_LEVEL;
-       }
-
-       /*
-        * remove the indicated amount of padding
-        *
-        * A possible overflow is checked above.
-        */
-       payload_and_verifier->length -= auth.auth_pad_length;
-
-       return NT_STATUS_OK;
-}
-
-NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
-                                   struct gensec_security *gensec,
-                                   TALLOC_CTX *mem_ctx,
-                                   DATA_BLOB *raw_packet,
-                                   size_t sig_size,
-                                   uint8_t payload_offset,
-                                   const DATA_BLOB *payload,
-                                   const struct ncacn_packet *pkt)
-{
-       TALLOC_CTX *frame = talloc_stackframe();
-       NTSTATUS status;
-       enum ndr_err_code ndr_err;
-       struct ndr_push *ndr = NULL;
-       uint32_t payload_length;
-       uint32_t whole_length;
-       DATA_BLOB blob = data_blob_null;
-       DATA_BLOB sig = data_blob_null;
-       struct dcerpc_auth _out_auth_info;
-       struct dcerpc_auth *out_auth_info = NULL;
-
-       *raw_packet = data_blob_null;
-
-       if (auth_state == NULL) {
-               TALLOC_FREE(frame);
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       switch (auth_state->auth_level) {
-       case DCERPC_AUTH_LEVEL_PRIVACY:
-       case DCERPC_AUTH_LEVEL_INTEGRITY:
-       case DCERPC_AUTH_LEVEL_PACKET:
-               if (sig_size == 0) {
-                       TALLOC_FREE(frame);
-                       return NT_STATUS_INTERNAL_ERROR;
-               }
-
-               if (gensec == NULL) {
-                       TALLOC_FREE(frame);
-                       return NT_STATUS_INTERNAL_ERROR;
-               }
-
-               _out_auth_info = (struct dcerpc_auth) {
-                       .auth_type = auth_state->auth_type,
-                       .auth_level = auth_state->auth_level,
-                       .auth_context_id = auth_state->auth_context_id,
-               };
-               out_auth_info = &_out_auth_info;
-               break;
-
-       case DCERPC_AUTH_LEVEL_CONNECT:
-               /*
-                * TODO: let the gensec mech decide if it wants to generate a
-                *       signature that might be needed for schannel...
-                */
-               if (sig_size != 0) {
-                       TALLOC_FREE(frame);
-                       return NT_STATUS_INTERNAL_ERROR;
-               }
-
-               if (gensec == NULL) {
-                       TALLOC_FREE(frame);
-                       return NT_STATUS_INTERNAL_ERROR;
-               }
-               break;
-
-       case DCERPC_AUTH_LEVEL_NONE:
-               if (sig_size != 0) {
-                       TALLOC_FREE(frame);
-                       return NT_STATUS_INTERNAL_ERROR;
-               }
-               break;
-
-       default:
-               TALLOC_FREE(frame);
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       ndr = ndr_push_init_ctx(frame);
-       if (ndr == NULL) {
-               TALLOC_FREE(frame);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
-       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-               TALLOC_FREE(frame);
-               return ndr_map_error2ntstatus(ndr_err);
-       }
-
-       if (out_auth_info != NULL) {
-               /*
-                * pad to 16 byte multiple in the payload portion of the
-                * packet. This matches what w2k3 does. Note that we can't use
-                * ndr_push_align() as that is relative to the start of the
-                * whole packet, whereas w2k8 wants it relative to the start
-                * of the stub.
-                */
-               out_auth_info->auth_pad_length =
-                       DCERPC_AUTH_PAD_LENGTH(payload->length);
-               ndr_err = ndr_push_zero(ndr, out_auth_info->auth_pad_length);
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                       TALLOC_FREE(frame);
-                       return ndr_map_error2ntstatus(ndr_err);
-               }
-
-               payload_length = payload->length +
-                       out_auth_info->auth_pad_length;
-
-               ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
-                                              out_auth_info);
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                       TALLOC_FREE(frame);
-                       return ndr_map_error2ntstatus(ndr_err);
-               }
-
-               whole_length = ndr->offset;
-
-               ndr_err = ndr_push_zero(ndr, sig_size);
-               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-                       TALLOC_FREE(frame);
-                       return ndr_map_error2ntstatus(ndr_err);
-               }
-       } else {
-               payload_length = payload->length;
-               whole_length = ndr->offset;
-       }
-
-       /* extract the whole packet as a blob */
-       blob = ndr_push_blob(ndr);
-
-       /*
-        * Setup the frag and auth length in the packet buffer.
-        * This is needed if the GENSEC mech does AEAD signing
-        * of the packet headers. The signature itself will be
-        * appended later.
-        */
-       dcerpc_set_frag_length(&blob, blob.length);
-       dcerpc_set_auth_length(&blob, sig_size);
-
-       /* sign or seal the packet */
-       switch (auth_state->auth_level) {
-       case DCERPC_AUTH_LEVEL_PRIVACY:
-               status = gensec_seal_packet(gensec,
-                                           frame,
-                                           blob.data + payload_offset,
-                                           payload_length,
-                                           blob.data,
-                                           whole_length,
-                                           &sig);
-               if (!NT_STATUS_IS_OK(status)) {
-                       TALLOC_FREE(frame);
-                       return status;
-               }
-               break;
-
-       case DCERPC_AUTH_LEVEL_INTEGRITY:
-       case DCERPC_AUTH_LEVEL_PACKET:
-               status = gensec_sign_packet(gensec,
-                                           frame,
-                                           blob.data + payload_offset,
-                                           payload_length,
-                                           blob.data,
-                                           whole_length,
-                                           &sig);
-               if (!NT_STATUS_IS_OK(status)) {
-                       TALLOC_FREE(frame);
-                       return status;
-               }
-               break;
-
-       case DCERPC_AUTH_LEVEL_CONNECT:
-       case DCERPC_AUTH_LEVEL_NONE:
-               break;
-
-       default:
-               TALLOC_FREE(frame);
-               return NT_STATUS_INTERNAL_ERROR;
-       }
-
-       if (sig.length != sig_size) {
-               TALLOC_FREE(frame);
-               return NT_STATUS_RPC_SEC_PKG_ERROR;
-       }
-
-       if (sig_size != 0) {
-               memcpy(blob.data + whole_length, sig.data, sig_size);
-       }
-
-       *raw_packet = blob;
-       talloc_steal(mem_ctx, raw_packet->data);
-       TALLOC_FREE(frame);
-       return NT_STATUS_OK;
-}
-
 struct dcerpc_read_ncacn_packet_state {
 #if 0
        struct {
@@ -1472,129 +1134,3 @@ void dcerpc_log_packet(const char *packet_log_dir,
                free(name);
        }
 }
-
-
-#ifdef DEVELOPER
-
-/*
- * Save valid, well-formed DCE/RPC stubs to use as a seed for
- * ndr_fuzz_X
- */
-void dcerpc_save_ndr_fuzz_seed(TALLOC_CTX *mem_ctx,
-                              DATA_BLOB raw_blob,
-                              const char *dump_dir,
-                              const char *iface_name,
-                              int flags,
-                              int opnum,
-                              bool ndr64)
-{
-       char *fname = NULL;
-       const char *sub_dir = NULL;
-       TALLOC_CTX *temp_ctx = talloc_new(mem_ctx);
-       DATA_BLOB blob;
-       int ret, rc;
-       uint8_t digest[20];
-       DATA_BLOB digest_blob;
-       char *digest_hex;
-       uint16_t fuzz_flags = 0;
-
-       /*
-        * We want to save the 'stub' in a per-pipe subdirectory, with
-        * the ndr_fuzz_X header 4 byte header. For the sake of
-        * convenience (this is a developer only function), we mkdir
-        * -p the sub-directories when they are needed.
-        */
-
-       if (dump_dir == NULL) {
-               return;
-       }
-
-       temp_ctx = talloc_stackframe();
-
-       sub_dir = talloc_asprintf(temp_ctx, "%s/%s",
-                                 dump_dir,
-                                 iface_name);
-       if (sub_dir == NULL) {
-               talloc_free(temp_ctx);
-               return;
-       }
-       ret = mkdir_p(sub_dir, 0755);
-       if (ret && errno != EEXIST) {
-               DBG_ERR("could not create %s\n", sub_dir);
-               talloc_free(temp_ctx);
-               return;
-       }
-
-       blob.length = raw_blob.length + 4;
-       blob.data = talloc_array(sub_dir,
-                                uint8_t,
-                                blob.length);
-       if (blob.data == NULL) {
-               DBG_ERR("could not allocate for fuzz seeds! (%s)\n",
-                       iface_name);
-               talloc_free(temp_ctx);
-               return;
-       }
-
-       if (ndr64) {
-               fuzz_flags = 4;
-       }
-       if (flags & NDR_IN) {
-               fuzz_flags |= 1;
-       } else if (flags & NDR_OUT) {
-               fuzz_flags |= 2;
-       }
-
-       SSVAL(blob.data, 0, fuzz_flags);
-       SSVAL(blob.data, 2, opnum);
-
-       memcpy(&blob.data[4],
-              raw_blob.data,
-              raw_blob.length);
-
-       /*
-        * This matches how oss-fuzz names the corpus input files, due
-        * to a preference from libFuzzer
-        */
-       rc = gnutls_hash_fast(GNUTLS_DIG_SHA1,
-                             blob.data,
-                             blob.length,
-                             digest);
-       if (rc < 0) {
-               /*
-                * This prints a better error message, eg if SHA1 is
-                * disabled
-                */
-               NTSTATUS status = gnutls_error_to_ntstatus(rc,
-                                                 NT_STATUS_HASH_NOT_SUPPORTED);
-               DBG_ERR("Failed to generate SHA1 to save fuzz seed: %s",
-                       nt_errstr(status));
-               talloc_free(temp_ctx);
-               return;
-       }
-
-       digest_blob.data = digest;
-       digest_blob.length = sizeof(digest);
-       digest_hex = data_blob_hex_string_lower(temp_ctx, &digest_blob);
-
-       fname = talloc_asprintf(temp_ctx, "%s/%s",
-                               sub_dir,
-                               digest_hex);
-       if (fname == NULL) {
-               talloc_free(temp_ctx);
-               return;
-       }
-
-       /*
-        * If this fails, it is most likely because that file already
-        * exists.  This is fine, it means we already have this
-        * sample
-        */
-       file_save(fname,
-                 blob.data,
-                 blob.length);
-
-       talloc_free(temp_ctx);
-}
-
-#endif /*if DEVELOPER, enveloping _dcesrv_save_ndr_fuzz_seed() */
index 0ecaf428c3c93df04c08c37c107c615c04a8f1d9..a9bc7bd383208f9b69250f436f30fab033fcdaf3 100644 (file)
@@ -74,24 +74,6 @@ NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
                                           size_t max_auth_info,
                                           uint8_t required_flags,
                                           uint8_t optional_flags);
-NTSTATUS dcerpc_ncacn_pull_pkt_auth(const struct dcerpc_auth *auth_state,
-                                   struct gensec_security *gensec,
-                                   TALLOC_CTX *mem_ctx,
-                                   enum dcerpc_pkt_type ptype,
-                                   uint8_t required_flags,
-                                   uint8_t optional_flags,
-                                   uint8_t payload_offset,
-                                   DATA_BLOB *payload_and_verifier,
-                                   DATA_BLOB *raw_packet,
-                                   const struct ncacn_packet *pkt);
-NTSTATUS dcerpc_ncacn_push_pkt_auth(const struct dcerpc_auth *auth_state,
-                                   struct gensec_security *gensec,
-                                   TALLOC_CTX *mem_ctx,
-                                   DATA_BLOB *raw_packet,
-                                   size_t sig_size,
-                                   uint8_t payload_offset,
-                                   const DATA_BLOB *payload,
-                                   const struct ncacn_packet *pkt);
 struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
                                                 struct tevent_context *ev,
                                                 struct tstream_context *stream);
index f7919ebf57558d54c4dce49e3e3194657160588a..8dda86d88e2cc0e0fe6024a258345d6b51e4e243 100644 (file)
@@ -24,6 +24,7 @@
 #include "librpc/rpc/dcesrv_core.h"
 #include "librpc/rpc/dcesrv_core_proto.h"
 #include "librpc/rpc/dcerpc_util.h"
+#include "librpc/rpc/dcerpc_pkt_auth.h"
 #include "librpc/gen_ndr/ndr_dcerpc.h"
 #include "auth/credentials/credentials.h"
 #include "auth/gensec/gensec.h"
index 8f31d59d3b5a9abece3b1ee41870d8d7c9b0efdf..a1c3c994876c1b9a1f7bc274fbe87751d1af164a 100644 (file)
@@ -655,12 +655,24 @@ bld.SAMBA_LIBRARY('ndr',
     )
 
 bld.SAMBA_LIBRARY('dcerpc-binding',
-    source='rpc/dcerpc_error.c rpc/binding.c rpc/dcerpc_util.c rpc/binding_handle.c',
-    deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util gensec',
+    source='''
+    rpc/dcerpc_error.c
+    rpc/binding.c
+    rpc/dcerpc_util.c
+    rpc/binding_handle.c
+    ''',
+    deps='ndr tevent NDR_DCERPC LIBTSOCKET tevent-util',
     pc_files=[],
     public_headers='rpc/rpc_common.h',
     vnum='0.0.1')
 
+bld.SAMBA_LIBRARY('dcerpc-pkt-auth',
+                  private_library=True,
+                  source='''
+                   rpc/dcerpc_pkt_auth.c
+                   ''',
+                  deps='dcerpc-binding gensec')
+
 bld.SAMBA_LIBRARY('dcerpc-server-core',
     source='''
            rpc/dcesrv_core.c
@@ -669,7 +681,14 @@ bld.SAMBA_LIBRARY('dcerpc-server-core',
            rpc/dcesrv_reply.c
            rpc/dcesrv_handles.c
            ''',
-    deps='ndr dcerpc-binding samba-util-core gnutls GNUTLS_HELPERS',
+    deps='''
+    ndr
+    dcerpc-binding
+    samba-util-core
+    gnutls
+    GNUTLS_HELPERS
+    dcerpc-pkt-auth
+    ''',
     pc_files=[],
     public_headers='rpc/dcesrv_core.h',
     autoproto='rpc/dcesrv_core_proto.h',
index d86a9fcadbfca2c4a613acc8e1373d789b0db472..46c914c7b22457a586d689849541f862b651179c 100644 (file)
@@ -1032,9 +1032,11 @@ bld.SAMBA3_LIBRARY('cli_spoolss',
                           rpc_client/init_spoolss.c
                           ''',
                    deps='''
-                        RPC_NDR_SPOOLSS
-                        smbconf
-                        secrets3''',
+                   RPC_NDR_SPOOLSS
+                   smbconf
+                   secrets3
+                   gensec
+                   ''',
                    private_library=True)
 
 bld.SAMBA3_SUBSYSTEM('LIBCLI_WINREG',
index f97263dcc5b0996653d14951feb07ded40e1fb3a..4847e8a020049bda3e2b84e0e165329eeac75a97 100644 (file)
@@ -27,6 +27,7 @@
 #include "librpc/rpc/dcerpc.h"
 #include "librpc/rpc/dcerpc_proto.h"
 #include "librpc/rpc/dcerpc_util.h"
+#include "librpc/rpc/dcerpc_pkt_auth.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/gen_ndr/ndr_dcerpc.h"
 #include "auth/gensec/gensec.h"
index ea9c4853d7aa5198347a45ac10fa03c4ccbc4668..511008d919d1aaeca69c9482666c5e05c3230f80 100644 (file)
@@ -157,7 +157,26 @@ bld.SAMBA_LIBRARY('dcerpc',
        rpc/dcerpc_roh_channel_in.c rpc/dcerpc_roh_channel_out.c rpc/dcerpc_roh.c
        rpc/dcerpc_connect.c rpc/dcerpc_secondary.c''',
        pc_files='dcerpc.pc',
-       deps='samba_socket LIBCLI_RESOLVE LIBCLI_SMB LIBCLI_SMB2 ndr NDR_DCERPC RPC_NDR_EPMAPPER NDR_SCHANNEL RPC_NDR_NETLOGON RPC_NDR_MGMT gensec LIBCLI_AUTH smbclient-raw LP_RESOLVE tevent-util dcerpc-binding param_options http',
+       deps='''
+        samba_socket
+        LIBCLI_RESOLVE
+        LIBCLI_SMB
+        LIBCLI_SMB2
+        ndr
+        NDR_DCERPC
+        RPC_NDR_EPMAPPER
+        NDR_SCHANNEL
+        RPC_NDR_NETLOGON
+        RPC_NDR_MGMT
+        gensec
+        LIBCLI_AUTH
+        smbclient-raw
+        LP_RESOLVE
+        tevent-util
+        dcerpc-binding
+        dcerpc-pkt-auth
+        param_options
+        http''',
        autoproto='rpc/dcerpc_proto.h',
        public_deps='samba-credentials tevent talloc',
        public_headers='''rpc/dcerpc.h''',