The branch, master has been updated via 4d3b6506d30 librpc: Remove the gensec dependency from library dcerpc-binding via 8945d99758d rpc: Give dcerpc_util.c its own header via 69a3d0fa4b7 gensec: Remove gensec_security_all(), it was only used internally via 02eef74e609 winbindd: Remove unused code via bf1012ee706 winbindd: Use samr in sam_rids_to_names() instead of lsa via 82e30f32036 winbindd: Make sam_sid_to_name use samr instead of lsa via c06be36e606 winbindd: Use samr instead of lsa in sam_name_to_sid() via 57246e1f814 winbindd: Avoid deadlock in sam_name_to_sid() via 30e0cac46bb rpc_server: tstream_npa_connect_recv() returns errno into sys_errno from 49a0f6170bf oss-fuzz: Update build script to be compatible with rpm distros
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 4d3b6506d30e4bf302f832493dad00a83b73d370 Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 2 13:41:21 2021 +0200 librpc: Remove the gensec dependency from library dcerpc-binding 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 <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Tue Apr 6 23:33:14 UTC 2021 on sn-devel-184 commit 8945d99758d8bedd374f1c51304b87a6cf10498c Author: Volker Lendecke <v...@samba.org> Date: Fri Apr 2 12:20:38 2021 +0200 rpc: Give dcerpc_util.c its own header Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 69a3d0fa4b7526b1d378bcad5efa840a4fcbf076 Author: Volker Lendecke <v...@samba.org> Date: Sat Apr 3 12:04:04 2021 +0200 gensec: Remove gensec_security_all(), it was only used internally Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 02eef74e609e685177accbc494ed8b8d3e5b6abd Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 23 16:16:39 2021 +0100 winbindd: Remove unused code Those calls were only used in winbindd_samr which now does direct and simpler samr calls. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit bf1012ee7063f03503eb2e348757b1b12d5bff0b Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 23 16:03:17 2021 +0100 winbindd: Use samr in sam_rids_to_names() instead of lsa Same argument as with previous patches: We don't need fancy lsa routing and samr is less prone to deadlock back into winbind Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 82e30f3203691a9bd3250887be7f0de298b96ace Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 23 11:49:16 2021 +0100 winbindd: Make sam_sid_to_name use samr instead of lsa Same argument as with name_to_sid: We don't need the lsa lookup routing, and samr is less prone to deadlocking. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit c06be36e6069eb7011b2601ff3521109c0c9f5d8 Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 23 10:38:16 2021 +0100 winbindd: Use samr instead of lsa in sam_name_to_sid() After the "Unix Users/Groups" and wkn names have been taken care of, all that remains here is our domain (BUILTIN or workgroup). We don't need any of the fancy routing in lsa_lookupnames, and samr_LookupNames is a lot less prone to deadlocks back into winbind. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 57246e1f814a9f8b17e0d3889822f271400a6515 Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 23 08:27:07 2021 +0100 winbindd: Avoid deadlock in sam_name_to_sid() "Unix Users" and "Unix Groups" can recurse into nsswitch and thus into winbind. In the binding process, we have winbindd_off(), but if we pass the lookupNames request to a forked lsad, lsad does not necessarily have that setting. So lsad might turn back to winbind, which could lead to a deadlock. Handle the nsswitch lookups in winbind. While there, also do the simple wellknown names and the "DOMAIN\" type 3 lookups directly in winbind. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit 30e0cac46bbf005612fcc50d3959b3a0351e4442 Author: Volker Lendecke <v...@samba.org> Date: Tue Feb 9 18:36:56 2021 +0100 rpc_server: tstream_npa_connect_recv() returns errno into sys_errno Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> ----------------------------------------------------------------------- Summary of changes: auth/gensec/gensec.h | 1 - auth/gensec/gensec_start.c | 10 +- libcli/auth/wscript_build | 10 +- librpc/rpc/dcerpc_pkt_auth.c | 497 ++++++++++++++++++++++++++++ librpc/rpc/dcerpc_pkt_auth.h | 58 ++++ librpc/rpc/dcerpc_util.c | 465 +------------------------- librpc/rpc/dcerpc_util.h | 85 +++++ librpc/rpc/dcesrv_auth.c | 2 + librpc/rpc/dcesrv_core.c | 1 + librpc/rpc/dcesrv_reply.c | 1 + librpc/rpc/rpc_common.h | 74 ----- librpc/wscript_build | 25 +- source3/librpc/rpc/dcerpc_helpers.c | 1 + source3/rpc_client/cli_pipe.c | 1 + source3/rpc_client/rpc_transport_np.c | 1 + source3/rpc_server/rpc_ncacn_np.c | 3 +- source3/winbindd/winbindd_rpc.c | 214 ------------ source3/winbindd/winbindd_rpc.h | 33 -- source3/winbindd/winbindd_samr.c | 448 +++++++++++++++++++------ source3/wscript_build | 8 +- source4/librpc/rpc/dcerpc.c | 2 + source4/librpc/rpc/dcerpc_roh_channel_out.c | 1 + source4/librpc/wscript_build | 21 +- 23 files changed, 1063 insertions(+), 899 deletions(-) create mode 100644 librpc/rpc/dcerpc_pkt_auth.c create mode 100644 librpc/rpc/dcerpc_pkt_auth.h create mode 100644 librpc/rpc/dcerpc_util.h Changeset truncated at 500 lines: diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h index 8bece3c3458..53fb1e43244 100644 --- a/auth/gensec/gensec.h +++ b/auth/gensec/gensec.h @@ -300,7 +300,6 @@ NTSTATUS gensec_wrap(struct gensec_security *gensec_security, const DATA_BLOB *in, DATA_BLOB *out); -const struct gensec_security_ops * const *gensec_security_all(void); bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security); NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, diff --git a/auth/gensec/gensec_start.c b/auth/gensec/gensec_start.c index 0a484eefcf4..906e3ee302c 100644 --- a/auth/gensec/gensec_start.c +++ b/auth/gensec/gensec_start.c @@ -43,13 +43,6 @@ static const struct gensec_security_ops **generic_security_ops; static int gensec_num_backends; -/* Return all the registered mechs. Don't modify the return pointer, - * but you may talloc_referen it if convient */ -_PUBLIC_ const struct gensec_security_ops * const *gensec_security_all(void) -{ - return generic_security_ops; -} - bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security) { bool ok = lpcfg_parm_bool(security->settings->lp_ctx, @@ -157,7 +150,8 @@ _PUBLIC_ const struct gensec_security_ops **gensec_security_mechs( struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx) { - const struct gensec_security_ops * const *backends = gensec_security_all(); + const struct gensec_security_ops * const *backends = + generic_security_ops; enum credentials_use_kerberos use_kerberos = CRED_USE_KERBEROS_DESIRED; bool keep_schannel = false; diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build index 2a6a7468e45..24ab68fac1e 100644 --- a/libcli/auth/wscript_build +++ b/libcli/auth/wscript_build @@ -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 index 00000000000..322d7497893 --- /dev/null +++ b/librpc/rpc/dcerpc_pkt_auth.c @@ -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; -- Samba Shared Repository