libsmb: provide authinfo domain for DFS referral auth
[Samba.git] / source3 / librpc / rpc / dcerpc_ep.c
blobbb080c5fddf237be696f220b28bbfdf043ad4537
1 /*
2 * Endpoint Mapper Functions
3 * DCERPC local endpoint mapper client routines
4 * Copyright (c) 2010-2011 Andreas Schneider.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "librpc/rpc/dcerpc.h"
22 #include "librpc/rpc/dcerpc_ep.h"
23 #include "../librpc/gen_ndr/ndr_epmapper_c.h"
24 #include "rpc_client/cli_pipe.h"
25 #include "auth.h"
26 #include "rpc_server/rpc_ncacn_np.h"
27 #include "../lib/tsocket/tsocket.h"
28 #include "rpc_server/rpc_config.h"
30 #define EPM_MAX_ANNOTATION_SIZE 64
32 static bool binding_vector_realloc(struct dcerpc_binding_vector *bvec)
34 if (bvec->count >= bvec->allocated) {
35 struct dcerpc_binding *tmp;
37 tmp = talloc_realloc(bvec,
38 bvec->bindings,
39 struct dcerpc_binding,
40 bvec->allocated * 2);
41 if (tmp == NULL) {
42 return false;
44 bvec->bindings = tmp;
45 bvec->allocated = bvec->allocated * 2;
48 return true;
51 NTSTATUS dcerpc_binding_vector_new(TALLOC_CTX *mem_ctx,
52 struct dcerpc_binding_vector **pbvec)
54 struct dcerpc_binding_vector *bvec;
55 NTSTATUS status;
56 TALLOC_CTX *tmp_ctx;
58 tmp_ctx = talloc_stackframe();
59 if (tmp_ctx == NULL) {
60 return NT_STATUS_NO_MEMORY;
63 bvec = talloc_zero(tmp_ctx, struct dcerpc_binding_vector);
64 if (bvec == NULL) {
65 status = NT_STATUS_NO_MEMORY;
66 goto done;
69 bvec->bindings = talloc_zero_array(bvec,
70 struct dcerpc_binding,
71 4);
72 if (bvec->bindings == NULL) {
73 status = NT_STATUS_NO_MEMORY;
74 goto done;
77 bvec->allocated = 4;
78 bvec->count = 0;
80 *pbvec = talloc_move(mem_ctx, &bvec);
82 status = NT_STATUS_OK;
83 done:
84 talloc_free(tmp_ctx);
86 return status;
89 NTSTATUS dcerpc_binding_vector_add_np_default(const struct ndr_interface_table *iface,
90 struct dcerpc_binding_vector *bvec)
92 uint32_t ep_count = iface->endpoints->count;
93 uint32_t i;
94 NTSTATUS status;
95 bool ok;
97 for (i = 0; i < ep_count; i++) {
98 struct dcerpc_binding *b;
100 b = talloc_zero(bvec->bindings, struct dcerpc_binding);
101 if (b == NULL) {
102 return NT_STATUS_NO_MEMORY;
105 status = dcerpc_parse_binding(b, iface->endpoints->names[i], &b);
106 if (!NT_STATUS_IS_OK(status)) {
107 return NT_STATUS_UNSUCCESSFUL;
110 /* Only add the named pipes defined in the iface endpoints */
111 if (b->transport != NCACN_NP) {
112 talloc_free(b);
113 continue;
116 b->object = iface->syntax_id;
118 b->host = talloc_asprintf(b, "\\\\%s", lp_netbios_name());
119 if (b->host == NULL) {
120 talloc_free(b);
121 return NT_STATUS_NO_MEMORY;
124 ok = binding_vector_realloc(bvec);
125 if (!ok) {
126 talloc_free(b);
127 return NT_STATUS_NO_MEMORY;
130 bvec->bindings[bvec->count] = *b;
131 bvec->count++;
134 return NT_STATUS_OK;
137 NTSTATUS dcerpc_binding_vector_add_port(const struct ndr_interface_table *iface,
138 struct dcerpc_binding_vector *bvec,
139 const char *host,
140 uint16_t port)
142 uint32_t ep_count = iface->endpoints->count;
143 uint32_t i;
144 NTSTATUS status;
145 bool ok;
147 for (i = 0; i < ep_count; i++) {
148 struct dcerpc_binding *b;
150 b = talloc_zero(bvec->bindings, struct dcerpc_binding);
151 if (b == NULL) {
152 return NT_STATUS_NO_MEMORY;
155 status = dcerpc_parse_binding(b, iface->endpoints->names[i], &b);
156 if (!NT_STATUS_IS_OK(status)) {
157 return NT_STATUS_UNSUCCESSFUL;
160 if (b->transport != NCACN_IP_TCP) {
161 talloc_free(b);
162 continue;
165 b->object = iface->syntax_id;
167 b->host = talloc_strdup(b, host);
168 if (b->host == NULL) {
169 talloc_free(b);
170 return NT_STATUS_NO_MEMORY;
173 b->endpoint = talloc_asprintf(b, "%u", port);
174 if (b->endpoint == NULL) {
175 talloc_free(b);
176 return NT_STATUS_NO_MEMORY;
179 ok = binding_vector_realloc(bvec);
180 if (!ok) {
181 talloc_free(b);
182 return NT_STATUS_NO_MEMORY;
185 bvec->bindings[bvec->count] = *b;
186 bvec->count++;
188 break;
191 return NT_STATUS_OK;
194 NTSTATUS dcerpc_binding_vector_add_unix(const struct ndr_interface_table *iface,
195 struct dcerpc_binding_vector *bvec,
196 const char *name)
198 uint32_t ep_count = iface->endpoints->count;
199 uint32_t i;
200 NTSTATUS status;
201 bool ok;
203 for (i = 0; i < ep_count; i++) {
204 struct dcerpc_binding *b;
206 b = talloc_zero(bvec->bindings, struct dcerpc_binding);
207 if (b == NULL) {
208 return NT_STATUS_NO_MEMORY;
211 status = dcerpc_parse_binding(b, iface->endpoints->names[i], &b);
212 if (!NT_STATUS_IS_OK(status)) {
213 return NT_STATUS_UNSUCCESSFUL;
216 if (b->transport != NCALRPC) {
217 talloc_free(b);
218 continue;
221 b->object = iface->syntax_id;
223 b->endpoint = talloc_asprintf(b,
224 "%s/%s",
225 lp_ncalrpc_dir(),
226 name);
227 if (b->endpoint == NULL) {
228 talloc_free(b);
229 return NT_STATUS_NO_MEMORY;
232 ok = binding_vector_realloc(bvec);
233 if (!ok) {
234 talloc_free(b);
235 return NT_STATUS_NO_MEMORY;
238 bvec->bindings[bvec->count] = *b;
239 bvec->count++;
241 break;
244 return NT_STATUS_OK;
247 NTSTATUS dcerpc_binding_vector_replace_iface(const struct ndr_interface_table *iface,
248 struct dcerpc_binding_vector *v)
250 uint32_t i;
252 for (i = 0; i < v->count; i++) {
253 struct dcerpc_binding *b;
255 b = &(v->bindings[i]);
256 b->object = iface->syntax_id;
259 return NT_STATUS_OK;
262 struct dcerpc_binding_vector *dcerpc_binding_vector_dup(TALLOC_CTX *mem_ctx,
263 const struct dcerpc_binding_vector *bvec)
265 struct dcerpc_binding_vector *v;
266 uint32_t i;
268 v = talloc(mem_ctx, struct dcerpc_binding_vector);
269 if (v == NULL) {
270 return NULL;
273 v->bindings = talloc_array(v, struct dcerpc_binding, bvec->allocated);
274 if (v->bindings == NULL) {
275 talloc_free(v);
276 return NULL;
278 v->allocated = bvec->allocated;
280 for (i = 0; i < bvec->count; i++) {
281 struct dcerpc_binding *b;
283 b = dcerpc_binding_dup(v->bindings, &bvec->bindings[i]);
284 if (b == NULL) {
285 talloc_free(v);
286 return NULL;
288 v->bindings[i] = *b;
290 v->count = bvec->count;
292 return v;
295 static NTSTATUS ep_register(TALLOC_CTX *mem_ctx,
296 struct messaging_context *msg_ctx,
297 const struct ndr_interface_table *iface,
298 const struct dcerpc_binding_vector *bind_vec,
299 const struct GUID *object_guid,
300 const char *annotation,
301 uint32_t replace,
302 uint32_t unregister,
303 struct dcerpc_binding_handle **pbh)
305 struct rpc_pipe_client *cli = NULL;
306 struct dcerpc_binding_handle *h;
307 struct pipe_auth_data *auth;
308 const char *ncalrpc_sock;
309 enum rpc_service_mode_e epmd_mode;
310 struct epm_entry_t *entries;
311 uint32_t num_ents, i;
312 TALLOC_CTX *tmp_ctx;
313 uint32_t result = EPMAPPER_STATUS_OK;
314 NTSTATUS status;
316 if (iface == NULL) {
317 return NT_STATUS_INVALID_PARAMETER;
320 if (bind_vec == NULL || bind_vec->count == 0) {
321 return NT_STATUS_INVALID_PARAMETER;
324 tmp_ctx = talloc_stackframe();
325 if (tmp_ctx == NULL) {
326 return NT_STATUS_NO_MEMORY;
329 epmd_mode = rpc_epmapper_mode();
331 if (epmd_mode == RPC_SERVICE_MODE_EMBEDDED) {
332 struct tsocket_address *local;
333 int rc;
335 rc = tsocket_address_inet_from_strings(tmp_ctx,
336 "ip",
337 "127.0.0.1",
339 &local);
340 if (rc < 0) {
341 return NT_STATUS_NO_MEMORY;
344 status = rpcint_binding_handle(tmp_ctx,
345 &ndr_table_epmapper,
346 local,
347 get_session_info_system(),
348 msg_ctx,
349 &h);
350 if (!NT_STATUS_IS_OK(status)) {
351 DEBUG(1, ("dcerpc_ep_register: Could not connect to "
352 "epmapper (%s)", nt_errstr(status)));
353 goto done;
355 } else if (epmd_mode == RPC_SERVICE_MODE_EXTERNAL) {
356 /* Connect to the endpoint mapper locally */
357 ncalrpc_sock = talloc_asprintf(tmp_ctx,
358 "%s/%s",
359 lp_ncalrpc_dir(),
360 "EPMAPPER");
361 if (ncalrpc_sock == NULL) {
362 status = NT_STATUS_NO_MEMORY;
363 goto done;
366 status = rpc_pipe_open_ncalrpc(tmp_ctx,
367 ncalrpc_sock,
368 &ndr_table_epmapper.syntax_id,
369 &cli);
370 if (!NT_STATUS_IS_OK(status)) {
371 goto done;
374 status = rpccli_ncalrpc_bind_data(cli, &auth);
375 if (!NT_STATUS_IS_OK(status)) {
376 DEBUG(0, ("Failed to initialize anonymous bind.\n"));
377 goto done;
380 status = rpc_pipe_bind(cli, auth);
381 if (!NT_STATUS_IS_OK(status)) {
382 DEBUG(2, ("Failed to bind ncalrpc socket.\n"));
383 goto done;
386 h = cli->binding_handle;
387 } else {
388 status = NT_STATUS_INVALID_PARAMETER;
389 goto done;
392 num_ents = bind_vec->count;
393 entries = talloc_array(tmp_ctx, struct epm_entry_t, num_ents);
395 for (i = 0; i < num_ents; i++) {
396 struct dcerpc_binding *map_binding = &bind_vec->bindings[i];
397 struct epm_twr_t *map_tower;
399 map_tower = talloc_zero(entries, struct epm_twr_t);
400 if (map_tower == NULL) {
401 status = NT_STATUS_NO_MEMORY;
402 goto done;
405 status = dcerpc_binding_build_tower(entries,
406 map_binding,
407 &map_tower->tower);
408 if (!NT_STATUS_IS_OK(status)) {
409 goto done;
412 entries[i].tower = map_tower;
413 if (annotation == NULL) {
414 entries[i].annotation = talloc_strdup(entries, "");
415 } else {
416 entries[i].annotation = talloc_strndup(entries,
417 annotation,
418 EPM_MAX_ANNOTATION_SIZE);
420 if (entries[i].annotation == NULL) {
421 status = NT_STATUS_NO_MEMORY;
422 goto done;
425 if (object_guid != NULL) {
426 entries[i].object = *object_guid;
427 } else {
428 entries[i].object = map_binding->object.uuid;
432 if (unregister) {
433 status = dcerpc_epm_Delete(h,
434 tmp_ctx,
435 num_ents,
436 entries,
437 &result);
438 } else {
439 status = dcerpc_epm_Insert(h,
440 tmp_ctx,
441 num_ents,
442 entries,
443 replace,
444 &result);
446 if (!NT_STATUS_IS_OK(status)) {
447 DEBUG(0, ("dcerpc_ep_register: Could not insert tower (%s)\n",
448 nt_errstr(status)));
449 goto done;
451 if (result != EPMAPPER_STATUS_OK) {
452 DEBUG(0, ("dcerpc_ep_register: Could not insert tower (0x%.8x)\n",
453 result));
454 status = NT_STATUS_UNSUCCESSFUL;
455 goto done;
458 if (pbh != NULL) {
459 *pbh = talloc_move(mem_ctx, &h);
460 talloc_steal(*pbh, cli);
463 done:
464 talloc_free(tmp_ctx);
466 return status;
469 NTSTATUS dcerpc_ep_register(TALLOC_CTX *mem_ctx,
470 struct messaging_context *msg_ctx,
471 const struct ndr_interface_table *iface,
472 const struct dcerpc_binding_vector *bind_vec,
473 const struct GUID *object_guid,
474 const char *annotation,
475 struct dcerpc_binding_handle **ph)
477 return ep_register(mem_ctx,
478 msg_ctx,
479 iface,
480 bind_vec,
481 object_guid,
482 annotation,
485 ph);
488 NTSTATUS dcerpc_ep_register_noreplace(TALLOC_CTX *mem_ctx,
489 struct messaging_context *msg_ctx,
490 const struct ndr_interface_table *iface,
491 const struct dcerpc_binding_vector *bind_vec,
492 const struct GUID *object_guid,
493 const char *annotation,
494 struct dcerpc_binding_handle **ph)
496 return ep_register(mem_ctx,
497 msg_ctx,
498 iface,
499 bind_vec,
500 object_guid,
501 annotation,
504 ph);
507 NTSTATUS dcerpc_ep_unregister(struct messaging_context *msg_ctx,
508 const struct ndr_interface_table *iface,
509 const struct dcerpc_binding_vector *bind_vec,
510 const struct GUID *object_guid)
512 return ep_register(NULL,
513 msg_ctx,
514 iface,
515 bind_vec,
516 object_guid,
517 NULL,
520 NULL);
523 /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */