diff options
author | Andreas Schneider <asn@samba.org> | 2010-12-21 19:38:40 +0100 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2011-02-02 12:44:20 +0100 |
commit | c451a454b3a87301ed17b3e7a06de37e6cfcb41e (patch) | |
tree | 22169031f95f5ac0e74f77c7581541241d69e362 | |
parent | 1d33f5c6d641f2c4c18eae47f7d9ef464396f471 (diff) | |
download | samba-c451a454b3a87301ed17b3e7a06de37e6cfcb41e.tar.gz samba-c451a454b3a87301ed17b3e7a06de37e6cfcb41e.tar.bz2 samba-c451a454b3a87301ed17b3e7a06de37e6cfcb41e.zip |
s3-epmapper: Improved the epm_Map function.
-rw-r--r-- | source3/rpc_server/srv_epmapper.c | 254 |
1 files changed, 210 insertions, 44 deletions
diff --git a/source3/rpc_server/srv_epmapper.c b/source3/rpc_server/srv_epmapper.c index 07097e4bad..028cadfb14 100644 --- a/source3/rpc_server/srv_epmapper.c +++ b/source3/rpc_server/srv_epmapper.c @@ -57,6 +57,11 @@ struct dcesrv_endpoint { struct dcesrv_iface_list *iface_list; }; +struct rpc_eps { + struct dcesrv_ep_iface *e; + uint32_t count; +}; + struct dcesrv_endpoint *endpoint_table; /* @@ -397,6 +402,7 @@ error_status_t _epm_Lookup(struct pipes_struct *p, struct epm_Lookup *r) { struct policy_handle *entry_handle; + struct rpc_eps *eps; TALLOC_CTX *tmp_ctx; error_status_t rc; uint32_t count = 0; @@ -405,11 +411,6 @@ error_status_t _epm_Lookup(struct pipes_struct *p, bool match = false; bool ok; - struct rpc_eps { - struct dcesrv_ep_iface *e; - uint32_t count; - } *eps; - *r->out.num_ents = 0; r->out.entries = NULL; @@ -724,74 +725,239 @@ done: error_status_t _epm_Map(struct pipes_struct *p, struct epm_Map *r) { + struct policy_handle *entry_handle; enum dcerpc_transport_t transport; - struct ndr_syntax_id ndr_syntax; - struct dcesrv_ep_iface *eps; + struct ndr_syntax_id ifid; struct epm_floor *floors; - uint32_t count, i; - - count = build_ep_list(p->mem_ctx, endpoint_table, NULL, &eps); + struct rpc_eps *eps; + TALLOC_CTX *tmp_ctx; + error_status_t rc; + uint32_t count = 0; + uint32_t num_towers = 0; + uint32_t num_floors = 0; + uint32_t i; + bool ok; - ZERO_STRUCT(*r->out.entry_handle); - r->out.num_towers = talloc(p->mem_ctx, uint32_t); - if (r->out.num_towers == NULL) { - return EPMAPPER_STATUS_NO_MEMORY; - } + *r->out.num_towers = 0; + r->out.towers = NULL; - *r->out.num_towers = 1; - r->out.towers = talloc(p->mem_ctx, struct epm_twr_p_t); - if (r->out.towers == NULL) { - return EPMAPPER_STATUS_NO_MEMORY; + if (r->in.map_tower == NULL || r->in.max_towers == 0 || + r->in.map_tower->tower.num_floors < 3) { + return EPMAPPER_STATUS_NO_MORE_ENTRIES; } - r->out.towers->twr = talloc(p->mem_ctx, struct epm_twr_t); - if (r->out.towers->twr == NULL) { + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { return EPMAPPER_STATUS_NO_MEMORY; } - if (r->in.map_tower == NULL || r->in.max_towers == 0 || - r->in.map_tower->tower.num_floors < 3) { - goto failed; - } - + ZERO_STRUCTP(r->out.entry_handle); + + DEBUG(3, ("_epm_Map: Trying to map max. %u towers.\n", + r->in.max_towers)); + + /* + * A tower has normally up to 6 floors + * + * +-----------------------------------------------------------------+ + * | Floor 1 | Provides the RPC interface identifier. (e.g. UUID for | + * | | netlogon) | + * +---------+-------------------------------------------------------+ + * | Floor 2 | Transfer syntax (NDR endcoded) | + * +---------+-------------------------------------------------------+ + * | Floor 3 | RPC protocol identifier (ncacn_tcp_ip, ncacn_np, ...) | + * +---------+-------------------------------------------------------+ + * | Floor 4 | Port address (e.g. TCP Port: 49156) | + * +---------+-------------------------------------------------------+ + * | Floor 5 | Transport (e.g. IP:192.168.51.10) | + * +---------+-------------------------------------------------------+ + * | Floor 6 | Routing | + * +---------+-------------------------------------------------------+ + */ + num_floors = r->in.map_tower->tower.num_floors; floors = r->in.map_tower->tower.floors; - dcerpc_floor_get_lhs_data(&r->in.map_tower->tower.floors[1], &ndr_syntax); + /* We accept NDR as the transfer syntax */ + dcerpc_floor_get_lhs_data(&floors[1], &ifid); if (floors[1].lhs.protocol != EPM_PROTOCOL_UUID || - !GUID_equal(&ndr_syntax.uuid, &ndr_transfer_syntax.uuid) || - ndr_syntax.if_version != ndr_transfer_syntax.if_version) { - goto failed; + !GUID_equal(&ifid.uuid, &ndr_transfer_syntax.uuid) || + ifid.if_version != ndr_transfer_syntax.if_version) { + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; } + /* We only talk to sane transports */ transport = dcerpc_transport_by_tower(&r->in.map_tower->tower); - if (transport == -1) { - DEBUG(2, ("epm_Insert: Client requested unknown transport with levels: ")); + if (transport == NCA_UNKNOWN) { + DEBUG(2, ("epm_Map: Client requested unknown transport with" + "levels: ")); for (i = 2; i < r->in.map_tower->tower.num_floors; i++) { DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol)); } DEBUG(2, ("\n")); - goto failed; + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + if (r->in.entry_handle == NULL || + policy_handle_empty(r->in.entry_handle)) { + struct GUID *obj; + + DEBUG(5, ("_epm_Map: No entry_handle found, creating it.\n")); + + eps = talloc_zero(tmp_ctx, struct rpc_eps); + if (eps == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + /* + * *** ATTENTION *** + * CDE 1.1 states: + * + * ept_map() + * Apply some algorithm (using the fields in the map_tower) + * to an endpoint map to produce a list of protocol towers. + * + * The following code is the mysterious "some algorithm"! + */ + + /* Filter by object id if one was given. */ + if (r->in.object == NULL || GUID_all_zero(r->in.object)) { + obj = NULL; + } else { + obj = r->in.object; + } + + eps->count = build_ep_list(eps, + endpoint_table, + obj, + &eps->e); + if (eps->count == 0) { + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + /* Filter out endpoints which match the interface. */ + { + struct rpc_eps *teps; + uint32_t total = 0; + + teps = talloc_zero(tmp_ctx, struct rpc_eps); + if (teps == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + for (i = 0; i < eps->count; i++) { + if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data, + &eps->e[i].ep.floors[0].lhs.lhs_data) != 0 || + transport != dcerpc_transport_by_tower(&eps->e[i].ep)) { + continue; + } + + teps->e = talloc_realloc(tmp_ctx, + teps->e, + struct dcesrv_ep_iface, + total + 1); + if (teps->e == NULL) { + return 0; + } + + teps->e[total].ep.floors = talloc_move(teps, &eps->e[i].ep.floors); + teps->e[total].ep.num_floors = eps->e[i].ep.num_floors; + teps->e[total].name = talloc_move(teps, &eps->e[i].name); + teps->e[total].syntax_id = eps->e[i].syntax_id; + + total++; + } + + teps->count = total; + talloc_free(eps); + eps = teps; + } + /* end of "some algorithm" */ + + ok = create_policy_hnd(p, r->out.entry_handle, eps); + if (!ok) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + + ok = find_policy_by_hnd(p, r->out.entry_handle, (void **)(void*) &eps); + if (!ok) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + entry_handle = r->out.entry_handle; + } else { + DEBUG(5, ("_epm_Map: Trying to find entry_handle.\n")); + + ok = find_policy_by_hnd(p, r->in.entry_handle, (void **)(void*) &eps); + if (!ok) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; + } + entry_handle = r->in.entry_handle; + } + + if (eps == NULL || eps->e == NULL) { + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + /* return the next N elements */ + count = r->in.max_towers; + if (count > eps->count) { + count = eps->count; + } + + if (count == 0) { + close_policy_hnd(p, entry_handle); + ZERO_STRUCTP(r->out.entry_handle); + + rc = EPMAPPER_STATUS_NO_MORE_ENTRIES; + goto done; + } + + r->out.towers = talloc_array(p->mem_ctx, struct epm_twr_p_t, count); + if (r->out.towers == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; } for (i = 0; i < count; i++) { - if (data_blob_cmp(&r->in.map_tower->tower.floors[0].lhs.lhs_data, - &eps[i].ep.floors[0].lhs.lhs_data) != 0 || - transport != dcerpc_transport_by_tower(&eps[i].ep)) { - continue; + DEBUG(5, ("_epm_Map: Map tower for '%s'\n", + eps->e[i].name)); + + r->out.towers[num_towers].twr = talloc(r->out.towers, + struct epm_twr_t); + if (r->out.towers[num_towers].twr == NULL) { + rc = EPMAPPER_STATUS_NO_MEMORY; + goto done; } + r->out.towers[num_towers].twr->tower.floors = talloc_move(r->out.towers[num_towers].twr, &eps->e[i].ep.floors); + r->out.towers[num_towers].twr->tower.num_floors = eps->e[i].ep.num_floors; + r->out.towers[num_towers].twr->tower_length = 0; - r->out.towers->twr->tower = eps[i].ep; - r->out.towers->twr->tower_length = 0; + num_towers++; + } - return EPMAPPER_STATUS_OK; + *r->out.num_towers = num_towers; + + eps->count -= count; + eps->e += count; + if (eps->count == 0) { + close_policy_hnd(p, entry_handle); + ZERO_STRUCTP(r->out.entry_handle); } -failed: - *r->out.num_towers = 0; - r->out.towers->twr = NULL; + rc = EPMAPPER_STATUS_OK; +done: + talloc_free(tmp_ctx); - return EPMAPPER_STATUS_NO_MORE_ENTRIES; + return rc; } /* |