1/* 2 Unix SMB/CIFS implementation. 3 Main DCOM functionality 4 Copyright (C) 2004 Jelmer Vernooij <jelmer@samba.org> 5 Copyright (C) 2006 Andrzej Hajda <andrzej.hajda@wp.pl> 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*/ 21 22#include "includes.h" 23#include "system/filesys.h" 24#include "librpc/gen_ndr/epmapper.h" 25#include "librpc/gen_ndr/ndr_remact_c.h" 26#include "librpc/gen_ndr/com_dcom.h" 27#include "librpc/gen_ndr/dcom.h" 28#include "librpc/rpc/dcerpc.h" 29#include "lib/com/dcom/dcom.h" 30#include "librpc/ndr/ndr_table.h" 31#include "../lib/util/dlinklist.h" 32#include "auth/credentials/credentials.h" 33#include "libcli/composite/composite.h" 34 35#define DCOM_NEGOTIATED_PROTOCOLS { EPM_PROTOCOL_TCP, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NCALRPC } 36 37static NTSTATUS dcerpc_binding_from_STRINGBINDING(TALLOC_CTX *mem_ctx, struct dcerpc_binding **b_out, struct STRINGBINDING *bd) 38{ 39 char *host, *endpoint; 40 struct dcerpc_binding *b; 41 42 b = talloc_zero(mem_ctx, struct dcerpc_binding); 43 if (!b) { 44 return NT_STATUS_NO_MEMORY; 45 } 46 47 b->transport = dcerpc_transport_by_endpoint_protocol(bd->wTowerId); 48 49 if (b->transport == -1) { 50 DEBUG(1, ("Can't find transport match endpoint protocol %d\n", bd->wTowerId)); 51 talloc_free(b); 52 return NT_STATUS_NOT_SUPPORTED; 53 } 54 55 host = talloc_strdup(b, bd->NetworkAddr); 56 endpoint = strchr(host, '['); 57 58 if (endpoint) { 59 *endpoint = '\0'; 60 endpoint++; 61 62 endpoint[strlen(endpoint)-1] = '\0'; 63 } 64 65 b->host = host; 66 b->endpoint = talloc_strdup(b, endpoint); 67 68 *b_out = b; 69 return NT_STATUS_OK; 70} 71 72struct cli_credentials *dcom_get_server_credentials(struct com_context *ctx, const char *server) 73{ 74 struct dcom_server_credentials *c; 75 struct cli_credentials *d; 76 77 d = NULL; 78 for (c = ctx->dcom->credentials; c; c = c->next) { 79 if (c->server == NULL) { 80 d = c->credentials; 81 continue; 82 } 83 if (server && !strcmp(c->server, server)) return c->credentials; 84 } 85 return d; 86} 87 88/** 89 * Register credentials for a specific server. 90 * 91 * @param ctx COM context 92 * @param server Name of server, can be NULL 93 * @param credentials Credentials object 94 */ 95void dcom_add_server_credentials(struct com_context *ctx, const char *server, 96 struct cli_credentials *credentials) 97{ 98 struct dcom_server_credentials *c; 99 100 /* FIXME: Don't use talloc_find_parent_bytype */ 101 for (c = ctx->dcom->credentials; c; c = c->next) { 102 if ((server == NULL && c->server == NULL) || 103 (server != NULL && c->server != NULL && 104 !strcmp(c->server, server))) { 105 if (c->credentials && c->credentials != credentials) { 106 talloc_unlink(c, c->credentials); 107 c->credentials = credentials; 108 if (talloc_find_parent_bytype(c->credentials, struct dcom_server_credentials)) 109 (void)talloc_reference(c, c->credentials); 110 else 111 talloc_steal(c, c->credentials); 112 } 113 114 return; 115 } 116 } 117 118 c = talloc(ctx->event_ctx, struct dcom_server_credentials); 119 c->server = talloc_strdup(c, server); 120 c->credentials = credentials; 121 if (talloc_find_parent_bytype(c->credentials, struct dcom_server_credentials)) 122 (void)talloc_reference(c, c->credentials); 123 else 124 talloc_steal(c, c->credentials); 125 126 DLIST_ADD(ctx->dcom->credentials, c); 127} 128 129void dcom_update_credentials_for_aliases(struct com_context *ctx, 130 const char *server, 131 struct DUALSTRINGARRAY *pds) 132{ 133 struct cli_credentials *cc; 134 struct dcerpc_binding *b; 135 uint32_t i; 136 NTSTATUS status; 137 138 cc = dcom_get_server_credentials(ctx, server); 139 for (i = 0; pds->stringbindings[i]; ++i) { 140 if (pds->stringbindings[i]->wTowerId != EPM_PROTOCOL_TCP) 141 continue; 142 status = dcerpc_binding_from_STRINGBINDING(ctx, &b, pds->stringbindings[i]); 143 if (!NT_STATUS_IS_OK(status)) 144 continue; 145 dcom_add_server_credentials(ctx, b->host, cc); 146 talloc_free(b); 147 } 148} 149 150struct dcom_client_context *dcom_client_init(struct com_context *ctx, struct cli_credentials *credentials) 151{ 152 ctx->dcom = talloc_zero(ctx, struct dcom_client_context); 153 if (!credentials) { 154 credentials = cli_credentials_init(ctx); 155 cli_credentials_set_conf(credentials, ctx->lp_ctx); 156 cli_credentials_parse_string(credentials, "%", CRED_SPECIFIED); 157 } 158 dcom_add_server_credentials(ctx, NULL, credentials); 159 return ctx->dcom; 160} 161 162static NTSTATUS dcom_connect_host(struct com_context *ctx, 163 struct dcerpc_pipe **p, const char *server) 164{ 165 struct dcerpc_binding *bd; 166 const char * available_transports[] = { "ncacn_ip_tcp", "ncacn_np" }; 167 int i; 168 NTSTATUS status; 169 TALLOC_CTX *loc_ctx; 170 171 if (server == NULL) { 172 return dcerpc_pipe_connect(ctx->event_ctx, p, "ncalrpc", 173 &ndr_table_IRemoteActivation, 174 dcom_get_server_credentials(ctx, NULL), ctx->event_ctx, ctx->lp_ctx); 175 } 176 loc_ctx = talloc_new(ctx); 177 178 /* Allow server name to contain a binding string */ 179 if (strchr(server, ':') && 180 NT_STATUS_IS_OK(dcerpc_parse_binding(loc_ctx, server, &bd))) { 181 if (DEBUGLVL(11)) 182 bd->flags |= DCERPC_DEBUG_PRINT_BOTH; 183 status = dcerpc_pipe_connect_b(ctx->event_ctx, p, bd, 184 &ndr_table_IRemoteActivation, 185 dcom_get_server_credentials(ctx, bd->host), ctx->event_ctx, ctx->lp_ctx); 186 goto end; 187 } 188 189 for (i = 0; i < ARRAY_SIZE(available_transports); i++) 190 { 191 char *binding = talloc_asprintf(loc_ctx, "%s:%s", available_transports[i], server); 192 if (!binding) { 193 status = NT_STATUS_NO_MEMORY; 194 goto end; 195 } 196 status = dcerpc_pipe_connect(ctx->event_ctx, p, binding, 197 &ndr_table_IRemoteActivation, 198 dcom_get_server_credentials(ctx, server), 199 ctx->event_ctx, ctx->lp_ctx); 200 201 if (NT_STATUS_IS_OK(status)) { 202 if (DEBUGLVL(11)) 203 (*p)->conn->flags |= DCERPC_DEBUG_PRINT_BOTH; 204 goto end; 205 } else { 206 DEBUG(1,(__location__": dcom_connect_host : %s\n", get_friendly_nt_error_msg(status))); 207 } 208 } 209 210end: 211 talloc_free(loc_ctx); 212 return status; 213} 214 215struct dcom_object_exporter *object_exporter_by_oxid(struct com_context *ctx, 216 uint64_t oxid) 217{ 218 struct dcom_object_exporter *ox; 219 for (ox = ctx->dcom->object_exporters; ox; ox = ox->next) { 220 if (ox->oxid == oxid) { 221 return ox; 222 } 223 } 224 225 return NULL; 226} 227 228struct dcom_object_exporter *object_exporter_update_oxid(struct com_context *ctx, uint64_t oxid, struct DUALSTRINGARRAY *bindings) 229{ 230 struct dcom_object_exporter *ox; 231 ox = object_exporter_by_oxid(ctx, oxid); 232 if (!ox) { 233 ox = talloc_zero(ctx, struct dcom_object_exporter); 234 DLIST_ADD(ctx->dcom->object_exporters, ox); 235 ox->oxid = oxid; 236 } else { 237 talloc_free(ox->bindings); 238 } 239 ox->bindings = bindings; 240 talloc_steal(ox, bindings); 241 return ox; 242} 243 244struct dcom_object_exporter *object_exporter_by_ip(struct com_context *ctx, struct IUnknown *ip) 245{ 246 return object_exporter_by_oxid(ctx, ip->obj.u_objref.u_standard.std.oxid); 247} 248 249WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct IUnknown ***ip, WERROR *results) 250{ 251 uint16_t protseq[] = DCOM_NEGOTIATED_PROTOCOLS; 252 struct dcerpc_pipe *p; 253 struct dcom_object_exporter *m; 254 NTSTATUS status; 255 struct RemoteActivation r; 256 struct DUALSTRINGARRAY *pds; 257 int i; 258 WERROR hr; 259 uint64_t oxid; 260 struct GUID ipidRemUnknown; 261 struct IUnknown *ru_template; 262 struct ORPCTHAT that; 263 uint32_t AuthnHint; 264 struct COMVERSION ServerVersion; 265 struct MInterfacePointer **ifaces; 266 TALLOC_CTX *loc_ctx; 267 268 status = dcom_connect_host(ctx, &p, server); 269 if (NT_STATUS_IS_ERR(status)) { 270 DEBUG(1, ("Unable to connect to %s - %s\n", server, get_friendly_nt_error_msg(status))); 271 return ntstatus_to_werror(status); 272 } 273 loc_ctx = talloc_new(ctx); 274 275 ifaces = talloc_array(loc_ctx, struct MInterfacePointer *, num_ifaces); 276 277 ZERO_STRUCT(r.in); 278 r.in.this.version.MajorVersion = COM_MAJOR_VERSION; 279 r.in.this.version.MinorVersion = COM_MINOR_VERSION; 280 r.in.this.cid = GUID_random(); 281 r.in.Clsid = *clsid; 282 r.in.ClientImpLevel = RPC_C_IMP_LEVEL_IDENTIFY; 283 r.in.num_protseqs = ARRAY_SIZE(protseq); 284 r.in.protseq = protseq; 285 r.in.Interfaces = num_ifaces; 286 r.in.pIIDs = iid; 287 r.out.that = &that; 288 r.out.pOxid = &oxid; 289 r.out.pdsaOxidBindings = &pds; 290 r.out.ipidRemUnknown = &ipidRemUnknown; 291 r.out.AuthnHint = &AuthnHint; 292 r.out.ServerVersion = &ServerVersion; 293 r.out.hr = &hr; 294 r.out.ifaces = ifaces; 295 r.out.results = results; 296 297 status = dcerpc_RemoteActivation(p, loc_ctx, &r); 298 talloc_free(p); 299 300 if(NT_STATUS_IS_ERR(status)) { 301 DEBUG(1, ("Error while running RemoteActivation %s\n", nt_errstr(status))); 302 hr = ntstatus_to_werror(status); 303 goto end; 304 } 305 306 if(!W_ERROR_IS_OK(r.out.result)) { 307 hr = r.out.result; 308 goto end; 309 } 310 311 if(!W_ERROR_IS_OK(hr)) { 312 goto end; 313 } 314 315 m = object_exporter_update_oxid(ctx, oxid, pds); 316 317 ru_template = NULL; 318 *ip = talloc_array(ctx, struct IUnknown *, num_ifaces); 319 for (i = 0; i < num_ifaces; i++) { 320 (*ip)[i] = NULL; 321 if (W_ERROR_IS_OK(results[i])) { 322 status = dcom_IUnknown_from_OBJREF(ctx, &(*ip)[i], &r.out.ifaces[i]->obj); 323 if (!NT_STATUS_IS_OK(status)) { 324 results[i] = ntstatus_to_werror(status); 325 } else if (!ru_template) 326 ru_template = (*ip)[i]; 327 } 328 } 329 330 /* TODO:avg check when exactly oxid should be updated,its lifetime etc */ 331 if (m->rem_unknown && memcmp(&m->rem_unknown->obj.u_objref.u_standard.std.ipid, &ipidRemUnknown, sizeof(ipidRemUnknown))) { 332 talloc_free(m->rem_unknown); 333 m->rem_unknown = NULL; 334 } 335 if (!m->rem_unknown) { 336 if (!ru_template) { 337 DEBUG(1,("dcom_create_object: Cannot Create IRemUnknown - template interface not available\n")); 338 hr = WERR_GENERAL_FAILURE; 339 } 340 m->rem_unknown = talloc_zero(m, struct IRemUnknown); 341 memcpy(m->rem_unknown, ru_template, sizeof(struct IUnknown)); 342 GUID_from_string(COM_IREMUNKNOWN_UUID, &m->rem_unknown->obj.iid); 343 m->rem_unknown->obj.u_objref.u_standard.std.ipid = ipidRemUnknown; 344 m->rem_unknown->vtable = (struct IRemUnknown_vtable *)dcom_proxy_vtable_by_iid(&m->rem_unknown->obj.iid); 345 /* TODO:avg copy stringbindigs?? */ 346 } 347 348 dcom_update_credentials_for_aliases(ctx, server, pds); 349 { 350 char *c; 351 c = strchr(server, '['); 352 if (m->host) talloc_free(m->host); 353 m->host = c ? talloc_strndup(m, server, c - server) : talloc_strdup(m, server); 354 } 355 hr = WERR_OK; 356end: 357 talloc_free(loc_ctx); 358 return hr; 359} 360 361int find_similar_binding(struct STRINGBINDING **sb, const char *host) 362{ 363 int i, l; 364 l = strlen(host); 365 for (i = 0; sb[i]; ++i) { 366 if ((sb[i]->wTowerId == EPM_PROTOCOL_TCP) && !strncasecmp(host, sb[i]->NetworkAddr, l) && (sb[i]->NetworkAddr[l] == '[')) 367 break; 368 } 369 return i; 370} 371 372WERROR dcom_query_interface(struct IUnknown *d, uint32_t cRefs, uint16_t cIids, struct GUID *iids, struct IUnknown **ip, WERROR *results) 373{ 374 struct dcom_object_exporter *ox; 375 struct REMQIRESULT *rqir; 376 WERROR result; 377 NTSTATUS status; 378 int i; 379 TALLOC_CTX *loc_ctx; 380 struct IUnknown ru; 381 382 loc_ctx = talloc_new(d); 383 ox = object_exporter_by_ip(d->ctx, d); 384 385 result = IRemUnknown_RemQueryInterface(ox->rem_unknown, loc_ctx, &IUnknown_ipid(d), cRefs, cIids, iids, &rqir); 386 if (!W_ERROR_IS_OK(result)) { 387 DEBUG(1, ("dcom_query_interface failed: %08X\n", W_ERROR_V(result))); 388 talloc_free(loc_ctx); 389 return result; 390 } 391 ru = *(struct IUnknown *)ox->rem_unknown; 392 for (i = 0; i < cIids; ++i) { 393 ip[i] = NULL; 394 results[i] = rqir[i].hResult; 395 if (W_ERROR_IS_OK(results[i])) { 396 ru.obj.iid = iids[i]; 397 ru.obj.u_objref.u_standard.std = rqir[i].std; 398 status = dcom_IUnknown_from_OBJREF(d->ctx, &ip[i], &ru.obj); 399 if (!NT_STATUS_IS_OK(status)) { 400 results[i] = ntstatus_to_werror(status); 401 } 402 } 403 } 404 405 talloc_free(loc_ctx); 406 return WERR_OK; 407} 408 409int is_ip_binding(const char* s) 410{ 411 while (*s && (*s != '[')) { 412 if (((*s >= '0') && (*s <= '9')) || *s == '.') 413 ++s; 414 else 415 return 0; 416 } 417 return 1; 418} 419 420NTSTATUS dcom_get_pipe(struct IUnknown *iface, struct dcerpc_pipe **pp) 421{ 422 struct dcerpc_binding *binding; 423 struct GUID iid; 424 uint64_t oxid; 425 NTSTATUS status; 426 int i, j, isimilar; 427 struct dcerpc_pipe *p; 428 struct dcom_object_exporter *ox; 429 const struct ndr_interface_table *table; 430 431 ox = object_exporter_by_oxid(iface->ctx, iface->obj.u_objref.u_standard.std.oxid); 432 if (!ox) { 433 DEBUG(0, ("dcom_get_pipe: OXID not found\n")); 434 return NT_STATUS_NOT_SUPPORTED; 435 } 436 437 p = ox->pipe; 438 439 iid = iface->vtable->iid; 440 table = ndr_table_by_uuid(&iid); 441 if (table == NULL) { 442 char *guid_str; 443 guid_str = GUID_string(NULL, &iid); 444 DEBUG(0,(__location__": dcom_get_pipe - unrecognized interface{%s}\n", guid_str)); 445 talloc_free(guid_str); 446 return NT_STATUS_NOT_SUPPORTED; 447 } 448 449 if (p && p->last_fault_code) { 450 talloc_free(p); 451 ox->pipe = p = NULL; 452 } 453 454 if (p) { 455 if (!GUID_equal(&p->syntax.uuid, &iid)) { 456 ox->pipe->syntax.uuid = iid; 457 458 /* interface will always be present, so 459 * idl_iface_by_uuid can't return NULL */ 460 /* status = dcerpc_secondary_context(p, &p2, idl_iface_by_uuid(&iid)); */ 461 status = dcerpc_alter_context(p, p, &ndr_table_by_uuid(&iid)->syntax_id, &p->transfer_syntax); 462 } else 463 status = NT_STATUS_OK; 464 *pp = p; 465 return status; 466 } 467 468 status = NT_STATUS_NO_MORE_ENTRIES; 469 470 /* To avoid delays whe connecting nonroutable bindings we 1st check binding starting with hostname */ 471 /* FIX:low create concurrent connections to all bindings, fastest wins - Win2k and newer does this way???? */ 472 isimilar = find_similar_binding(ox->bindings->stringbindings, ox->host); 473 DEBUG(1, (__location__": dcom_get_pipe: host=%s, similar=%s\n", ox->host, ox->bindings->stringbindings[isimilar] ? ox->bindings->stringbindings[isimilar]->NetworkAddr : "None")); 474 j = isimilar - 1; 475 for (i = 0; ox->bindings->stringbindings[i]; ++i) { 476 if (!ox->bindings->stringbindings[++j]) j = 0; 477 /* FIXME:LOW Use also other transports if possible */ 478 if ((j != isimilar) && (ox->bindings->stringbindings[j]->wTowerId != EPM_PROTOCOL_TCP || !is_ip_binding(ox->bindings->stringbindings[j]->NetworkAddr))) { 479 DEBUG(9, ("dcom_get_pipe: Skipping stringbinding %24.24s\n", ox->bindings->stringbindings[j]->NetworkAddr)); 480 continue; 481 } 482 DEBUG(9, ("dcom_get_pipe: Trying stringbinding %s\n", ox->bindings->stringbindings[j]->NetworkAddr)); 483 status = dcerpc_binding_from_STRINGBINDING(iface->ctx, &binding, 484 ox->bindings->stringbindings[j]); 485 if (!NT_STATUS_IS_OK(status)) { 486 DEBUG(1, ("Error parsing string binding")); 487 } else { 488 /* FIXME:LOW Make flags more flexible */ 489 binding->flags |= DCERPC_AUTH_NTLM | DCERPC_SIGN; 490 if (DEBUGLVL(11)) 491 binding->flags |= DCERPC_DEBUG_PRINT_BOTH; 492 status = dcerpc_pipe_connect_b(iface->ctx->event_ctx, &p, binding, 493 ndr_table_by_uuid(&iid), 494 dcom_get_server_credentials(iface->ctx, binding->host), 495 iface->ctx->event_ctx, iface->ctx->lp_ctx); 496 talloc_unlink(iface->ctx, binding); 497 } 498 if (NT_STATUS_IS_OK(status)) break; 499 } 500 501 if (NT_STATUS_IS_ERR(status)) { 502 DEBUG(0, ("Unable to connect to remote host - %s\n", nt_errstr(status))); 503 return status; 504 } 505 506 DEBUG(2, ("Successfully connected to OXID %llx\n", (long long)oxid)); 507 508 ox->pipe = *pp = p; 509 510 return NT_STATUS_OK; 511} 512 513NTSTATUS dcom_OBJREF_from_IUnknown(TALLLOC_CTX *mem_ctx, struct OBJREF *o, struct IUnknown *p) 514{ 515 /* FIXME: Cache generated objref objects? */ 516 ZERO_STRUCTP(o); 517 518 if (!p) { 519 o->signature = OBJREF_SIGNATURE; 520 o->flags = OBJREF_NULL; 521 } else { 522 *o = p->obj; 523 switch(o->flags) { 524 case OBJREF_CUSTOM: { 525 marshal_fn marshal; 526 527 marshal = dcom_marshal_by_clsid(&o->u_objref.u_custom.clsid); 528 if (marshal) { 529 return marshal(mem_ctx, p, o); 530 } else { 531 return NT_STATUS_NOT_SUPPORTED; 532 } 533 } 534 } 535 } 536 537 return NT_STATUS_OK; 538} 539 540enum ndr_err_code dcom_IUnknown_from_OBJREF(struct com_context *ctx, struct IUnknown **_p, struct OBJREF *o) 541{ 542 struct IUnknown *p; 543 struct dcom_object_exporter *ox; 544 unmarshal_fn unmarshal; 545 546 switch(o->flags) { 547 case OBJREF_NULL: 548 *_p = NULL; 549 return NDR_ERR_SUCCESS; 550 551 case OBJREF_STANDARD: 552 p = talloc_zero(ctx, struct IUnknown); 553 p->ctx = ctx; 554 p->obj = *o; 555 p->vtable = dcom_proxy_vtable_by_iid(&o->iid); 556 557 if (!p->vtable) { 558 DEBUG(0, ("Unable to find proxy class for interface with IID %s\n", GUID_string(ctx, &o->iid))); 559 return NDR_ERR_INVALID_POINTER; 560 } 561 562 p->vtable->Release_send = dcom_release_send; 563 564 ox = object_exporter_by_oxid(ctx, o->u_objref.u_standard.std.oxid); 565 /* FIXME: Add object to list of objects to ping */ 566 *_p = p; 567 return NDR_ERR_SUCCESS; 568 569 case OBJREF_HANDLER: 570 p = talloc_zero(ctx, struct IUnknown); 571 p->ctx = ctx; 572 p->obj = *o; 573 ox = object_exporter_by_oxid(ctx, o->u_objref.u_handler.std.oxid ); 574 /* FIXME: Add object to list of objects to ping */ 575/*FIXME p->vtable = dcom_vtable_by_clsid(&o->u_objref.u_handler.clsid);*/ 576 /* FIXME: Do the custom unmarshaling call */ 577 578 *_p = p; 579 return NDR_ERR_BAD_SWITCH; 580 581 case OBJREF_CUSTOM: 582 p = talloc_zero(ctx, struct IUnknown); 583 p->ctx = ctx; 584 p->vtable = NULL; 585 p->obj = *o; 586 unmarshal = dcom_unmarshal_by_clsid(&o->u_objref.u_custom.clsid); 587 *_p = p; 588 if (unmarshal) { 589 return unmarshal(ctx, o, _p); 590 } else { 591 return NDR_ERR_BAD_SWITCH; 592 } 593 } 594 595 return NDR_ERR_BAD_SWITCH; 596} 597 598uint64_t dcom_get_current_oxid(void) 599{ 600 return getpid(); 601} 602 603/* FIXME:Fake async dcom_get_pipe_* */ 604struct composite_context *dcom_get_pipe_send(struct IUnknown *d, TALLOC_CTX *mem_ctx) 605{ 606 struct composite_context *c; 607 608 c = composite_create(0, d->ctx->event_ctx); 609 if (c == NULL) return NULL; 610 c->private_data = d; 611 /* composite_done(c); bugged - callback is triggered twice by composite_continue and composite_done */ 612 c->state = COMPOSITE_STATE_DONE; /* this is workaround */ 613 614 return c; 615} 616 617NTSTATUS dcom_get_pipe_recv(struct composite_context *c, struct dcerpc_pipe **pp) 618{ 619 NTSTATUS status; 620 621 status = dcom_get_pipe((struct IUnknown *)c->private_data, pp); 622 talloc_free(c); 623 624 return status; 625} 626 627/* FIXME:avg put IUnknown_Release_out into header */ 628struct IUnknown_Release_out { 629 uint32_t result; 630}; 631 632void dcom_release_continue(struct composite_context *cr) 633{ 634 struct composite_context *c; 635 struct IUnknown *d; 636 struct IUnknown_Release_out *out; 637 WERROR r; 638 639 c = talloc_get_type(cr->async.private_data, struct composite_context); 640 d = c->private_data; 641 r = IRemUnknown_RemRelease_recv(cr); 642 talloc_free(d); 643 out = talloc_zero(c, struct IUnknown_Release_out); 644 out->result = W_ERROR_V(r); 645 c->private_data = out; 646 composite_done(c); 647} 648 649struct composite_context *dcom_release_send(struct IUnknown *d, TALLOC_CTX *mem_ctx) 650{ 651 struct composite_context *c, *cr; 652 struct REMINTERFACEREF iref; 653 struct dcom_object_exporter *ox; 654 655 c = composite_create(d->ctx, d->ctx->event_ctx); 656 if (c == NULL) return NULL; 657 c->private_data = d; 658 659 ox = object_exporter_by_ip(d->ctx, d); 660 iref.ipid = IUnknown_ipid(d); 661 iref.cPublicRefs = 5; 662 iref.cPrivateRefs = 0; 663 cr = IRemUnknown_RemRelease_send(ox->rem_unknown, mem_ctx, 1, &iref); 664 665 composite_continue(c, cr, dcom_release_continue, c); 666 return c; 667} 668 669uint32_t dcom_release_recv(struct composite_context *c) 670{ 671 NTSTATUS status; 672 WERROR r; 673 674 status = composite_wait(c); 675 if (!NT_STATUS_IS_OK(status)) 676 r = ntstatus_to_werror(status); 677 else 678 W_ERROR_V(r) = ((struct IUnknown_Release_out *)c->private_data)->result; 679 talloc_free(c); 680 return W_ERROR_IS_OK(r) ? 0 : W_ERROR_V(r); 681} 682 683uint32_t dcom_release(void *interface, TALLOC_CTX *mem_ctx) 684{ 685 struct composite_context *c; 686 687 c = dcom_release_send(interface, mem_ctx); 688 return dcom_release_recv(c); 689} 690 691void dcom_proxy_async_call_recv_pipe_send_rpc(struct composite_context *c_pipe) 692{ 693 struct composite_context *c; 694 struct dcom_proxy_async_call_state *s; 695 struct dcerpc_pipe *p; 696 struct rpc_request *req; 697 NTSTATUS status; 698 699 c = c_pipe->async.private_data; 700 s = talloc_get_type(c->private_data, struct dcom_proxy_async_call_state); 701 702 status = dcom_get_pipe_recv(c_pipe, &p); 703 if (!NT_STATUS_IS_OK(status)) { 704 composite_error(c, NT_STATUS_RPC_NT_CALL_FAILED); 705 return; 706 } 707 708 req = dcerpc_ndr_request_send(p, &s->d->obj.u_objref.u_standard.std.ipid, s->table, s->opnum, s, s->r); 709 composite_continue_rpc(c, req, s->continuation, c); 710} 711