From: Stefan Metzmacher Date: Fri, 18 Mar 2016 03:40:30 +0000 (+0100) Subject: CVE-2016-2118: s3:rpc_server: make use of "allow dcerpc auth level connect" X-Git-Tag: samba-4.2.10~101 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f0b5e62fe02666c262120dfbae52d9e586f144fa;p=thirdparty%2Fsamba.git CVE-2016-2118: s3:rpc_server: make use of "allow dcerpc auth level connect" With this option turned off we only allow DCERPC_AUTH_LEVEL_{NONE,INTEGRITY,PRIVACY}, this means the reject any request with AUTH_LEVEL_CONNECT with ACCESS_DENIED. We sadly need to keep this enabled by default for now. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11616 Pair-Programmed-With: Günther Deschner Signed-off-by: Stefan Metzmacher Signed-off-by: Günther Deschner --- diff --git a/source3/rpc_server/rpc_ncacn_np.c b/source3/rpc_server/rpc_ncacn_np.c index d504847b434..5514956b983 100644 --- a/source3/rpc_server/rpc_ncacn_np.c +++ b/source3/rpc_server/rpc_ncacn_np.c @@ -224,7 +224,7 @@ struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, return NULL; } - context_fns = talloc(p, struct pipe_rpc_fns); + context_fns = talloc_zero(p, struct pipe_rpc_fns); if (context_fns == NULL) { DEBUG(0,("talloc() failed!\n")); TALLOC_FREE(p); diff --git a/source3/rpc_server/rpc_pipes.h b/source3/rpc_server/rpc_pipes.h index e65209aefc0..14b870532c8 100644 --- a/source3/rpc_server/rpc_pipes.h +++ b/source3/rpc_server/rpc_pipes.h @@ -94,6 +94,10 @@ struct pipe_rpc_fns { uint32_t context_id; struct ndr_syntax_id syntax; + /* + * shall we allow "connect" auth level for this interface ? + */ + bool allow_connect; }; /* diff --git a/source3/rpc_server/srv_pipe.c b/source3/rpc_server/srv_pipe.c index 4ffaa0dbb03..49026765a14 100644 --- a/source3/rpc_server/srv_pipe.c +++ b/source3/rpc_server/srv_pipe.c @@ -44,6 +44,7 @@ #include "librpc/ndr/ndr_table.h" #include "auth/gensec/gensec.h" #include "librpc/ndr/ndr_dcerpc.h" +#include "lib/tsocket/tsocket.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_RPC_SRV @@ -338,6 +339,7 @@ static bool check_bind_req(struct pipes_struct *p, { struct pipe_rpc_fns *context_fns; bool ok; + const char *interface_name = NULL; DEBUG(3,("check_bind_req for %s\n", ndr_interface_name(&abstract->uuid, @@ -359,18 +361,34 @@ static bool check_bind_req(struct pipes_struct *p, return false; } - context_fns = talloc(p, struct pipe_rpc_fns); + context_fns = talloc_zero(p, struct pipe_rpc_fns); if (context_fns == NULL) { DEBUG(0,("check_bind_req: talloc() failed!\n")); return false; } + interface_name = ndr_interface_name(&abstract->uuid, + abstract->if_version); + SMB_ASSERT(interface_name != NULL); + context_fns->next = context_fns->prev = NULL; context_fns->n_cmds = rpc_srv_get_pipe_num_cmds(abstract); context_fns->cmds = rpc_srv_get_pipe_cmds(abstract); context_fns->context_id = context_id; context_fns->syntax = *abstract; + context_fns->allow_connect = lp_allow_dcerpc_auth_level_connect(); + /* + * every interface can be modified to allow "connect" auth_level by + * using a parametric option like: + * allow dcerpc auth level connect: + * e.g. + * allow dcerpc auth level connect:samr = yes + */ + context_fns->allow_connect = lp_parm_bool(-1, + "allow dcerpc auth level connect", + interface_name, context_fns->allow_connect); + /* add to the list of open contexts */ DLIST_ADD( p->contexts, context_fns ); @@ -1174,6 +1192,7 @@ static bool api_pipe_request(struct pipes_struct *p, TALLOC_CTX *frame = talloc_stackframe(); bool ret = False; struct pipe_rpc_fns *pipe_fns; + const char *interface_name = NULL; if (!p->pipe_bound) { DEBUG(1, ("Pipe not bound!\n")); @@ -1194,6 +1213,37 @@ static bool api_pipe_request(struct pipes_struct *p, return false; } + interface_name = ndr_interface_name(&pipe_fns->syntax.uuid, + pipe_fns->syntax.if_version); + SMB_ASSERT(interface_name != NULL); + + switch (p->auth.auth_level) { + case DCERPC_AUTH_LEVEL_NONE: + case DCERPC_AUTH_LEVEL_INTEGRITY: + case DCERPC_AUTH_LEVEL_PRIVACY: + break; + default: + if (!pipe_fns->allow_connect) { + char *addr; + + addr = tsocket_address_string(p->remote_address, frame); + + DEBUG(1, ("%s: restrict auth_level_connect access " + "to [%s] with auth[type=0x%x,level=0x%x] " + "on [%s] from [%s]\n", + __func__, interface_name, + p->auth.auth_type, + p->auth.auth_level, + derpc_transport_string_by_transport(p->transport), + addr)); + + setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED)); + TALLOC_FREE(frame); + return true; + } + break; + } + if (!srv_pipe_check_verification_trailer(p, pkt, pipe_fns)) { DEBUG(1, ("srv_pipe_check_verification_trailer: failed\n")); setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_ACCESS_DENIED)); @@ -1209,9 +1259,7 @@ static bool api_pipe_request(struct pipes_struct *p, return false; } - DEBUG(5, ("Requested %s rpc service\n", - ndr_interface_name(&pipe_fns->syntax.uuid, - pipe_fns->syntax.if_version))); + DEBUG(5, ("Requested %s rpc service\n", interface_name)); ret = api_rpcTNP(p, pkt, pipe_fns->cmds, pipe_fns->n_cmds, &pipe_fns->syntax);