LCOV - code coverage report
Current view: top level - librpc/rpc - binding.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 580 797 72.8 %
Date: 2024-04-21 15:09:00 Functions: 28 31 90.3 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    dcerpc utility functions
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2003
       7             :    Copyright (C) Jelmer Vernooij 2004
       8             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
       9             :    Copyright (C) Rafal Szczesniak 2006
      10             :    Copyright (C) Stefan Metzmacher 2014
      11             : 
      12             :    This program is free software; you can redistribute it and/or modify
      13             :    it under the terms of the GNU General Public License as published by
      14             :    the Free Software Foundation; either version 3 of the License, or
      15             :    (at your option) any later version.
      16             : 
      17             :    This program is distributed in the hope that it will be useful,
      18             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20             :    GNU General Public License for more details.
      21             : 
      22             :    You should have received a copy of the GNU General Public License
      23             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24             : */
      25             : 
      26             : #include "includes.h"
      27             : #include "../../lib/util/util_net.h"
      28             : #include "librpc/gen_ndr/ndr_epmapper.h"
      29             : #include "librpc/gen_ndr/ndr_misc.h"
      30             : #include "librpc/rpc/dcerpc.h"
      31             : #include "rpc_common.h"
      32             : 
      33             : #undef strcasecmp
      34             : #undef strncasecmp
      35             : 
      36             : #define MAX_PROTSEQ             10
      37             : 
      38             : struct dcerpc_binding {
      39             :         enum dcerpc_transport_t transport;
      40             :         struct GUID object;
      41             :         const char *object_string;
      42             :         const char *host;
      43             :         const char *target_hostname;
      44             :         const char *target_principal;
      45             :         const char *endpoint;
      46             :         const char **options;
      47             :         uint32_t flags;
      48             :         uint32_t assoc_group_id;
      49             :         char assoc_group_string[11]; /* 0x3456789a + '\0' */
      50             : };
      51             : 
      52             : static const struct {
      53             :         const char *name;
      54             :         enum dcerpc_transport_t transport;
      55             :         int num_protocols;
      56             :         enum epm_protocol protseq[MAX_PROTSEQ];
      57             : } transports[] = {
      58             :         { "ncacn_np",     NCACN_NP, 3, 
      59             :                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NETBIOS }},
      60             :         { "ncacn_ip_tcp", NCACN_IP_TCP, 3, 
      61             :                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP, EPM_PROTOCOL_IP } }, 
      62             :         { "ncacn_http", NCACN_HTTP, 3, 
      63             :                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP, EPM_PROTOCOL_IP } }, 
      64             :         { "ncadg_ip_udp", NCACN_IP_UDP, 3, 
      65             :                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UDP, EPM_PROTOCOL_IP } },
      66             :         { "ncalrpc", NCALRPC, 2, 
      67             :                 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_NAMED_PIPE } },
      68             :         { "ncacn_unix_stream", NCACN_UNIX_STREAM, 2, 
      69             :                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } },
      70             :         { "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2, 
      71             :                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UNIX_DS } },
      72             :         { "ncacn_at_dsp", NCACN_AT_DSP, 3, 
      73             :                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DSP } },
      74             :         { "ncadg_at_ddp", NCADG_AT_DDP, 3, 
      75             :                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DDP } },
      76             :         { "ncacn_vns_ssp", NCACN_VNS_SPP, 3, 
      77             :                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_SPP } },
      78             :         { "ncacn_vns_ipc", NCACN_VNS_IPC, 3, 
      79             :                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_IPC }, },
      80             :         { "ncadg_ipx", NCADG_IPX, 2,
      81             :                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_IPX },
      82             :         },
      83             :         { "ncacn_spx", NCACN_SPX, 3,
      84             :                 /* I guess some MS programmer confused the identifier for 
      85             :                  * EPM_PROTOCOL_UUID (0x0D or 13) with the one for 
      86             :                  * EPM_PROTOCOL_SPX (0x13) here. -- jelmer*/
      87             :                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID },
      88             :         },
      89             : };
      90             : 
      91             : static const struct ncacn_option {
      92             :         const char *name;
      93             :         uint32_t flag;
      94             : } ncacn_options[] = {
      95             :         {"sign", DCERPC_SIGN},
      96             :         {"seal", DCERPC_SEAL},
      97             :         {"connect", DCERPC_CONNECT},
      98             :         {"spnego", DCERPC_AUTH_SPNEGO},
      99             :         {"ntlm", DCERPC_AUTH_NTLM},
     100             :         {"krb5", DCERPC_AUTH_KRB5},
     101             :         {"schannel", DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO},
     102             :         {"validate", DCERPC_DEBUG_VALIDATE_BOTH},
     103             :         {"print", DCERPC_DEBUG_PRINT_BOTH},
     104             :         {"padcheck", DCERPC_DEBUG_PAD_CHECK},
     105             :         {"bigendian", DCERPC_PUSH_BIGENDIAN},
     106             :         {"smb1", DCERPC_SMB1},
     107             :         {"smb2", DCERPC_SMB2},
     108             :         {"ndr64", DCERPC_NDR64},
     109             :         {"packet", DCERPC_PACKET},
     110             : };
     111             : 
     112     1063828 : static const struct ncacn_option *ncacn_option_by_name(const char *name)
     113             : {
     114       17389 :         size_t i;
     115             : 
     116    16792937 :         for (i=0; i<ARRAY_SIZE(ncacn_options); i++) {
     117      255673 :                 int ret;
     118             : 
     119    15749947 :                 ret = strcasecmp(ncacn_options[i].name, name);
     120    15749947 :                 if (ret != 0) {
     121    15729109 :                         continue;
     122             :                 }
     123             : 
     124       20838 :                 return &ncacn_options[i];
     125             :         }
     126             : 
     127     1026323 :         return NULL;
     128             : }
     129             : 
     130        4392 : const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
     131             : {
     132           0 :         struct ndr_syntax_id syntax;
     133           0 :         NTSTATUS status;
     134             : 
     135        4392 :         switch(epm_floor->lhs.protocol) {
     136        1780 :                 case EPM_PROTOCOL_UUID:
     137        1780 :                         status = dcerpc_floor_get_uuid_full(epm_floor, &syntax);
     138        1780 :                         if (NT_STATUS_IS_OK(status)) {
     139             :                                 /* lhs is used: UUID */
     140           0 :                                 struct GUID_txt_buf buf;
     141             : 
     142        1780 :                                 if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr.uuid)) {
     143         893 :                                         return "NDR";
     144             :                                 } 
     145             : 
     146         887 :                                 if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr64.uuid)) {
     147           0 :                                         return "NDR64";
     148             :                                 } 
     149             : 
     150         887 :                                 return talloc_asprintf(
     151             :                                         mem_ctx,
     152             :                                         " uuid %s/0x%02x",
     153             :                                         GUID_buf_string(&syntax.uuid, &buf),
     154             :                                         syntax.if_version);
     155             :                         } else { /* IPX */
     156           0 :                                 return talloc_asprintf(mem_ctx, "IPX:%s", 
     157           0 :                                                 data_blob_hex_string_upper(mem_ctx, &epm_floor->rhs.uuid.unknown));
     158             :                         }
     159             : 
     160         832 :                 case EPM_PROTOCOL_NCACN:
     161         832 :                         return "RPC-C";
     162             : 
     163           0 :                 case EPM_PROTOCOL_NCADG:
     164           0 :                         return "RPC";
     165             : 
     166          58 :                 case EPM_PROTOCOL_NCALRPC:
     167          58 :                         return "NCALRPC";
     168             : 
     169           0 :                 case EPM_PROTOCOL_DNET_NSP:
     170           0 :                         return "DNET/NSP";
     171             : 
     172         385 :                 case EPM_PROTOCOL_IP:
     173         385 :                         return talloc_asprintf(mem_ctx, "IP:%s", epm_floor->rhs.ip.ipaddr);
     174             : 
     175          58 :                 case EPM_PROTOCOL_NAMED_PIPE:
     176          58 :                         return talloc_asprintf(mem_ctx, "NAMED-PIPE:%s", epm_floor->rhs.named_pipe.path);
     177             : 
     178         447 :                 case EPM_PROTOCOL_SMB:
     179         447 :                         return talloc_asprintf(mem_ctx, "SMB:%s", epm_floor->rhs.smb.unc);
     180             : 
     181           0 :                 case EPM_PROTOCOL_UNIX_DS:
     182           0 :                         return talloc_asprintf(mem_ctx, "Unix:%s", epm_floor->rhs.unix_ds.path);
     183             : 
     184         447 :                 case EPM_PROTOCOL_NETBIOS:
     185         447 :                         return talloc_asprintf(mem_ctx, "NetBIOS:%s", epm_floor->rhs.netbios.name);
     186             : 
     187           0 :                 case EPM_PROTOCOL_NETBEUI:
     188           0 :                         return "NETBeui";
     189             : 
     190           0 :                 case EPM_PROTOCOL_SPX:
     191           0 :                         return "SPX";
     192             : 
     193           0 :                 case EPM_PROTOCOL_NB_IPX:
     194           0 :                         return "NB_IPX";
     195             : 
     196          76 :                 case EPM_PROTOCOL_HTTP:
     197          76 :                         return talloc_asprintf(mem_ctx, "HTTP:%"PRIu16, epm_floor->rhs.http.port);
     198             : 
     199         309 :                 case EPM_PROTOCOL_TCP:
     200         309 :                         return talloc_asprintf(mem_ctx, "TCP:%"PRIu16, epm_floor->rhs.tcp.port);
     201             : 
     202           0 :                 case EPM_PROTOCOL_UDP:
     203           0 :                         return talloc_asprintf(mem_ctx, "UDP:%"PRIu16, epm_floor->rhs.udp.port);
     204             : 
     205           0 :                 default:
     206           0 :                         return talloc_asprintf(mem_ctx, "UNK(%02x):", epm_floor->lhs.protocol);
     207             :         }
     208             : }
     209             : 
     210             : 
     211             : /*
     212             :   form a binding string from a binding structure
     213             : */
     214       47002 : _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
     215             : {
     216       47002 :         char *s = NULL;
     217         298 :         size_t i;
     218       47002 :         const char *t_name = NULL;
     219       47002 :         bool option_section = false;
     220       47002 :         const char *target_hostname = NULL;
     221             : 
     222       47002 :         if (b->transport != NCA_UNKNOWN) {
     223       46980 :                 t_name = derpc_transport_string_by_transport(b->transport);
     224       46980 :                 if (!t_name) {
     225           0 :                         return NULL;
     226             :                 }
     227             :         }
     228             : 
     229       47002 :         s = talloc_strdup(mem_ctx, "");
     230             : 
     231       47002 :         if (!GUID_all_zero(&b->object)) {
     232           6 :                 struct GUID_txt_buf buf;
     233           6 :                 talloc_asprintf_addbuf(
     234             :                         &s, "%s@", GUID_buf_string(&b->object, &buf));
     235             :         }
     236             : 
     237       47002 :         if (t_name != NULL) {
     238       46980 :                 talloc_asprintf_addbuf(&s, "%s:", t_name);
     239             :         }
     240             : 
     241       47002 :         if (b->host) {
     242        1230 :                 talloc_asprintf_addbuf(&s, "%s", b->host);
     243             :         }
     244             : 
     245       47002 :         target_hostname = b->target_hostname;
     246       47002 :         if (target_hostname != NULL && b->host != NULL) {
     247        1230 :                 if (strcmp(target_hostname, b->host) == 0) {
     248        1197 :                         target_hostname = NULL;
     249             :                 }
     250             :         }
     251             : 
     252       47300 :         option_section =
     253        4453 :                 (b->endpoint != NULL) ||
     254        4434 :                 (target_hostname != NULL) ||
     255        4434 :                 (b->target_principal != NULL) ||
     256        4434 :                 (b->assoc_group_id != 0) ||
     257       55722 :                 (b->options != NULL) ||
     258        4431 :                 (b->flags != 0);
     259             : 
     260       47002 :         if (!option_section) {
     261        4069 :                 return s;
     262             :         }
     263             : 
     264       42933 :         talloc_asprintf_addbuf(&s, "[");
     265             : 
     266       42933 :         if (b->endpoint) {
     267       42549 :                 talloc_asprintf_addbuf(&s, "%s", b->endpoint);
     268             :         }
     269             : 
     270      686928 :         for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
     271      643995 :                 if (!(b->flags & ncacn_options[i].flag)) {
     272      643322 :                         continue;
     273             :                 }
     274             : 
     275         673 :                 talloc_asprintf_addbuf(&s, ",%s", ncacn_options[i].name);
     276             :         }
     277             : 
     278       42933 :         if (target_hostname) {
     279          33 :                 talloc_asprintf_addbuf(
     280          33 :                         &s, ",target_hostname=%s", b->target_hostname);
     281             :         }
     282             : 
     283       42933 :         if (b->target_principal) {
     284           9 :                 talloc_asprintf_addbuf(
     285           0 :                         &s, ",target_principal=%s", b->target_principal);
     286             :         }
     287             : 
     288       42933 :         if (b->assoc_group_id != 0) {
     289          87 :                 talloc_asprintf_addbuf(
     290          60 :                         &s, ",assoc_group_id=0x%08x", b->assoc_group_id);
     291             :         }
     292             : 
     293       43968 :         for (i=0;b->options && b->options[i];i++) {
     294        1035 :                 talloc_asprintf_addbuf(&s, ",%s", b->options[i]);
     295             :         }
     296             : 
     297       42933 :         talloc_asprintf_addbuf(&s, "]");
     298             : 
     299       42933 :         return s;
     300             : }
     301             : 
     302             : /*
     303             :   parse a binding string into a dcerpc_binding structure
     304             : */
     305      171483 : _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *_s, struct dcerpc_binding **b_out)
     306             : {
     307        1873 :         char *_t;
     308        1873 :         struct dcerpc_binding *b;
     309        1873 :         char *s;
     310      171483 :         char *options = NULL;
     311        1873 :         char *p;
     312        1873 :         size_t i;
     313        1873 :         NTSTATUS status;
     314             : 
     315      171483 :         b = talloc_zero(mem_ctx, struct dcerpc_binding);
     316      171483 :         if (!b) {
     317           0 :                 return NT_STATUS_NO_MEMORY;
     318             :         }
     319             : 
     320      171483 :         _t = talloc_strdup(b, _s);
     321      171483 :         if (_t == NULL) {
     322           0 :                 talloc_free(b);
     323           0 :                 return NT_STATUS_NO_MEMORY;
     324             :         }
     325             : 
     326      171483 :         s = _t;
     327             : 
     328      171483 :         p = strchr(s, '[');
     329      171483 :         if (p) {
     330      143772 :                 char *q = p + strlen(p) - 1;
     331      143772 :                 if (*q != ']') {
     332           0 :                         talloc_free(b);
     333           0 :                         return NT_STATUS_INVALID_PARAMETER_MIX;
     334             :                 }
     335      143772 :                 *p = '\0';
     336      143772 :                 *q = '\0';
     337      143772 :                 options = p + 1;
     338             :         }
     339             : 
     340      171483 :         p = strchr(s, '@');
     341             : 
     342      171483 :         if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
     343          24 :                 *p = '\0';
     344             : 
     345          24 :                 status = dcerpc_binding_set_string_option(b, "object", s);
     346          24 :                 if (!NT_STATUS_IS_OK(status)) {
     347           0 :                         talloc_free(b);
     348           0 :                         return status;
     349             :                 }
     350             : 
     351          24 :                 s = p + 1;
     352             :         }
     353             : 
     354      171483 :         p = strchr(s, ':');
     355             : 
     356      171483 :         if (p == NULL) {
     357        1964 :                 b->transport = NCA_UNKNOWN;
     358      169519 :         } else if (is_ipaddress_v6(s)) {
     359          14 :                 b->transport = NCA_UNKNOWN;
     360             :         } else {
     361      169505 :                 *p = '\0';
     362             : 
     363      169505 :                 status = dcerpc_binding_set_string_option(b, "transport", s);
     364      169505 :                 if (!NT_STATUS_IS_OK(status)) {
     365           0 :                         talloc_free(b);
     366           0 :                         return status;
     367             :                 }
     368             : 
     369      169505 :                 s = p + 1;
     370             :         }
     371             : 
     372      171483 :         if (strlen(s) > 0) {
     373       13321 :                 status = dcerpc_binding_set_string_option(b, "host", s);
     374       13321 :                 if (!NT_STATUS_IS_OK(status)) {
     375           0 :                         talloc_free(b);
     376           0 :                         return status;
     377             :                 }
     378             : 
     379       13321 :                 b->target_hostname = talloc_strdup(b, b->host);
     380       13321 :                 if (b->target_hostname == NULL) {
     381           0 :                         talloc_free(b);
     382           0 :                         return NT_STATUS_NO_MEMORY;
     383             :                 }
     384             :         }
     385             : 
     386      319179 :         for (i=0; options != NULL; i++) {
     387      147696 :                 const char *name = options;
     388      147696 :                 const char *value = NULL;
     389             : 
     390      147696 :                 p = strchr(options, ',');
     391      147696 :                 if (p != NULL) {
     392        3924 :                         *p = '\0';
     393        3924 :                         options = p+1;
     394             :                 } else {
     395      142368 :                         options = NULL;
     396             :                 }
     397             : 
     398      147696 :                 p = strchr(name, '=');
     399      147696 :                 if (p != NULL) {
     400        1591 :                         *p = '\0';
     401        1591 :                         value = p + 1;
     402             :                 }
     403             : 
     404      146150 :                 if (value == NULL) {
     405             :                         /*
     406             :                          * If it's not a key=value pair
     407             :                          * it might be a ncacn_option
     408             :                          * or if it's the first option
     409             :                          * it's the endpoint.
     410             :                          */
     411      146105 :                         const struct ncacn_option *no = NULL;
     412             : 
     413      146105 :                         value = name;
     414             : 
     415      146105 :                         no = ncacn_option_by_name(name);
     416      146105 :                         if (no == NULL) {
     417      135700 :                                 if (i > 0) {
     418             :                                         /*
     419             :                                          * we don't allow unknown options
     420             :                                          */
     421           0 :                                         return NT_STATUS_INVALID_PARAMETER_MIX;
     422             :                                 }
     423             : 
     424             :                                 /*
     425             :                                  * This is the endpoint
     426             :                                  */
     427      135700 :                                 name = "endpoint";
     428      135700 :                                 if (strlen(value) == 0) {
     429        2794 :                                         value = NULL;
     430             :                                 }
     431             :                         }
     432             :                 }
     433             : 
     434      147696 :                 status = dcerpc_binding_set_string_option(b, name, value);
     435      147696 :                 if (!NT_STATUS_IS_OK(status)) {
     436           0 :                         talloc_free(b);
     437           0 :                         return status;
     438             :                 }
     439             :         }
     440             : 
     441      171483 :         talloc_free(_t);
     442      171483 :         *b_out = b;
     443      171483 :         return NT_STATUS_OK;
     444             : }
     445             : 
     446       48696 : _PUBLIC_ struct GUID dcerpc_binding_get_object(const struct dcerpc_binding *b)
     447             : {
     448       48696 :         return b->object;
     449             : }
     450             : 
     451       10678 : _PUBLIC_ NTSTATUS dcerpc_binding_set_object(struct dcerpc_binding *b,
     452             :                                             struct GUID object)
     453             : {
     454       10678 :         char *tmp = discard_const_p(char, b->object_string);
     455             : 
     456       10678 :         if (GUID_all_zero(&object)) {
     457       10652 :                 talloc_free(tmp);
     458       10652 :                 b->object_string = NULL;
     459       10652 :                 ZERO_STRUCT(b->object);
     460       10652 :                 return NT_STATUS_OK;
     461             :         }
     462             : 
     463          26 :         b->object_string = GUID_string(b, &object);
     464          26 :         if (b->object_string == NULL) {
     465           0 :                 b->object_string = tmp;
     466           0 :                 return NT_STATUS_NO_MEMORY;
     467             :         }
     468          26 :         talloc_free(tmp);
     469             : 
     470          26 :         b->object = object;
     471          26 :         return NT_STATUS_OK;
     472             : }
     473             : 
     474     1824801 : _PUBLIC_ enum dcerpc_transport_t dcerpc_binding_get_transport(const struct dcerpc_binding *b)
     475             : {
     476     1824801 :         return b->transport;
     477             : }
     478             : 
     479      173605 : _PUBLIC_ NTSTATUS dcerpc_binding_set_transport(struct dcerpc_binding *b,
     480             :                                                enum dcerpc_transport_t transport)
     481             : {
     482        2177 :         NTSTATUS status;
     483             : 
     484             :         /*
     485             :          * TODO: we may want to check the transport value is
     486             :          * wellknown.
     487             :          */
     488      173605 :         if (b->transport == transport) {
     489         923 :                 return NT_STATUS_OK;
     490             :         }
     491             : 
     492             :         /*
     493             :          * This implicitly resets the endpoint
     494             :          * as the endpoint is transport specific.
     495             :          *
     496             :          * It also resets the assoc group as it's
     497             :          * also endpoint specific.
     498             :          *
     499             :          * TODO: in future we may reset more options
     500             :          * here.
     501             :          */
     502      172682 :         status = dcerpc_binding_set_string_option(b, "endpoint", NULL);
     503      172682 :         if (!NT_STATUS_IS_OK(status)) {
     504           0 :                 return status;
     505             :         }
     506             : 
     507      172682 :         b->assoc_group_id = 0;
     508             : 
     509      172682 :         b->transport = transport;
     510      172682 :         return NT_STATUS_OK;
     511             : }
     512             : 
     513           0 : _PUBLIC_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
     514             :                                            enum dcerpc_AuthType *_auth_type,
     515             :                                            enum dcerpc_AuthLevel *_auth_level)
     516             : {
     517           0 :         enum dcerpc_AuthType auth_type;
     518           0 :         enum dcerpc_AuthLevel auth_level;
     519             : 
     520           0 :         if (b->flags & DCERPC_AUTH_SPNEGO) {
     521           0 :                 auth_type = DCERPC_AUTH_TYPE_SPNEGO;
     522           0 :         } else if (b->flags & DCERPC_AUTH_KRB5) {
     523           0 :                 auth_type = DCERPC_AUTH_TYPE_KRB5;
     524           0 :         } else if (b->flags & DCERPC_SCHANNEL) {
     525           0 :                 auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
     526           0 :         } else if (b->flags & DCERPC_AUTH_NTLM) {
     527           0 :                 auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
     528             :         } else {
     529           0 :                 auth_type = DCERPC_AUTH_TYPE_NONE;
     530             :         }
     531             : 
     532           0 :         if (b->flags & DCERPC_SEAL) {
     533           0 :                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
     534           0 :         } else if (b->flags & DCERPC_SIGN) {
     535           0 :                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
     536           0 :         } else if (b->flags & DCERPC_CONNECT) {
     537           0 :                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
     538           0 :         } else if (b->flags & DCERPC_PACKET) {
     539           0 :                 auth_level = DCERPC_AUTH_LEVEL_PACKET;
     540           0 :         } else if (auth_type != DCERPC_AUTH_TYPE_NONE) {
     541           0 :                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
     542             :         } else {
     543           0 :                 auth_level = DCERPC_AUTH_LEVEL_NONE;
     544             :         }
     545             : 
     546           0 :         if (_auth_type != NULL) {
     547           0 :                 *_auth_type = auth_type;
     548             :         }
     549             : 
     550           0 :         if (_auth_level != NULL) {
     551           0 :                 *_auth_level = auth_level;
     552             :         }
     553           0 : }
     554             : 
     555       26129 : _PUBLIC_ uint32_t dcerpc_binding_get_assoc_group_id(const struct dcerpc_binding *b)
     556             : {
     557       26129 :         return b->assoc_group_id;
     558             : }
     559             : 
     560       31420 : _PUBLIC_ NTSTATUS dcerpc_binding_set_assoc_group_id(struct dcerpc_binding *b,
     561             :                                                     uint32_t assoc_group_id)
     562             : {
     563       31420 :         b->assoc_group_id = assoc_group_id;
     564       31420 :         return NT_STATUS_OK;
     565             : }
     566             : 
     567      427380 : _PUBLIC_ struct ndr_syntax_id dcerpc_binding_get_abstract_syntax(const struct dcerpc_binding *b)
     568             : {
     569      427380 :         const char *s = dcerpc_binding_get_string_option(b, "abstract_syntax");
     570        7161 :         bool ok;
     571        7161 :         struct ndr_syntax_id id;
     572             : 
     573      427380 :         if (s == NULL) {
     574          38 :                 return ndr_syntax_id_null;
     575             :         }
     576             : 
     577      427342 :         ok = ndr_syntax_id_from_string(s, &id);
     578      427342 :         if (!ok) {
     579           0 :                 return ndr_syntax_id_null;
     580             :         }
     581             : 
     582      427342 :         return id;
     583             : }
     584             : 
     585      450174 : _PUBLIC_ NTSTATUS dcerpc_binding_set_abstract_syntax(struct dcerpc_binding *b,
     586             :                                                      const struct ndr_syntax_id *syntax)
     587             : {
     588        7812 :         NTSTATUS status;
     589        7812 :         struct ndr_syntax_id_buf buf;
     590             : 
     591      450174 :         if (syntax == NULL) {
     592           0 :                 status = dcerpc_binding_set_string_option(b, "abstract_syntax", NULL);
     593           0 :                 return status;
     594             :         }
     595             : 
     596      450174 :         if (ndr_syntax_id_equal(&ndr_syntax_id_null, syntax)) {
     597          42 :                 status = dcerpc_binding_set_string_option(b, "abstract_syntax", NULL);
     598          42 :                 return status;
     599             :         }
     600             : 
     601      450132 :         status = dcerpc_binding_set_string_option(
     602      450132 :                 b, "abstract_syntax", ndr_syntax_id_buf_string(syntax, &buf));
     603      450132 :         return status;
     604             : }
     605             : 
     606     1142399 : _PUBLIC_ const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
     607             :                                                       const char *name)
     608             : {
     609       16332 :         struct {
     610             :                 const char *name;
     611             :                 const char *value;
     612             : #define _SPECIAL(x) { .name = #x, .value = b->x, }
     613     1142399 :         } specials[] = {
     614     1142399 :                 { .name = "object", .value = b->object_string, },
     615     1142399 :                 _SPECIAL(host),
     616     1142399 :                 _SPECIAL(endpoint),
     617     1142399 :                 _SPECIAL(target_hostname),
     618     1142399 :                 _SPECIAL(target_principal),
     619             : #undef _SPECIAL
     620             :         };
     621     1142399 :         const struct ncacn_option *no = NULL;
     622     1142399 :         size_t name_len = strlen(name);
     623       16332 :         size_t i;
     624       16332 :         int ret;
     625             : 
     626     1142399 :         ret = strcmp(name, "transport");
     627     1142399 :         if (ret == 0) {
     628           0 :                 return derpc_transport_string_by_transport(b->transport);
     629             :         }
     630             : 
     631     1142399 :         ret = strcmp(name, "assoc_group_id");
     632     1142399 :         if (ret == 0) {
     633           0 :                 char *tmp = discard_const_p(char, b->assoc_group_string);
     634             : 
     635           0 :                 if (b->assoc_group_id == 0) {
     636           0 :                         return NULL;
     637             :                 }
     638             : 
     639           0 :                 snprintf(tmp, sizeof(b->assoc_group_string),
     640           0 :                          "0x%08x", b->assoc_group_id);
     641           0 :                 return (const char *)b->assoc_group_string;
     642             :         }
     643             : 
     644     4736924 :         for (i=0; i < ARRAY_SIZE(specials); i++) {
     645     4292465 :                 ret = strcmp(specials[i].name, name);
     646     4292465 :                 if (ret != 0) {
     647     3594525 :                         continue;
     648             :                 }
     649             : 
     650      697940 :                 return specials[i].value;
     651             :         }
     652             : 
     653      444459 :         no = ncacn_option_by_name(name);
     654      444459 :         if (no != NULL) {
     655           0 :                 if (b->flags & no->flag) {
     656           0 :                         return no->name;
     657             :                 }
     658             : 
     659           0 :                 return NULL;
     660             :         }
     661             : 
     662      444459 :         if (b->options == NULL) {
     663          23 :                 return NULL;
     664             :         }
     665             : 
     666      462131 :         for (i=0; b->options[i]; i++) {
     667      446173 :                 const char *o = b->options[i];
     668      446173 :                 const char *vs = NULL;
     669             : 
     670      446173 :                 ret = strncmp(name, o, name_len);
     671      446173 :                 if (ret != 0) {
     672       17728 :                         continue;
     673             :                 }
     674             : 
     675      428445 :                 if (o[name_len] != '=') {
     676           0 :                         continue;
     677             :                 }
     678             : 
     679      428445 :                 vs = &o[name_len + 1];
     680             : 
     681      428445 :                 return vs;
     682             :         }
     683             : 
     684       15713 :         return NULL;
     685             : }
     686             : 
     687           0 : _PUBLIC_ char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
     688             :                                                  const struct dcerpc_binding *b,
     689             :                                                  const char *name)
     690             : {
     691           0 :         const char *c = dcerpc_binding_get_string_option(b, name);
     692           0 :         char *v;
     693             : 
     694           0 :         if (c == NULL) {
     695           0 :                 errno = ENOENT;
     696           0 :                 return NULL;
     697             :         }
     698             : 
     699           0 :         v = talloc_strdup(mem_ctx, c);
     700           0 :         if (v == NULL) {
     701           0 :                 errno = ENOMEM;
     702           0 :                 return NULL;
     703             :         }
     704             : 
     705           0 :         return v;
     706             : }
     707             : 
     708     1014008 : _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
     709             :                                                    const char *name,
     710             :                                                    const char *value)
     711             : {
     712       15263 :         struct {
     713             :                 const char *name;
     714             :                 const char **ptr;
     715             : #define _SPECIAL(x) { .name = #x, .ptr = &b->x, }
     716     1014008 :         } specials[] = {
     717     1014008 :                 _SPECIAL(host),
     718     1014008 :                 _SPECIAL(endpoint),
     719     1014008 :                 _SPECIAL(target_hostname),
     720     1014008 :                 _SPECIAL(target_principal),
     721             : #undef _SPECIAL
     722             :         };
     723     1014008 :         const struct ncacn_option *no = NULL;
     724     1014008 :         size_t name_len = strlen(name);
     725     1014008 :         const char *opt = NULL;
     726       15263 :         char *tmp;
     727       15263 :         size_t i;
     728       15263 :         int ret;
     729             : 
     730             :         /*
     731             :          * Note: value == NULL, means delete it.
     732             :          * value != NULL means add or reset.
     733             :          */
     734             : 
     735     1014008 :         ret = strcmp(name, "transport");
     736     1014008 :         if (ret == 0) {
     737      169505 :                 enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
     738             : 
     739      169505 :                 if (t == NCA_UNKNOWN && value != NULL) {
     740           0 :                         return NT_STATUS_INVALID_PARAMETER_MIX;
     741             :                 }
     742             : 
     743      169505 :                 return dcerpc_binding_set_transport(b, t);
     744             :         }
     745             : 
     746      844503 :         ret = strcmp(name, "object");
     747      844503 :         if (ret == 0) {
     748           8 :                 NTSTATUS status;
     749          24 :                 struct GUID uuid = GUID_zero();
     750             : 
     751          24 :                 if (value != NULL) {
     752           8 :                         DATA_BLOB blob;
     753          24 :                         blob = data_blob_string_const(value);
     754          24 :                         if (blob.length != 36) {
     755           0 :                                 return NT_STATUS_INVALID_PARAMETER_MIX;
     756             :                         }
     757             : 
     758          24 :                         status = GUID_from_data_blob(&blob, &uuid);
     759          24 :                         if (!NT_STATUS_IS_OK(status)) {
     760           0 :                                 return status;
     761             :                         }
     762             :                 }
     763             : 
     764          24 :                 return dcerpc_binding_set_object(b, uuid);
     765             :         }
     766             : 
     767      844479 :         ret = strcmp(name, "assoc_group_id");
     768      844479 :         if (ret == 0) {
     769           4 :                 uint32_t assoc_group_id = 0;
     770             : 
     771           4 :                 if (value != NULL) {
     772           4 :                         char c;
     773             : 
     774           4 :                         ret = sscanf(value, "0x%08x%c", &assoc_group_id, &c);
     775           4 :                         if (ret != 1) {
     776           0 :                                 return NT_STATUS_INVALID_PARAMETER_MIX;
     777             :                         }
     778             :                 }
     779             : 
     780           4 :                 return dcerpc_binding_set_assoc_group_id(b, assoc_group_id);
     781             :         }
     782             : 
     783     3086109 :         for (i=0; i < ARRAY_SIZE(specials); i++) {
     784     2612845 :                 ret = strcmp(specials[i].name, name);
     785     2612845 :                 if (ret != 0) {
     786     2241634 :                         continue;
     787             :                 }
     788             : 
     789      371211 :                 tmp = discard_const_p(char, *specials[i].ptr);
     790             : 
     791      371211 :                 if (value == NULL) {
     792      187633 :                         talloc_free(tmp);
     793      187633 :                         *specials[i].ptr = NULL;
     794      187633 :                         return NT_STATUS_OK;
     795             :                 }
     796             : 
     797      183578 :                 if (value[0] == '\0') {
     798           0 :                         return NT_STATUS_INVALID_PARAMETER_MIX;
     799             :                 }
     800             : 
     801      183578 :                 *specials[i].ptr = talloc_strdup(b, value);
     802      183578 :                 if (*specials[i].ptr == NULL) {
     803           0 :                         *specials[i].ptr = tmp;
     804           0 :                         return NT_STATUS_NO_MEMORY;
     805             :                 }
     806      183578 :                 talloc_free(tmp);
     807             : 
     808      183578 :                 return NT_STATUS_OK;
     809             :         }
     810             : 
     811      473264 :         no = ncacn_option_by_name(name);
     812      473264 :         if (no != NULL) {
     813       10433 :                 if (value == NULL) {
     814           0 :                         b->flags &= ~no->flag;
     815           0 :                         return NT_STATUS_OK;
     816             :                 }
     817             : 
     818       10433 :                 ret = strcasecmp(no->name, value);
     819       10433 :                 if (ret != 0) {
     820           0 :                         return NT_STATUS_INVALID_PARAMETER_MIX;
     821             :                 }
     822             : 
     823       10433 :                 b->flags |= no->flag;
     824       10433 :                 return NT_STATUS_OK;
     825             :         }
     826             : 
     827      475813 :         for (i=0; b->options && b->options[i]; i++) {
     828       26758 :                 const char *o = b->options[i];
     829             : 
     830       26758 :                 ret = strncmp(name, o, name_len);
     831       26758 :                 if (ret != 0) {
     832       12982 :                         continue;
     833             :                 }
     834             : 
     835       13776 :                 if (o[name_len] != '=') {
     836           0 :                         continue;
     837             :                 }
     838             : 
     839       13352 :                 opt = o;
     840       13352 :                 break;
     841             :         }
     842             : 
     843      462831 :         if (opt == NULL) {
     844        7646 :                 const char **n;
     845             : 
     846      449055 :                 if (value == NULL) {
     847          35 :                         return NT_STATUS_OK;
     848             :                 }
     849             : 
     850      449020 :                 n = talloc_realloc(b, b->options, const char *, i + 2);
     851      449020 :                 if (n == NULL) {
     852           0 :                         return NT_STATUS_NO_MEMORY;
     853             :                 }
     854      449020 :                 n[i] = NULL;
     855      449020 :                 n[i + 1] = NULL;
     856      449020 :                 b->options = n;
     857             :         }
     858             : 
     859      462796 :         tmp = discard_const_p(char, opt);
     860             : 
     861      462796 :         if (value == NULL) {
     862          14 :                 for (;b->options[i];i++) {
     863           7 :                         b->options[i] = b->options[i+1];
     864             :                 }
     865           7 :                 talloc_free(tmp);
     866           7 :                 return NT_STATUS_OK;
     867             :         }
     868             : 
     869      462789 :         b->options[i] = talloc_asprintf(b->options, "%s=%s",
     870             :                                         name, value);
     871      462789 :         if (b->options[i] == NULL) {
     872           0 :                 b->options[i] = tmp;
     873           0 :                 return NT_STATUS_NO_MEMORY;
     874             :         }
     875             : 
     876      462789 :         return NT_STATUS_OK;
     877             : }
     878             : 
     879       72943 : _PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
     880             : {
     881       72943 :         return b->flags;
     882             : }
     883             : 
     884       36214 : _PUBLIC_ NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
     885             :                                            uint32_t additional,
     886             :                                            uint32_t clear)
     887             : {
     888             :         /*
     889             :          * TODO: in future we may want to reject invalid combinations
     890             :          */
     891       36214 :         b->flags &= ~clear;
     892       36214 :         b->flags |= additional;
     893             : 
     894       36214 :         return NT_STATUS_OK;
     895             : }
     896             : 
     897       72942 : _PUBLIC_ NTSTATUS dcerpc_floor_get_uuid_full(const struct epm_floor *epm_floor,
     898             :                                              struct ndr_syntax_id *syntax)
     899             : {
     900       72942 :         TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
     901        1562 :         struct ndr_pull *ndr;
     902        1562 :         enum ndr_err_code ndr_err;
     903       72942 :         uint16_t if_version=0;
     904             : 
     905       72942 :         *syntax = (struct ndr_syntax_id) { .if_version = 0, };
     906             : 
     907       72942 :         if (epm_floor->lhs.protocol != EPM_PROTOCOL_UUID) {
     908           0 :                 talloc_free(mem_ctx);
     909           0 :                 return NT_STATUS_INVALID_PARAMETER;
     910             :         }
     911             : 
     912       72942 :         ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
     913       72942 :         if (ndr == NULL) {
     914           0 :                 talloc_free(mem_ctx);
     915           0 :                 return NT_STATUS_NO_MEMORY;
     916             :         }
     917       72942 :         ndr->flags |= LIBNDR_FLAG_NOALIGN;
     918             : 
     919       72942 :         ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
     920       72942 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     921           0 :                 talloc_free(mem_ctx);
     922           0 :                 return ndr_map_error2ntstatus(ndr_err);
     923             :         }
     924             : 
     925       72942 :         ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
     926       72942 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     927           0 :                 talloc_free(mem_ctx);
     928           0 :                 return ndr_map_error2ntstatus(ndr_err);
     929             :         }
     930             : 
     931       72942 :         syntax->if_version = if_version;
     932             : 
     933       72942 :         TALLOC_FREE(ndr);
     934             : 
     935       72942 :         ndr = ndr_pull_init_blob(&epm_floor->rhs.uuid.unknown, mem_ctx);
     936       72942 :         if (ndr == NULL) {
     937           0 :                 talloc_free(mem_ctx);
     938           0 :                 return NT_STATUS_NO_MEMORY;
     939             :         }
     940       72942 :         ndr->flags |= LIBNDR_FLAG_NOALIGN;
     941             : 
     942       72942 :         ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
     943       72942 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     944           0 :                 talloc_free(mem_ctx);
     945           0 :                 return ndr_map_error2ntstatus(ndr_err);
     946             :         }
     947             : 
     948       72942 :         syntax->if_version |= (((uint32_t)if_version) << 16) & 0xffff0000;
     949             : 
     950       72942 :         talloc_free(mem_ctx);
     951             : 
     952       72942 :         return NT_STATUS_OK;
     953             : }
     954             : 
     955      854758 : static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
     956             : {
     957       14320 :         DATA_BLOB blob;
     958       14320 :         enum ndr_err_code ndr_err;
     959       14320 :         struct ndr_push *ndr;
     960             : 
     961      854758 :         ndr = ndr_push_init_ctx(mem_ctx);
     962      854758 :         if (ndr == NULL) {
     963           0 :                 return data_blob_null;
     964             :         }
     965             : 
     966      854758 :         ndr->flags |= LIBNDR_FLAG_NOALIGN;
     967             : 
     968      854758 :         ndr_err = ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
     969      854758 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     970           0 :                 return data_blob_null;
     971             :         }
     972      854758 :         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
     973      854758 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     974           0 :                 return data_blob_null;
     975             :         }
     976             : 
     977      854758 :         blob = ndr_push_blob(ndr);
     978      854758 :         talloc_steal(mem_ctx, blob.data);
     979      854758 :         talloc_free(ndr);
     980      854758 :         return blob;
     981             : }
     982             : 
     983      854758 : static bool dcerpc_floor_pack_rhs_if_version_data(
     984             :         TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax,
     985             :         DATA_BLOB *pblob)
     986             : {
     987       14320 :         DATA_BLOB blob;
     988      854758 :         struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
     989       14320 :         enum ndr_err_code ndr_err;
     990             : 
     991      854758 :         if (ndr == NULL) {
     992           0 :                 return false;
     993             :         }
     994             : 
     995      854758 :         ndr->flags |= LIBNDR_FLAG_NOALIGN;
     996             : 
     997      854758 :         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version >> 16);
     998      854758 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     999           0 :                 return false;
    1000             :         }
    1001             : 
    1002      854758 :         blob = ndr_push_blob(ndr);
    1003      854758 :         talloc_steal(mem_ctx, blob.data);
    1004      854758 :         talloc_free(ndr);
    1005      854758 :         *pblob = blob;
    1006      854758 :         return true;
    1007             : }
    1008             : 
    1009      854758 : static NTSTATUS dcerpc_floor_pack_uuid_full(TALLOC_CTX *mem_ctx,
    1010             :                                             struct epm_floor *floor,
    1011             :                                             const struct ndr_syntax_id *syntax)
    1012             : {
    1013       14320 :         bool ok;
    1014             : 
    1015      854758 :         floor->lhs.protocol = EPM_PROTOCOL_UUID;
    1016             : 
    1017      854758 :         floor->lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx, syntax);
    1018      854758 :         if (floor->lhs.lhs_data.data == NULL) {
    1019           0 :                 return NT_STATUS_NO_MEMORY;
    1020             :         }
    1021             : 
    1022      854758 :         ok = dcerpc_floor_pack_rhs_if_version_data(mem_ctx, syntax,
    1023             :                                 &floor->rhs.uuid.unknown);
    1024      854758 :         if (!ok) {
    1025           0 :                 data_blob_free(&floor->lhs.lhs_data);
    1026           0 :                 return NT_STATUS_NO_MEMORY;
    1027             :         }
    1028             : 
    1029      854758 :         return NT_STATUS_OK;
    1030             : }
    1031             : 
    1032        7027 : char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
    1033             : {
    1034        7027 :         switch (epm_floor->lhs.protocol) {
    1035        5371 :         case EPM_PROTOCOL_TCP:
    1036        5371 :                 if (epm_floor->rhs.tcp.port == 0) return NULL;
    1037        5364 :                 return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.tcp.port);
    1038             : 
    1039           1 :         case EPM_PROTOCOL_UDP:
    1040           1 :                 if (epm_floor->rhs.udp.port == 0) return NULL;
    1041           0 :                 return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.udp.port);
    1042             : 
    1043           3 :         case EPM_PROTOCOL_HTTP:
    1044           3 :                 if (epm_floor->rhs.http.port == 0) return NULL;
    1045           2 :                 return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.http.port);
    1046             : 
    1047          24 :         case EPM_PROTOCOL_IP:
    1048          24 :                 return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
    1049             : 
    1050           0 :         case EPM_PROTOCOL_NCACN:
    1051           0 :                 return NULL;
    1052             : 
    1053           0 :         case EPM_PROTOCOL_NCADG:
    1054           0 :                 return NULL;
    1055             : 
    1056         472 :         case EPM_PROTOCOL_SMB:
    1057         472 :                 if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
    1058         469 :                 return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
    1059             : 
    1060         682 :         case EPM_PROTOCOL_NAMED_PIPE:
    1061         682 :                 if (strlen(epm_floor->rhs.named_pipe.path) == 0) return NULL;
    1062         680 :                 return talloc_strdup(mem_ctx, epm_floor->rhs.named_pipe.path);
    1063             : 
    1064         472 :         case EPM_PROTOCOL_NETBIOS:
    1065         472 :                 if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
    1066           4 :                 return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
    1067             : 
    1068           0 :         case EPM_PROTOCOL_NCALRPC:
    1069           0 :                 return NULL;
    1070             : 
    1071           0 :         case EPM_PROTOCOL_VINES_SPP:
    1072           0 :                 return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.vines_spp.port);
    1073             : 
    1074           0 :         case EPM_PROTOCOL_VINES_IPC:
    1075           0 :                 return talloc_asprintf(mem_ctx, "%"PRIu16, epm_floor->rhs.vines_ipc.port);
    1076             : 
    1077           0 :         case EPM_PROTOCOL_STREETTALK:
    1078           0 :                 return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
    1079             : 
    1080           2 :         case EPM_PROTOCOL_UNIX_DS:
    1081           2 :                 if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
    1082           2 :                 return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
    1083             : 
    1084           0 :         case EPM_PROTOCOL_NULL:
    1085           0 :                 return NULL;
    1086             : 
    1087           0 :         default:
    1088           0 :                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
    1089           0 :                 break;
    1090             :         }
    1091             : 
    1092           0 :         return NULL;
    1093             : }
    1094             : 
    1095     1617973 : static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx, 
    1096             :                                           struct epm_floor *epm_floor,  
    1097             :                                           const char *data)
    1098             : {
    1099     1617973 :         if (data == NULL) {
    1100     1190519 :                 data = "";
    1101             :         }
    1102             : 
    1103     1617973 :         switch (epm_floor->lhs.protocol) {
    1104      239139 :         case EPM_PROTOCOL_TCP:
    1105      243289 :                 epm_floor->rhs.tcp.port = atoi(data);
    1106     1594985 :                 return NT_STATUS_OK;
    1107             : 
    1108           0 :         case EPM_PROTOCOL_UDP:
    1109           1 :                 epm_floor->rhs.udp.port = atoi(data);
    1110           1 :                 return NT_STATUS_OK;
    1111             : 
    1112       27272 :         case EPM_PROTOCOL_HTTP:
    1113       27777 :                 epm_floor->rhs.http.port = atoi(data);
    1114       27777 :                 return NT_STATUS_OK;
    1115             : 
    1116      143728 :         case EPM_PROTOCOL_IP:
    1117      143728 :                 if (!is_ipaddress_v4(data)) {
    1118      142676 :                         data = "0.0.0.0";
    1119             :                 }
    1120      143728 :                 epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
    1121      143728 :                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
    1122      143728 :                 return NT_STATUS_OK;
    1123             : 
    1124      335762 :         case EPM_PROTOCOL_NCACN:
    1125      335762 :                 epm_floor->rhs.ncacn.minor_version = 0;
    1126      335762 :                 return NT_STATUS_OK;
    1127             : 
    1128           1 :         case EPM_PROTOCOL_NCADG:
    1129           1 :                 epm_floor->rhs.ncadg.minor_version = 0;
    1130           1 :                 return NT_STATUS_OK;
    1131             : 
    1132      395227 :         case EPM_PROTOCOL_SMB:
    1133      395227 :                 epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
    1134      395227 :                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
    1135      395227 :                 return NT_STATUS_OK;
    1136             : 
    1137      182661 :         case EPM_PROTOCOL_NAMED_PIPE:
    1138      182661 :                 epm_floor->rhs.named_pipe.path = talloc_strdup(mem_ctx, data);
    1139      182661 :                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.named_pipe.path);
    1140      182661 :                 return NT_STATUS_OK;
    1141             : 
    1142      197907 :         case EPM_PROTOCOL_NETBIOS:
    1143      197907 :                 epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
    1144      197907 :                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
    1145      197907 :                 return NT_STATUS_OK;
    1146             : 
    1147       91616 :         case EPM_PROTOCOL_NCALRPC:
    1148       91616 :                 return NT_STATUS_OK;
    1149             : 
    1150           0 :         case EPM_PROTOCOL_VINES_SPP:
    1151           0 :                 epm_floor->rhs.vines_spp.port = atoi(data);
    1152           0 :                 return NT_STATUS_OK;
    1153             : 
    1154           0 :         case EPM_PROTOCOL_VINES_IPC:
    1155           0 :                 epm_floor->rhs.vines_ipc.port = atoi(data);
    1156           0 :                 return NT_STATUS_OK;
    1157             : 
    1158           0 :         case EPM_PROTOCOL_STREETTALK:
    1159           0 :                 epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
    1160           0 :                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
    1161           0 :                 return NT_STATUS_OK;
    1162             : 
    1163           4 :         case EPM_PROTOCOL_UNIX_DS:
    1164           4 :                 epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
    1165           4 :                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
    1166           4 :                 return NT_STATUS_OK;
    1167             : 
    1168           0 :         case EPM_PROTOCOL_NULL:
    1169           0 :                 return NT_STATUS_OK;
    1170             : 
    1171           0 :         default:
    1172           0 :                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
    1173           0 :                 break;
    1174             :         }
    1175             : 
    1176           0 :         return NT_STATUS_NOT_SUPPORTED;
    1177             : }
    1178             : 
    1179           0 : enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
    1180             : {
    1181           0 :         size_t i;
    1182             : 
    1183             :         /* Find a transport that has 'prot' as 4th protocol */
    1184           0 :         for (i=0;i<ARRAY_SIZE(transports);i++) {
    1185           0 :                 if (transports[i].num_protocols >= 2 && 
    1186           0 :                         transports[i].protseq[1] == prot) {
    1187           0 :                         return transports[i].transport;
    1188             :                 }
    1189             :         }
    1190             : 
    1191             :         /* Unknown transport */
    1192           0 :         return (unsigned int)-1;
    1193             : }
    1194             : 
    1195      283066 : _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower)
    1196             : {
    1197        5405 :         size_t i;
    1198             : 
    1199             :         /* Find a transport that matches this tower */
    1200      598318 :         for (i=0;i<ARRAY_SIZE(transports);i++) {
    1201       11794 :                 int j;
    1202      598128 :                 if (transports[i].num_protocols != tower->num_floors - 2) {
    1203      254712 :                         continue; 
    1204             :                 }
    1205             : 
    1206     1188711 :                 for (j = 0; j < transports[i].num_protocols && j < MAX_PROTSEQ; j++) {
    1207      905835 :                         if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
    1208       59131 :                                 break;
    1209             :                         }
    1210             :                 }
    1211             : 
    1212      343416 :                 if (j == transports[i].num_protocols) {
    1213      282876 :                         return transports[i].transport;
    1214             :                 }
    1215             :         }
    1216             : 
    1217             :         /* Unknown transport */
    1218         190 :         return (unsigned int)-1;
    1219             : }
    1220             : 
    1221       93613 : _PUBLIC_ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t)
    1222             : {
    1223         716 :         size_t i;
    1224             : 
    1225      115523 :         for (i=0; i<ARRAY_SIZE(transports); i++) {
    1226      115523 :                 if (t == transports[i].transport) {
    1227       93613 :                         return transports[i].name;
    1228             :                 }
    1229             :         }
    1230           0 :         return NULL;
    1231             : }
    1232             : 
    1233      169505 : _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_name(const char *name)
    1234             : {
    1235        1771 :         size_t i;
    1236             : 
    1237      169505 :         if (name == NULL) {
    1238           0 :                 return NCA_UNKNOWN;
    1239             :         }
    1240             : 
    1241      259013 :         for (i=0; i<ARRAY_SIZE(transports);i++) {
    1242      259013 :                 if (strcasecmp(name, transports[i].name) == 0) {
    1243      169505 :                         return transports[i].transport;
    1244             :                 }
    1245             :         }
    1246             : 
    1247           0 :         return NCA_UNKNOWN;
    1248             : }
    1249             : 
    1250         501 : _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
    1251             :                                             struct epm_tower *tower,
    1252             :                                             struct dcerpc_binding **b_out)
    1253             : {
    1254          35 :         NTSTATUS status;
    1255          35 :         struct dcerpc_binding *b;
    1256          35 :         enum dcerpc_transport_t transport;
    1257          35 :         struct ndr_syntax_id abstract_syntax;
    1258         501 :         char *endpoint = NULL;
    1259         501 :         char *host = NULL;
    1260             : 
    1261             :         /*
    1262             :          * A tower needs to have at least 4 floors to carry useful
    1263             :          * information. Floor 3 is the transport identifier which defines
    1264             :          * how many floors are required at least.
    1265             :          */
    1266         501 :         if (tower->num_floors < 4) {
    1267           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1268             :         }
    1269             : 
    1270         501 :         status = dcerpc_parse_binding(mem_ctx, "", &b);
    1271         501 :         if (!NT_STATUS_IS_OK(status)) {
    1272           0 :                 return status;
    1273             :         }
    1274             : 
    1275         501 :         transport = dcerpc_transport_by_tower(tower);
    1276         501 :         if (transport == NCA_UNKNOWN) {
    1277           0 :                 talloc_free(b);
    1278           0 :                 return NT_STATUS_NOT_SUPPORTED;
    1279             :         }
    1280             : 
    1281         501 :         status = dcerpc_binding_set_transport(b, transport);
    1282         501 :         if (!NT_STATUS_IS_OK(status)) {
    1283           0 :                 talloc_free(b);
    1284           0 :                 return status;
    1285             :         }
    1286             : 
    1287             :         /* Set abstract syntax */
    1288         501 :         status = dcerpc_floor_get_uuid_full(&tower->floors[0], &abstract_syntax);
    1289         501 :         if (!NT_STATUS_IS_OK(status)) {
    1290           0 :                 talloc_free(b);
    1291           0 :                 return status;
    1292             :         }
    1293             : 
    1294         501 :         status = dcerpc_binding_set_abstract_syntax(b, &abstract_syntax);
    1295         501 :         if (!NT_STATUS_IS_OK(status)) {
    1296           0 :                 talloc_free(b);
    1297           0 :                 return status;
    1298             :         }
    1299             : 
    1300             :         /* Ignore floor 1, it contains the NDR version info */
    1301             : 
    1302             :         /* Set endpoint */
    1303         501 :         errno = 0;
    1304         501 :         if (tower->num_floors >= 4) {
    1305         501 :                 endpoint = dcerpc_floor_get_rhs_data(b, &tower->floors[3]);
    1306             :         }
    1307         501 :         if (errno != 0) {
    1308           0 :                 int saved_errno = errno;
    1309           0 :                 talloc_free(b);
    1310           0 :                 return map_nt_error_from_unix_common(saved_errno);
    1311             :         }
    1312             : 
    1313         501 :         status = dcerpc_binding_set_string_option(b, "endpoint", endpoint);
    1314         501 :         if (!NT_STATUS_IS_OK(status)) {
    1315           0 :                 talloc_free(b);
    1316           0 :                 return status;
    1317             :         }
    1318         501 :         TALLOC_FREE(endpoint);
    1319             : 
    1320             :         /* Set network address */
    1321         501 :         errno = 0;
    1322         501 :         if (tower->num_floors >= 5) {
    1323         496 :                 host = dcerpc_floor_get_rhs_data(b, &tower->floors[4]);
    1324             :         }
    1325         501 :         if (errno != 0) {
    1326           0 :                 int saved_errno = errno;
    1327           0 :                 talloc_free(b);
    1328           0 :                 return map_nt_error_from_unix_common(saved_errno);
    1329             :         }
    1330             : 
    1331         501 :         status = dcerpc_binding_set_string_option(b, "host", host);
    1332         501 :         if (!NT_STATUS_IS_OK(status)) {
    1333           0 :                 talloc_free(b);
    1334           0 :                 return status;
    1335             :         }
    1336         501 :         status = dcerpc_binding_set_string_option(b, "target_hostname", host);
    1337         501 :         if (!NT_STATUS_IS_OK(status)) {
    1338           0 :                 talloc_free(b);
    1339           0 :                 return status;
    1340             :         }
    1341         501 :         TALLOC_FREE(host);
    1342             : 
    1343         501 :         *b_out = b;
    1344         501 :         return NT_STATUS_OK;
    1345             : }
    1346             : 
    1347      486412 : _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
    1348             :                                                    const struct dcerpc_binding *b)
    1349             : {
    1350        9136 :         struct dcerpc_binding *n;
    1351        9136 :         uint32_t count;
    1352             : 
    1353      486412 :         n = talloc_zero(mem_ctx, struct dcerpc_binding);
    1354      486412 :         if (n == NULL) {
    1355           0 :                 return NULL;
    1356             :         }
    1357             : 
    1358      486412 :         n->transport = b->transport;
    1359      486412 :         n->object = b->object;
    1360      486412 :         n->flags = b->flags;
    1361      486412 :         n->assoc_group_id = b->assoc_group_id;
    1362             : 
    1363      486412 :         if (b->object_string != NULL) {
    1364          25 :                 n->object_string = talloc_strdup(n, b->object_string);
    1365          25 :                 if (n->object_string == NULL) {
    1366           0 :                         goto nomem;
    1367             :                 }
    1368             :         }
    1369      486412 :         if (b->host != NULL) {
    1370       61530 :                 n->host = talloc_strdup(n, b->host);
    1371       61530 :                 if (n->host == NULL) {
    1372           0 :                         goto nomem;
    1373             :                 }
    1374             :         }
    1375             : 
    1376      486412 :         if (b->target_hostname != NULL) {
    1377       61530 :                 n->target_hostname = talloc_strdup(n, b->target_hostname);
    1378       61530 :                 if (n->target_hostname == NULL) {
    1379           0 :                         goto nomem;
    1380             :                 }
    1381             :         }
    1382             : 
    1383      486412 :         if (b->target_principal != NULL) {
    1384       14722 :                 n->target_principal = talloc_strdup(n, b->target_principal);
    1385       14722 :                 if (n->target_principal == NULL) {
    1386           0 :                         goto nomem;
    1387             :                 }
    1388             :         }
    1389             : 
    1390      486412 :         if (b->endpoint != NULL) {
    1391      449055 :                 n->endpoint = talloc_strdup(n, b->endpoint);
    1392      449055 :                 if (n->endpoint == NULL) {
    1393           0 :                         goto nomem;
    1394             :                 }
    1395             :         }
    1396             : 
    1397      548267 :         for (count = 0; b->options && b->options[count]; count++);
    1398             : 
    1399      486412 :         if (count > 0) {
    1400        1845 :                 uint32_t i;
    1401             : 
    1402       47191 :                 n->options = talloc_array(n, const char *, count + 1);
    1403       47191 :                 if (n->options == NULL) {
    1404           0 :                         goto nomem;
    1405             :                 }
    1406             : 
    1407      109046 :                 for (i = 0; i < count; i++) {
    1408       61855 :                         n->options[i] = talloc_strdup(n->options, b->options[i]);
    1409       61855 :                         if (n->options[i] == NULL) {
    1410           0 :                                 goto nomem;
    1411             :                         }
    1412             :                 }
    1413       47191 :                 n->options[count] = NULL;
    1414             :         }
    1415             : 
    1416      477276 :         return n;
    1417           0 : nomem:
    1418           0 :         TALLOC_FREE(n);
    1419           0 :         return NULL;
    1420             : }
    1421             : 
    1422      427379 : _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
    1423             :                                              const struct dcerpc_binding *binding,
    1424             :                                              struct epm_tower *tower)
    1425             : {
    1426      427379 :         const enum epm_protocol *protseq = NULL;
    1427      427379 :         size_t i, num_protocols = 0;
    1428        7160 :         struct ndr_syntax_id abstract_syntax;
    1429        7160 :         NTSTATUS status;
    1430             : 
    1431             :         /* Find transport */
    1432      945890 :         for (i=0;i<ARRAY_SIZE(transports);i++) {
    1433      945890 :                 if (transports[i].transport == binding->transport) {
    1434      427379 :                         protseq = transports[i].protseq;
    1435      427379 :                         num_protocols = transports[i].num_protocols;
    1436      427379 :                         break;
    1437             :                 }
    1438             :         }
    1439             : 
    1440      427379 :         if (i == ARRAY_SIZE(transports)) {
    1441           0 :                 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
    1442           0 :                 return NT_STATUS_UNSUCCESSFUL;
    1443             :         }
    1444             : 
    1445      427379 :         tower->num_floors = 2 + num_protocols;
    1446      427379 :         tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
    1447      427379 :         if (tower->floors == NULL) {
    1448           0 :                 return NT_STATUS_NO_MEMORY;
    1449             :         }
    1450             : 
    1451             :         /* Floor 0 */
    1452      427379 :         abstract_syntax = dcerpc_binding_get_abstract_syntax(binding);
    1453      427379 :         status = dcerpc_floor_pack_uuid_full(tower->floors,
    1454             :                                              &tower->floors[0],
    1455             :                                              &abstract_syntax);
    1456      427379 :         if (!NT_STATUS_IS_OK(status)) {
    1457           0 :                 return status;
    1458             :         }
    1459             : 
    1460             :         /* Floor 1 */
    1461      434539 :         status = dcerpc_floor_pack_uuid_full(tower->floors,
    1462      427379 :                                              &tower->floors[1],
    1463             :                                              &ndr_transfer_syntax_ndr);
    1464      427379 :         if (!NT_STATUS_IS_OK(status)) {
    1465           0 :                 return status;
    1466             :         }
    1467             : 
    1468             :         /* Floor 2 to num_protocols */
    1469     1617898 :         for (i = 0; i < num_protocols; i++) {
    1470     1190519 :                 tower->floors[2 + i].lhs.protocol = protseq[i];
    1471     1190519 :                 tower->floors[2 + i].lhs.lhs_data = data_blob_null;
    1472     1190519 :                 ZERO_STRUCT(tower->floors[2 + i].rhs);
    1473     1210490 :                 status = dcerpc_floor_set_rhs_data(tower->floors,
    1474     1190519 :                                                    &tower->floors[2 + i],
    1475             :                                                    NULL);
    1476     1190519 :                 if (!NT_STATUS_IS_OK(status)) {
    1477           0 :                         return status;
    1478             :                 }
    1479             :         }
    1480             : 
    1481             :         /* The 4th floor contains the endpoint */
    1482      427379 :         if (num_protocols >= 2 && binding->endpoint) {
    1483      428601 :                 status = dcerpc_floor_set_rhs_data(tower->floors,
    1484      421580 :                                                    &tower->floors[3],
    1485      414559 :                                                    binding->endpoint);
    1486      421580 :                 if (!NT_STATUS_IS_OK(status)) {
    1487           0 :                         return status;
    1488             :                 }
    1489             :         }
    1490             : 
    1491             :         /* The 5th contains the network address */
    1492      427379 :         if (num_protocols >= 3 && binding->host) {
    1493        6020 :                 status = dcerpc_floor_set_rhs_data(tower->floors,
    1494        5874 :                                                    &tower->floors[4],
    1495        5728 :                                                    binding->host);
    1496        5874 :                 if (!NT_STATUS_IS_OK(status)) {
    1497           0 :                         return status;
    1498             :                 }
    1499             :         }
    1500             : 
    1501      427379 :         return NT_STATUS_OK;
    1502             : }

Generated by: LCOV version 1.14