LCOV - code coverage report
Current view: top level - source3/rpc_server/epmapper - srv_epmapper.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 275 483 56.9 %
Date: 2024-04-21 15:09:00 Functions: 10 14 71.4 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Endpoint server for the epmapper pipe
       5             : 
       6             :    Copyright (C) 2010-2011 Andreas Schneider <asn@samba.org>
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "ntdomain.h"
      24             : #include "../libcli/security/security.h"
      25             : #include "../lib/tsocket/tsocket.h"
      26             : #include "auth.h"
      27             : 
      28             : #include "librpc/rpc/dcesrv_core.h"
      29             : #include "librpc/gen_ndr/ndr_epmapper.h"
      30             : #include "librpc/gen_ndr/ndr_epmapper_scompat.h"
      31             : #include "rpc_server/rpc_server.h"
      32             : #include "lib/tdb_wrap/tdb_wrap.h"
      33             : #include "lib/util/util_tdb.h"
      34             : #include "lib/util/strv.h"
      35             : 
      36             : static struct tdb_wrap *epmdb = NULL;
      37             : 
      38             : /* handle types for this module */
      39             : enum handle_types {HTYPE_LOOKUP};
      40             : 
      41             : typedef uint32_t error_status_t;
      42             : 
      43             : /* An endpoint combined with an interface description */
      44             : struct dcesrv_ep_iface {
      45             :         const char *name;
      46             :         struct ndr_syntax_id syntax_id;
      47             :         struct epm_tower ep;
      48             : };
      49             : 
      50             : /* A rpc service interface like samr, lsarpc or netlogon */
      51             : struct dcesrv_iface {
      52             :         const char *name;
      53             :         struct ndr_syntax_id syntax_id;
      54             : };
      55             : 
      56             : struct dcesrv_iface_list {
      57             :         struct dcesrv_iface_list *next, *prev;
      58             :         struct dcesrv_iface *iface;
      59             : };
      60             : 
      61             : /*
      62             :  * An endpoint can serve multiple rpc services interfaces.
      63             :  * For example \\pipe\netlogon can be used by lsarpc and netlogon.
      64             :  */
      65             : struct dcesrv_epm_endpoint {
      66             :         struct dcesrv_epm_endpoint *next, *prev;
      67             : 
      68             :         /* The type and the location of the endpoint */
      69             :         struct dcerpc_binding *ep_description;
      70             : 
      71             :         /* A list of rpc services able to connect to the endpoint */
      72             :         struct dcesrv_iface_list *iface_list;
      73             : };
      74             : 
      75             : struct rpc_eps {
      76             :         struct dcesrv_ep_iface *e;
      77             :         uint32_t count;
      78             : };
      79             : 
      80             : struct build_ep_list_state {
      81             :         const struct GUID *uuid;
      82             :         const char *srv_addr;
      83             :         TALLOC_CTX *mem_ctx;
      84             :         struct dcesrv_ep_iface *ifaces;
      85             : };
      86             : 
      87         352 : static bool build_ep_list_fill_iface(
      88             :         TALLOC_CTX *mem_ctx,
      89             :         const struct ndr_syntax_id *syntax_id,
      90             :         const char *endpoint,
      91             :         const char *name,
      92             :         const char *srv_addr,
      93             :         struct dcesrv_ep_iface *dst)
      94             : {
      95         352 :         struct dcesrv_ep_iface iface = {
      96             :                 .syntax_id = *syntax_id,
      97             :         };
      98         352 :         struct dcerpc_binding *binding = NULL;
      99           0 :         enum dcerpc_transport_t transport;
     100         352 :         char *name_dup = NULL;
     101         352 :         const char *host_addr = NULL;
     102           0 :         NTSTATUS status;
     103             : 
     104             :         /* copy without const for error path TALLOC_FREE */
     105         352 :         name_dup = talloc_strdup(mem_ctx, name);
     106         352 :         if (name_dup == NULL) {
     107           0 :                 goto fail;
     108             :         }
     109         352 :         iface.name = name_dup;
     110             : 
     111         352 :         status = dcerpc_parse_binding(mem_ctx, endpoint, &binding);
     112         352 :         if (!NT_STATUS_IS_OK(status)) {
     113           0 :                 DBG_DEBUG("dcerpc_parse_binding failed: %s\n",
     114             :                           nt_errstr(status));
     115           0 :                 goto fail;
     116             :         }
     117             : 
     118         352 :         status = dcerpc_binding_set_abstract_syntax(binding, syntax_id);
     119         352 :         if (!NT_STATUS_IS_OK(status)) {
     120           0 :                 DBG_DEBUG("dcerpc_binding_set_abstract_syntax failed: %s\n",
     121             :                           nt_errstr(status));
     122           0 :                 goto fail;
     123             :         }
     124             : 
     125         352 :         transport = dcerpc_binding_get_transport(binding);
     126         352 :         if (transport == NCACN_IP_TCP) {
     127          80 :                 const char *host = NULL;
     128             : 
     129          80 :                 host = dcerpc_binding_get_string_option(binding, "host");
     130          80 :                 if (host == NULL) {
     131          80 :                         host_addr = srv_addr;
     132           0 :                 } else if (!is_ipaddress_v4(host)) {
     133           0 :                         host_addr = srv_addr;
     134           0 :                 } else if (strcmp(host, "0.0.0.0") == 0) {
     135           0 :                         host_addr = srv_addr;
     136             :                 }
     137             :         }
     138             : 
     139         352 :         if (host_addr != NULL) {
     140          20 :                 status = dcerpc_binding_set_string_option(
     141             :                         binding, "host", host_addr);
     142          20 :                 if (!NT_STATUS_IS_OK(status)) {
     143           0 :                         DBG_DEBUG("dcerpc_binding_set_string_option "
     144             :                                   "failed: %s\n",
     145             :                                   nt_errstr(status));
     146           0 :                         goto fail;
     147             :                 }
     148             :         }
     149             : 
     150         352 :         status = dcerpc_binding_build_tower(mem_ctx, binding, &iface.ep);
     151         352 :         TALLOC_FREE(binding);
     152         352 :         if (!NT_STATUS_IS_OK(status)) {
     153           0 :                 DBG_DEBUG("dcerpc_binding_build_tower failed: %s\n",
     154             :                           nt_errstr(status));
     155           0 :                 goto fail;
     156             :         }
     157             : 
     158         352 :         *dst = iface;
     159         352 :         return true;
     160             : 
     161           0 : fail:
     162           0 :         TALLOC_FREE(binding);
     163           0 :         TALLOC_FREE(name_dup);
     164           0 :         TALLOC_FREE(iface.ep.floors);
     165           0 :         return false;
     166             : }
     167             : 
     168         136 : static int build_ep_list_fn(
     169             :         struct tdb_context *tdb,
     170             :         TDB_DATA key,
     171             :         TDB_DATA value,
     172             :         void *private_data)
     173             : {
     174         136 :         struct build_ep_list_state *state = private_data;
     175         136 :         struct ndr_syntax_id syntax_id = { .if_version = 0 };
     176         136 :         const char *name = NULL;
     177         136 :         char *endpoints = NULL;
     178         136 :         const char *endpoint = NULL;
     179           0 :         bool ok;
     180             : 
     181         136 :         if ((key.dsize == 0) || (key.dptr[key.dsize-1] != '\0') ||
     182         136 :             (value.dsize == 0) || (value.dptr[value.dsize-1] != '\0')) {
     183           0 :                 DBG_DEBUG("Invalid record\n");
     184           0 :                 return 0;
     185             :         }
     186             : 
     187         136 :         ok = ndr_syntax_id_from_string((char *)key.dptr, &syntax_id);
     188         136 :         if (!ok) {
     189           0 :                 DBG_DEBUG("Invalid interface: %s\n", (char *)key.dptr);
     190           0 :                 return 0;
     191             :         }
     192             : 
     193         136 :         endpoints = (char *)value.dptr;
     194         136 :         endpoint = endpoints;
     195         136 :         name = endpoints;
     196             : 
     197         488 :         while ((endpoint = strv_len_next(endpoints, value.dsize, endpoint))) {
     198         352 :                 size_t num_ifaces = talloc_array_length(state->ifaces);
     199         352 :                 struct dcesrv_ep_iface *tmp = NULL;
     200             : 
     201         352 :                 if (num_ifaces+1 < num_ifaces) {
     202           0 :                         return 1;
     203             :                 }
     204             : 
     205         352 :                 tmp = talloc_realloc(
     206             :                         state->mem_ctx,
     207             :                         state->ifaces,
     208             :                         struct dcesrv_ep_iface,
     209             :                         num_ifaces+1);
     210         352 :                 if (tmp == NULL) {
     211           0 :                         return 1;
     212             :                 }
     213         352 :                 state->ifaces = tmp;
     214             : 
     215         352 :                 ok = build_ep_list_fill_iface(
     216         352 :                         state->ifaces,
     217             :                         &syntax_id,
     218             :                         endpoint,
     219             :                         name,
     220             :                         state->srv_addr,
     221         352 :                         &state->ifaces[num_ifaces]);
     222         352 :                 if (!ok) {
     223           0 :                         state->ifaces = talloc_realloc(
     224             :                                 state->mem_ctx,
     225             :                                 state->ifaces,
     226             :                                 struct dcesrv_ep_iface,
     227             :                                 num_ifaces);
     228             :                 }
     229             :         }
     230             : 
     231         136 :         return 0;
     232             : }
     233             : 
     234             : /*
     235             :  * Build a list of all interfaces handled by all endpoint servers.
     236             :  */
     237           8 : static uint32_t build_ep_list(TALLOC_CTX *mem_ctx,
     238             :                               const struct GUID *uuid,
     239             :                               const char *srv_addr,
     240             :                               struct dcesrv_ep_iface **peps)
     241             : {
     242           8 :         struct build_ep_list_state state = {
     243             :                 .mem_ctx = mem_ctx, .uuid = uuid, .srv_addr = srv_addr,
     244             :         };
     245           0 :         int ret;
     246             : 
     247           8 :         ret = tdb_traverse_read(epmdb->tdb, build_ep_list_fn, &state);
     248           8 :         if (ret == -1) {
     249           0 :                 DBG_DEBUG("tdb_traverse_read failed\n");
     250           0 :                 return 0;
     251             :         }
     252             : 
     253           8 :         *peps = state.ifaces;
     254           8 :         return talloc_array_length(*peps);
     255             : }
     256             : 
     257             : /*
     258             :  * epm_Insert
     259             :  *
     260             :  * Add the specified entries to an endpoint map.
     261             :  */
     262           4 : error_status_t _epm_Insert(struct pipes_struct *p,
     263             :                            struct epm_Insert *r)
     264             : {
     265           4 :         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
     266           4 :         return EPMAPPER_STATUS_CANT_PERFORM_OP;
     267             : }
     268             : 
     269             : /*
     270             :  * epm_Delete
     271             :  *
     272             :  * Delete the specified entries from an endpoint map.
     273             :  */
     274           0 : error_status_t _epm_Delete(struct pipes_struct *p,
     275             :                            struct epm_Delete *r)
     276             : {
     277           0 :         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
     278           0 :         return EPMAPPER_STATUS_CANT_PERFORM_OP;
     279             : }
     280             : 
     281             : /*
     282             :  * epm_Lookup
     283             :  *
     284             :  * Lookup entries in an endpoint map.
     285             :  */
     286          28 : error_status_t _epm_Lookup(struct pipes_struct *p,
     287             :                            struct epm_Lookup *r)
     288             : {
     289          28 :         struct dcesrv_call_state *dce_call = p->dce_call;
     290          28 :         struct dcesrv_connection *dcesrv_conn = dce_call->conn;
     291           0 :         struct policy_handle *entry_handle;
     292           0 :         struct rpc_eps *eps;
     293           0 :         TALLOC_CTX *tmp_ctx;
     294           0 :         error_status_t rc;
     295          28 :         uint32_t count = 0;
     296          28 :         uint32_t num_ents = 0;
     297           0 :         uint32_t i;
     298          28 :         bool match = false;
     299           0 :         bool ok;
     300           0 :         NTSTATUS status;
     301             : 
     302          28 :         *r->out.num_ents = 0;
     303          28 :         r->out.entries = NULL;
     304             : 
     305          28 :         tmp_ctx = talloc_stackframe();
     306          28 :         if (tmp_ctx == NULL) {
     307           0 :                 return EPMAPPER_STATUS_NO_MEMORY;
     308             :         }
     309             : 
     310          28 :         DEBUG(5, ("_epm_Lookup: Trying to lookup max. %u entries.\n",
     311             :                   r->in.max_ents));
     312             : 
     313          56 :         if (r->in.entry_handle == NULL ||
     314          28 :             ndr_policy_handle_empty(r->in.entry_handle)) {
     315           0 :                 const struct tsocket_address *local_address =
     316           8 :                         dcesrv_connection_get_local_address(dcesrv_conn);
     317           8 :                 char *srv_addr = NULL;
     318             : 
     319           8 :                 DEBUG(7, ("_epm_Lookup: No entry_handle found, creating it.\n"));
     320             : 
     321           8 :                 eps = talloc_zero(tmp_ctx, struct rpc_eps);
     322           8 :                 if (eps == NULL) {
     323           0 :                         rc = EPMAPPER_STATUS_NO_MEMORY;
     324           0 :                         goto done;
     325             :                 }
     326             : 
     327          16 :                 if (local_address != NULL &&
     328           8 :                     tsocket_address_is_inet(local_address, "ipv4"))
     329             :                 {
     330           2 :                         srv_addr = tsocket_address_inet_addr_string(
     331             :                                 local_address, tmp_ctx);
     332             :                 }
     333             : 
     334           8 :                 switch (r->in.inquiry_type) {
     335           8 :                 case RPC_C_EP_ALL_ELTS:
     336             :                         /*
     337             :                          * Return all elements from the endpoint map. The
     338             :                          * interface_id, vers_option, and object parameters MUST
     339             :                          * be ignored.
     340             :                          */
     341           8 :                         eps->count = build_ep_list(eps,
     342             :                                                    NULL,
     343             :                                                    srv_addr,
     344             :                                                    &eps->e);
     345           8 :                         break;
     346           0 :                 case RPC_C_EP_MATCH_BY_IF:
     347             :                         /*
     348             :                          * Return endpoint map elements that contain the
     349             :                          * interface identifier specified by the interface_id
     350             :                          * and vers_option values.
     351             :                          *
     352             :                          * RPC_C_EP_MATCH_BY_IF and RPC_C_EP_MATCH_BY_BOTH
     353             :                          * need both the same endpoint list. There is a second
     354             :                          * check for the inquiry_type below which differentiates
     355             :                          * between them.
     356             :                          */
     357             :                 case RPC_C_EP_MATCH_BY_BOTH:
     358             :                         /*
     359             :                          * Return endpoint map elements that contain the
     360             :                          * interface identifier and object UUID specified by
     361             :                          * interface_id, vers_option, and object.
     362             :                          */
     363           0 :                         eps->count = build_ep_list(eps,
     364           0 :                                                    &r->in.interface_id->uuid,
     365             :                                                    srv_addr,
     366             :                                                    &eps->e);
     367           0 :                         break;
     368           0 :                 case RPC_C_EP_MATCH_BY_OBJ:
     369             :                         /*
     370             :                          * Return endpoint map elements that contain the object
     371             :                          * UUID specified by object.
     372             :                          */
     373           0 :                         eps->count = build_ep_list(eps,
     374           0 :                                                    r->in.object,
     375             :                                                    srv_addr,
     376             :                                                    &eps->e);
     377           0 :                         break;
     378           0 :                 default:
     379           0 :                         rc = EPMAPPER_STATUS_CANT_PERFORM_OP;
     380           0 :                         goto done;
     381             :                 }
     382             : 
     383           8 :                 if (eps->count == 0) {
     384           0 :                         rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     385           0 :                         goto done;
     386             :                 }
     387             : 
     388           8 :                 ok = create_policy_hnd(p, r->out.entry_handle, HTYPE_LOOKUP, eps);
     389           8 :                 if (!ok) {
     390           0 :                         rc = EPMAPPER_STATUS_NO_MEMORY;
     391           0 :                         goto done;
     392             :                 }
     393             : 
     394           8 :                 eps = find_policy_by_hnd(p,
     395             :                                          r->out.entry_handle,
     396             :                                          HTYPE_LOOKUP,
     397             :                                          struct rpc_eps,
     398           0 :                                          &status);
     399           8 :                 if (!NT_STATUS_IS_OK(status)) {
     400           0 :                         rc = EPMAPPER_STATUS_NO_MEMORY;
     401           0 :                         goto done;
     402             :                 }
     403           8 :                 entry_handle = r->out.entry_handle;
     404             :         } else {
     405          20 :                 DEBUG(7, ("_epm_Lookup: Trying to find entry_handle.\n"));
     406             : 
     407          20 :                 eps = find_policy_by_hnd(p,
     408             :                                          r->in.entry_handle,
     409             :                                          HTYPE_LOOKUP,
     410             :                                          struct rpc_eps,
     411           0 :                                          &status);
     412          20 :                 if (!NT_STATUS_IS_OK(status)) {
     413           2 :                         rc = EPMAPPER_STATUS_NO_MEMORY;
     414           2 :                         goto done;
     415             :                 }
     416          18 :                 entry_handle = r->in.entry_handle;
     417             :         }
     418             : 
     419          26 :         if (eps == NULL || eps->e == NULL) {
     420           0 :                 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     421           0 :                 goto done;
     422             :         }
     423             : 
     424             :         /* return the next N elements */
     425          26 :         count = r->in.max_ents;
     426          26 :         if (count > eps->count) {
     427           4 :                 count = eps->count;
     428             :         }
     429             : 
     430          26 :         DEBUG(5, ("_epm_Lookup: Find %u entries\n", count));
     431             : 
     432          26 :         if (count == 0) {
     433           0 :                 close_policy_hnd(p, entry_handle);
     434           0 :                 ZERO_STRUCTP(r->out.entry_handle);
     435             : 
     436           0 :                 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     437           0 :                 goto done;
     438             :         }
     439             : 
     440          26 :         r->out.entries = talloc_array(p->mem_ctx, struct epm_entry_t, count);
     441          26 :         if (r->out.entries == NULL) {
     442           0 :                 rc = EPMAPPER_STATUS_NO_MEMORY;
     443           0 :                 goto done;
     444             :         }
     445             : 
     446         210 :         for (i = 0; i < count; i++) {
     447         184 :                 match = false;
     448             : 
     449         184 :                 switch (r->in.inquiry_type) {
     450         184 :                 case RPC_C_EP_ALL_ELTS:
     451             :                         /*
     452             :                          * Return all elements from the endpoint map. The
     453             :                          * interface_id, vers_option, and object parameters MUST
     454             :                          * be ignored.
     455             :                          */
     456         184 :                         match = true;
     457         184 :                         break;
     458           0 :                 case RPC_C_EP_MATCH_BY_IF:
     459             :                         /*
     460             :                          * Return endpoint map elements that contain the
     461             :                          * interface identifier specified by the interface_id
     462             :                          * and vers_option values.
     463             :                          */
     464           0 :                         if (GUID_equal(&r->in.interface_id->uuid,
     465           0 :                                        &eps->e[i].syntax_id.uuid)) {
     466           0 :                                 match = true;
     467             :                         }
     468           0 :                         break;
     469           0 :                 case RPC_C_EP_MATCH_BY_OBJ:
     470             :                         /*
     471             :                          * Return endpoint map elements that contain the object
     472             :                          * UUID specified by object.
     473             :                          */
     474           0 :                         if (GUID_equal(r->in.object,
     475           0 :                                        &eps->e[i].syntax_id.uuid)) {
     476           0 :                                 match = true;
     477             :                         }
     478           0 :                         break;
     479           0 :                 case RPC_C_EP_MATCH_BY_BOTH:
     480             :                         /*
     481             :                          * Return endpoint map elements that contain the
     482             :                          * interface identifier and object UUID specified by
     483             :                          * interface_id, vers_option, and object.
     484             :                          */
     485           0 :                         if (GUID_equal(&r->in.interface_id->uuid,
     486           0 :                                        &eps->e[i].syntax_id.uuid) &&
     487           0 :                             GUID_equal(r->in.object, &eps->e[i].syntax_id.uuid)) {
     488           0 :                                 match = true;
     489             :                         }
     490           0 :                         break;
     491           0 :                 default:
     492           0 :                         return EPMAPPER_STATUS_CANT_PERFORM_OP;
     493             :                 }
     494             : 
     495         184 :                 if (match) {
     496         184 :                         if (r->in.inquiry_type == RPC_C_EP_MATCH_BY_IF ||
     497         184 :                             r->in.inquiry_type == RPC_C_EP_MATCH_BY_OBJ) {
     498             :                                 /* Check interface version */
     499             : 
     500           0 :                                 match = false;
     501           0 :                                 switch (r->in.vers_option) {
     502           0 :                                 case RPC_C_VERS_ALL:
     503             :                                         /*
     504             :                                          * Return endpoint map elements that
     505             :                                          * contain the specified interface UUID,
     506             :                                          * regardless of the version numbers.
     507             :                                          */
     508           0 :                                         match = true;
     509           0 :                                         break;
     510           0 :                                 case RPC_C_VERS_COMPATIBLE:
     511             :                                         /*
     512             :                                          * Return the endpoint map elements that
     513             :                                          * contain the same major versions of
     514             :                                          * the specified interface UUID and a
     515             :                                          * minor version greater than or equal
     516             :                                          * to the minor version of the specified
     517             :                                          * UUID.
     518             :                                          */
     519           0 :                                         if (r->in.interface_id->vers_major ==
     520           0 :                                             (eps->e[i].syntax_id.if_version >> 16) &&
     521           0 :                                             r->in.interface_id->vers_minor <=
     522           0 :                                             (eps->e[i].syntax_id.if_version & 0xFFFF)) {
     523           0 :                                                 match = true;
     524             :                                         }
     525           0 :                                         break;
     526           0 :                                 case RPC_C_VERS_EXACT:
     527             :                                         /*
     528             :                                          * Return endpoint map elements that
     529             :                                          * contain the specified version of the
     530             :                                          * specified interface UUID.
     531             :                                          */
     532           0 :                                         if (r->in.interface_id->vers_major ==
     533           0 :                                             (eps->e[i].syntax_id.if_version >> 16) &&
     534           0 :                                             r->in.interface_id->vers_minor ==
     535           0 :                                             (eps->e[i].syntax_id.if_version & 0xFFFF)) {
     536           0 :                                                 match = true;
     537             :                                         }
     538           0 :                                         match = true;
     539           0 :                                         break;
     540           0 :                                 case RPC_C_VERS_MAJOR_ONLY:
     541             :                                         /*
     542             :                                          * Return endpoint map elements that
     543             :                                          * contain the same version of the
     544             :                                          * specified interface UUID and ignore
     545             :                                          * the minor version.
     546             :                                          */
     547           0 :                                         if (r->in.interface_id->vers_major ==
     548           0 :                                             (eps->e[i].syntax_id.if_version >> 16)) {
     549           0 :                                                 match = true;
     550             :                                         }
     551           0 :                                         match = true;
     552           0 :                                         break;
     553           0 :                                 case RPC_C_VERS_UPTO:
     554             :                                         /*
     555             :                                          * Return endpoint map elements that
     556             :                                          * contain a version of the specified
     557             :                                          * interface UUID less than or equal to
     558             :                                          * the specified major and minor
     559             :                                          * version.
     560             :                                          */
     561           0 :                                         if (r->in.interface_id->vers_major >
     562           0 :                                             eps->e[i].syntax_id.if_version >> 16) {
     563           0 :                                                 match = true;
     564             :                                         } else {
     565           0 :                                                 if (r->in.interface_id->vers_major ==
     566           0 :                                                     (eps->e[i].syntax_id.if_version >> 16) &&
     567           0 :                                                     r->in.interface_id->vers_minor >=
     568           0 :                                                     (eps->e[i].syntax_id.if_version & 0xFFFF)) {
     569           0 :                                                         match = true;
     570             :                                                 }
     571             :                                         }
     572           0 :                                         break;
     573           0 :                                 default:
     574           0 :                                         return EPMAPPER_STATUS_CANT_PERFORM_OP;
     575             :                                 }
     576             :                         }
     577             :                 }
     578             : 
     579         184 :                 if (match) {
     580         184 :                         ZERO_STRUCT(r->out.entries[num_ents].object);
     581             : 
     582         184 :                         DEBUG(10, ("_epm_Lookup: Adding tower for '%s'\n",
     583             :                                    eps->e[i].name));
     584         368 :                         r->out.entries[num_ents].annotation = talloc_strdup(r->out.entries,
     585         184 :                                                                             eps->e[i].name);
     586         184 :                         r->out.entries[num_ents].tower = talloc(r->out.entries,
     587             :                                                                 struct epm_twr_t);
     588         184 :                         if (r->out.entries[num_ents].tower == NULL) {
     589           0 :                                 rc = EPMAPPER_STATUS_NO_MEMORY;
     590           0 :                                 goto done;
     591             :                         }
     592         184 :                         r->out.entries[num_ents].tower->tower.floors = talloc_move(r->out.entries[num_ents].tower, &eps->e[i].ep.floors);
     593         184 :                         r->out.entries[num_ents].tower->tower.num_floors = eps->e[i].ep.num_floors;
     594         184 :                         r->out.entries[num_ents].tower->tower_length = 0;
     595             : 
     596         184 :                         num_ents++;
     597             :                 }
     598             :         } /* end for loop */
     599             : 
     600          26 :         *r->out.num_ents = num_ents;
     601             : 
     602          26 :         eps->count -= count;
     603          26 :         eps->e += count;
     604          26 :         if (eps->count == 0) {
     605           4 :                 close_policy_hnd(p, entry_handle);
     606           4 :                 ZERO_STRUCTP(r->out.entry_handle);
     607           4 :                 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     608           4 :                 goto done;
     609             :         }
     610             : 
     611          22 :         rc = EPMAPPER_STATUS_OK;
     612          28 : done:
     613          28 :         talloc_free(tmp_ctx);
     614             : 
     615          28 :         return rc;
     616             : }
     617             : 
     618         720 : static struct rpc_eps *epm_map_get_towers(
     619             :         TALLOC_CTX *mem_ctx,
     620             :         const struct ndr_syntax_id *iface,
     621             :         enum dcerpc_transport_t transport,
     622             :         const char *local_address)
     623             : {
     624           0 :         struct ndr_syntax_id_buf idbuf;
     625         720 :         char *iface_string = ndr_syntax_id_buf_string(iface, &idbuf);
     626         720 :         struct rpc_eps *eps = NULL;
     627         720 :         uint8_t *buf = NULL;
     628           0 :         size_t buflen;
     629         720 :         char *bindings = NULL;
     630         720 :         char *binding = NULL;
     631         720 :         char *name = NULL;
     632           0 :         NTSTATUS status;
     633           0 :         int ret;
     634             : 
     635         720 :         DBG_DEBUG("Mapping interface %s\n", iface_string);
     636             : 
     637         720 :         eps = talloc_zero(mem_ctx, struct rpc_eps);
     638         720 :         if (eps == NULL) {
     639           0 :                 goto fail;
     640             :         }
     641             : 
     642         720 :         ret = tdb_fetch_talloc(
     643         720 :                 epmdb->tdb, string_term_tdb_data(iface_string), eps, &buf);
     644         720 :         if (ret != 0) {
     645          48 :                 DBG_DEBUG("Could not find epm entry for %s: %s\n",
     646             :                           iface_string,
     647             :                           strerror(ret));
     648          48 :                 goto fail;
     649             :         }
     650         672 :         buflen = talloc_array_length(buf);
     651             : 
     652         672 :         if ((buflen < 1) || (buf[buflen-1] != '\0')) {
     653           0 :                 DBG_DEBUG("epm entry for %s invalid\n", iface_string);
     654           0 :                 goto fail;
     655             :         }
     656         672 :         bindings = (char *)buf;
     657             : 
     658         672 :         name = bindings;        /* name comes first */
     659         672 :         binding = name;         /* strv_next will skip name */
     660             : 
     661        3046 :         while ((binding = strv_next(bindings, binding)) != NULL) {
     662        2374 :                 struct dcerpc_binding *b = NULL;
     663           0 :                 enum dcerpc_transport_t found_transport;
     664        2374 :                 struct dcesrv_ep_iface *tmp = NULL, *new_ep = NULL;
     665             : 
     666        2374 :                 DBG_DEBUG("Found %s for %s\n", binding, name);
     667             : 
     668        2374 :                 status = dcerpc_parse_binding(mem_ctx, binding, &b);
     669        2374 :                 if (!NT_STATUS_IS_OK(status)) {
     670           0 :                         DBG_DEBUG("dcerpc_parse_binding() for %s failed: %s\n",
     671             :                                   binding,
     672             :                                   nt_errstr(status));
     673           0 :                         goto fail;
     674             :                 }
     675             : 
     676        2374 :                 found_transport = dcerpc_binding_get_transport(b);
     677        2374 :                 if (found_transport != transport) {
     678        1568 :                         DBG_DEBUG("Transport %d does not match %d\n",
     679             :                                   (int)found_transport,
     680             :                                   (int)transport);
     681        1568 :                         TALLOC_FREE(b);
     682        1568 :                         continue;
     683             :                 }
     684             : 
     685         806 :                 if (found_transport == NCACN_IP_TCP) {
     686         210 :                         status = dcerpc_binding_set_string_option(
     687             :                                 b, "host", local_address);
     688         210 :                         if (!NT_STATUS_IS_OK(status)) {
     689           0 :                                 DBG_DEBUG("Could not set host: %s\n",
     690             :                                           nt_errstr(status));
     691           0 :                                 goto fail;
     692             :                         }
     693             :                 }
     694             : 
     695         806 :                 status = dcerpc_binding_set_abstract_syntax(b, iface);
     696         806 :                 if (!NT_STATUS_IS_OK(status)) {
     697           0 :                         DBG_DEBUG("Could not set abstract syntax: %s\n",
     698             :                                   nt_errstr(status));
     699           0 :                         goto fail;
     700             :                 }
     701             : 
     702         806 :                 tmp = talloc_realloc(
     703             :                         eps,
     704             :                         eps->e,
     705             :                         struct dcesrv_ep_iface,
     706             :                         eps->count+1);
     707         806 :                 if (tmp == NULL) {
     708           0 :                         goto fail;
     709             :                 }
     710         806 :                 eps->e = tmp;
     711             : 
     712         806 :                 new_ep = &eps->e[eps->count];
     713             : 
     714         806 :                 new_ep->name = talloc_strdup(eps->e, name);
     715         806 :                 if (new_ep->name == NULL) {
     716           0 :                         goto fail;
     717             :                 }
     718         806 :                 new_ep->syntax_id = *iface;
     719             : 
     720         806 :                 status = dcerpc_binding_build_tower(eps->e, b, &new_ep->ep);
     721         806 :                 if (!NT_STATUS_IS_OK(status)) {
     722           0 :                         DBG_DEBUG("dcerpc_binding_build_tower failed: %s\n",
     723             :                                   nt_errstr(status));
     724           0 :                         goto fail;
     725             :                 }
     726             : 
     727         806 :                 eps->count += 1;
     728             : 
     729         806 :                 TALLOC_FREE(b);
     730             :         }
     731         672 :         return eps;
     732             : 
     733          48 : fail:
     734          48 :         TALLOC_FREE(eps);
     735          48 :         return NULL;
     736             : }
     737             : 
     738             : /*
     739             :  * epm_Map
     740             :  *
     741             :  * Apply some algorithm (using the fields in the map_tower) to an endpoint map
     742             :  * to produce a list of protocol towers.
     743             :  */
     744         720 : error_status_t _epm_Map(struct pipes_struct *p,
     745             :                         struct epm_Map *r)
     746             : {
     747         720 :         struct dcesrv_call_state *dce_call = p->dce_call;
     748         720 :         struct dcesrv_connection *dcesrv_conn = dce_call->conn;
     749           0 :         struct policy_handle *entry_handle;
     750           0 :         enum dcerpc_transport_t transport;
     751           0 :         struct ndr_syntax_id ifid;
     752           0 :         struct epm_floor *floors;
     753           0 :         struct rpc_eps *eps;
     754           0 :         TALLOC_CTX *tmp_ctx;
     755           0 :         error_status_t rc;
     756         720 :         uint32_t count = 0;
     757         720 :         uint32_t num_towers = 0;
     758           0 :         uint32_t i;
     759           0 :         bool ok;
     760           0 :         NTSTATUS status;
     761             : 
     762         720 :         *r->out.num_towers = 0;
     763         720 :         r->out.towers = NULL;
     764             : 
     765         720 :         if (r->in.map_tower == NULL || r->in.max_towers == 0 ||
     766         720 :             r->in.map_tower->tower.num_floors < 3) {
     767           0 :                 return EPMAPPER_STATUS_NO_MORE_ENTRIES;
     768             :         }
     769             : 
     770         720 :         tmp_ctx = talloc_stackframe();
     771             : 
     772         720 :         ZERO_STRUCTP(r->out.entry_handle);
     773             : 
     774         720 :         DEBUG(5, ("_epm_Map: Trying to map max. %u towers.\n",
     775             :                   r->in.max_towers));
     776             : 
     777             :         /*
     778             :          * A tower has normally up to 6 floors
     779             :          *
     780             :          * +-----------------------------------------------------------------+
     781             :          * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for |
     782             :          * |         | netlogon)                                             |
     783             :          * +---------+-------------------------------------------------------+
     784             :          * | Floor 2 | Transfer syntax (NDR encoded)                        |
     785             :          * +---------+-------------------------------------------------------+
     786             :          * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) |
     787             :          * +---------+-------------------------------------------------------+
     788             :          * | Floor 4 | Port address (e.g. TCP Port: 49156)                   |
     789             :          * +---------+-------------------------------------------------------+
     790             :          * | Floor 5 | Transport (e.g. IP:192.168.51.10)                     |
     791             :          * +---------+-------------------------------------------------------+
     792             :          * | Floor 6 | Routing                                               |
     793             :          * +---------+-------------------------------------------------------+
     794             :          */
     795         720 :         floors = r->in.map_tower->tower.floors;
     796             : 
     797             :         /* We accept NDR as the transfer syntax */
     798         720 :         status = dcerpc_floor_get_uuid_full(&floors[1], &ifid);
     799         720 :         if (!NT_STATUS_IS_OK(status)) {
     800           0 :                 DBG_DEBUG("dcerpc_floor_get_uuid_full() failed: %s\n",
     801             :                           nt_errstr(status));
     802           0 :                 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     803           0 :                 goto done;
     804             :         }
     805             : 
     806         720 :         if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID ||
     807         720 :             !ndr_syntax_id_equal(&ifid, &ndr_transfer_syntax_ndr)) {
     808           0 :                 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     809           0 :                 goto done;
     810             :         }
     811             : 
     812             :         /* We only talk to sane transports */
     813         720 :         transport = dcerpc_transport_by_tower(&r->in.map_tower->tower);
     814         720 :         if (transport == NCA_UNKNOWN) {
     815           0 :                 DEBUG(2, ("epm_Map: Client requested unknown transport with "
     816             :                           "levels: "));
     817           0 :                 for (i = 2; i < r->in.map_tower->tower.num_floors; i++) {
     818           0 :                         DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol));
     819             :                 }
     820           0 :                 DEBUG(2, ("\n"));
     821           0 :                 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     822           0 :                 goto done;
     823             :         }
     824             : 
     825        1440 :         if (r->in.entry_handle == NULL ||
     826         720 :             ndr_policy_handle_empty(r->in.entry_handle)) {
     827           0 :                 const struct tsocket_address *local_addr =
     828         720 :                         dcesrv_connection_get_local_address(dcesrv_conn);
     829         720 :                 char *local_address = NULL;
     830           0 :                 struct ndr_syntax_id_buf buf;
     831         720 :                 char *if_string = NULL;
     832             : 
     833         720 :                 DEBUG(7, ("_epm_Map: No entry_handle found, creating it.\n"));
     834             : 
     835         720 :                 status = dcerpc_floor_get_uuid_full(&floors[0], &ifid);
     836         720 :                 if (!NT_STATUS_IS_OK(status)) {
     837           0 :                         DBG_DEBUG("dcerpc_floor_get_uuid_full() failed: %s\n",
     838             :                                   nt_errstr(status));
     839           0 :                         rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     840          48 :                         goto done;
     841             :                 }
     842             : 
     843         720 :                 if_string = ndr_syntax_id_buf_string(&ifid, &buf);
     844             : 
     845         720 :                 DBG_INFO("Mapping interface %s\n", if_string);
     846             : 
     847         978 :                 if ((transport == NCACN_IP_TCP) &&
     848         258 :                     tsocket_address_is_inet(local_addr, "ip")) {
     849             :                         /*
     850             :                          * We don't have the host ip in the epm
     851             :                          * database. For NCACN_IP_TCP, add the IP that
     852             :                          * the client connected to.
     853             :                          */
     854         182 :                         local_address = tsocket_address_inet_addr_string(
     855             :                                 local_addr, tmp_ctx);
     856             :                 }
     857             : 
     858         720 :                 eps = epm_map_get_towers(
     859             :                         tmp_ctx, &ifid, transport, local_address);
     860         720 :                 if (eps == NULL) {
     861          48 :                         DBG_DEBUG("No bindings found\n");
     862          48 :                         rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     863          48 :                         goto done;
     864             :                 }
     865             : 
     866         672 :                 ok = create_policy_hnd(p, r->out.entry_handle, HTYPE_LOOKUP, eps);
     867         672 :                 if (!ok) {
     868           0 :                         rc = EPMAPPER_STATUS_NO_MEMORY;
     869           0 :                         goto done;
     870             :                 }
     871             : 
     872         672 :                 eps = find_policy_by_hnd(p,
     873             :                                          r->out.entry_handle,
     874             :                                          HTYPE_LOOKUP,
     875             :                                          struct rpc_eps,
     876           0 :                                          &status);
     877         672 :                 if (!NT_STATUS_IS_OK(status)) {
     878           0 :                         rc = EPMAPPER_STATUS_NO_MEMORY;
     879           0 :                         goto done;
     880             :                 }
     881         672 :                 entry_handle = r->out.entry_handle;
     882             :         } else {
     883           0 :                 DEBUG(7, ("_epm_Map: Trying to find entry_handle.\n"));
     884             : 
     885           0 :                 eps = find_policy_by_hnd(p,
     886             :                                          r->in.entry_handle,
     887             :                                          HTYPE_LOOKUP,
     888             :                                          struct rpc_eps,
     889           0 :                                          &status);
     890           0 :                 if (!NT_STATUS_IS_OK(status)) {
     891           0 :                         rc = EPMAPPER_STATUS_NO_MEMORY;
     892           0 :                         goto done;
     893             :                 }
     894           0 :                 entry_handle = r->in.entry_handle;
     895             :         }
     896             : 
     897         672 :         if (eps == NULL || eps->e == NULL) {
     898         126 :                 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     899         126 :                 goto done;
     900             :         }
     901             : 
     902             :         /* return the next N elements */
     903         546 :         count = r->in.max_towers;
     904         546 :         if (count > eps->count) {
     905         396 :                 count = eps->count;
     906             :         }
     907             : 
     908         546 :         if (count == 0) {
     909           0 :                 close_policy_hnd(p, entry_handle);
     910           0 :                 ZERO_STRUCTP(r->out.entry_handle);
     911             : 
     912           0 :                 rc = EPMAPPER_STATUS_NO_MORE_ENTRIES;
     913           0 :                 goto done;
     914             :         }
     915             : 
     916         546 :         r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count);
     917         546 :         if (r->out.towers == NULL) {
     918           0 :                 rc = EPMAPPER_STATUS_NO_MEMORY;
     919           0 :                 goto done;
     920             :         }
     921             : 
     922        1352 :         for (i = 0; i < count; i++) {
     923         806 :                 DEBUG(7, ("_epm_Map: Map tower for '%s'\n",
     924             :                            eps->e[i].name));
     925             : 
     926         806 :                 r->out.towers[num_towers].twr = talloc(r->out.towers,
     927             :                                                        struct epm_twr_t);
     928         806 :                 if (r->out.towers[num_towers].twr == NULL) {
     929           0 :                         rc = EPMAPPER_STATUS_NO_MEMORY;
     930           0 :                         goto done;
     931             :                 }
     932         806 :                 r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors);
     933         806 :                 r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors;
     934         806 :                 r->out.towers[num_towers].twr->tower_length = 0;
     935             : 
     936         806 :                 num_towers++;
     937             :         }
     938             : 
     939         546 :         *r->out.num_towers = num_towers;
     940             : 
     941         546 :         eps->count -= count;
     942         546 :         eps->e += count;
     943         546 :         if (eps->count == 0) {
     944         546 :                 close_policy_hnd(p, entry_handle);
     945         546 :                 ZERO_STRUCTP(r->out.entry_handle);
     946             :         }
     947             : 
     948         546 :         rc = EPMAPPER_STATUS_OK;
     949         720 : done:
     950         720 :         talloc_free(tmp_ctx);
     951             : 
     952         720 :         return rc;
     953             : }
     954             : 
     955             : /*
     956             :  * epm_LookupHandleFree
     957             :  */
     958           4 : error_status_t _epm_LookupHandleFree(struct pipes_struct *p,
     959             :                                      struct epm_LookupHandleFree *r)
     960             : {
     961           4 :         if (r->in.entry_handle == NULL) {
     962           0 :                 return EPMAPPER_STATUS_OK;
     963             :         }
     964             : 
     965           4 :         if (is_valid_policy_hnd(r->in.entry_handle)) {
     966           4 :                 close_policy_hnd(p, r->in.entry_handle);
     967             :         }
     968             : 
     969           4 :         r->out.entry_handle = r->in.entry_handle;
     970             : 
     971           4 :         return EPMAPPER_STATUS_OK;
     972             : }
     973             : 
     974             : 
     975             : /*
     976             :  * epm_InqObject
     977             :  *
     978             :  * A client implementation SHOULD NOT call this method. These extensions do not
     979             :  * provide an alternative method.
     980             :  */
     981           0 : error_status_t _epm_InqObject(struct pipes_struct *p,
     982             :                       struct epm_InqObject *r)
     983             : {
     984           0 :         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
     985           0 :         return EPMAPPER_STATUS_CANT_PERFORM_OP;
     986             : }
     987             : 
     988             : 
     989             : /*
     990             :  * epm_MgmtDelete
     991             :  *
     992             :  * A client implementation SHOULD NOT call this method. These extensions do not
     993             :  * provide an alternative method.
     994             : */
     995           0 : error_status_t _epm_MgmtDelete(struct pipes_struct *p,
     996             :                        struct epm_MgmtDelete *r)
     997             : {
     998           0 :         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
     999           0 :         return EPMAPPER_STATUS_CANT_PERFORM_OP;
    1000             : }
    1001             : 
    1002             : 
    1003             : /*
    1004             :   epm_MapAuth
    1005             : */
    1006           0 : error_status_t _epm_MapAuth(struct pipes_struct *p,
    1007             :                     struct epm_MapAuth *r)
    1008             : {
    1009           0 :         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
    1010           0 :         return EPMAPPER_STATUS_CANT_PERFORM_OP;
    1011             : }
    1012             : 
    1013             : static NTSTATUS epmapper__op_shutdown_server(struct dcesrv_context *dce_ctx,
    1014             :                         const struct dcesrv_endpoint_server *ep_server);
    1015             : 
    1016             : #define DCESRV_INTERFACE_EPMAPPER_SHUTDOWN_SERVER \
    1017             :        epmapper_shutdown_server
    1018             : 
    1019          30 : static NTSTATUS epmapper_shutdown_server(struct dcesrv_context *dce_ctx,
    1020             :                 const struct dcesrv_endpoint_server *ep_server)
    1021             : {
    1022          30 :         return epmapper__op_shutdown_server(dce_ctx, ep_server);
    1023             : }
    1024             : 
    1025             : static NTSTATUS epmapper__op_init_server(
    1026             :         struct dcesrv_context *dce_ctx,
    1027             :         const struct dcesrv_endpoint_server *ep_server);
    1028             : 
    1029          30 : static NTSTATUS epmapper_init_server(
    1030             :         struct dcesrv_context *dce_ctx,
    1031             :         const struct dcesrv_endpoint_server *ep_server)
    1032             : {
    1033          30 :         char *epmdb_path = NULL;
    1034           0 :         NTSTATUS status;
    1035             : 
    1036          30 :         epmdb_path = lock_path(dce_ctx, "epmdb.tdb");
    1037          30 :         if (epmdb_path == NULL) {
    1038           0 :                 return NT_STATUS_NO_MEMORY;
    1039             :         }
    1040             : 
    1041          30 :         epmdb = tdb_wrap_open(
    1042             :                 dce_ctx,
    1043             :                 epmdb_path,
    1044             :                 0,
    1045             :                 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
    1046             :                 O_RDONLY,
    1047             :                 0644);
    1048          30 :         if (epmdb == NULL) {
    1049           0 :                 DBG_DEBUG("Could not open epmdb.tdb: %s\n", strerror(errno));
    1050           0 :                 return map_nt_error_from_unix(errno);
    1051             :         }
    1052          30 :         TALLOC_FREE(epmdb_path);
    1053             : 
    1054          30 :         status = epmapper__op_init_server(dce_ctx, ep_server);
    1055          30 :         return status;
    1056             : }
    1057             : 
    1058             : #define DCESRV_INTERFACE_EPMAPPER_INIT_SERVER epmapper_init_server
    1059             : 
    1060             : /* include the generated boilerplate */
    1061             : #include "librpc/gen_ndr/ndr_epmapper_scompat.c"
    1062             : 
    1063             : /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */

Generated by: LCOV version 1.14