root/source4/lib/com/dcom/main.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dcerpc_binding_from_STRINGBINDING
  2. dcom_get_server_credentials
  3. dcom_add_server_credentials
  4. dcom_update_credentials_for_aliases
  5. dcom_client_init
  6. dcom_connect_host
  7. object_exporter_by_oxid
  8. object_exporter_update_oxid
  9. object_exporter_by_ip
  10. dcom_create_object
  11. find_similar_binding
  12. dcom_query_interface
  13. is_ip_binding
  14. dcom_get_pipe
  15. dcom_OBJREF_from_IUnknown
  16. dcom_IUnknown_from_OBJREF
  17. dcom_get_current_oxid
  18. dcom_get_pipe_send
  19. dcom_get_pipe_recv
  20. dcom_release_continue
  21. dcom_release_send
  22. dcom_release_recv
  23. dcom_release
  24. dcom_proxy_async_call_recv_pipe_send_rpc

   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 
  37 static NTSTATUS dcerpc_binding_from_STRINGBINDING(TALLOC_CTX *mem_ctx, struct dcerpc_binding **b_out, struct STRINGBINDING *bd)
     /* [<][>][^][v][top][bottom][index][help] */
  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 
  72 struct cli_credentials *dcom_get_server_credentials(struct com_context *ctx, const char *server)
     /* [<][>][^][v][top][bottom][index][help] */
  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  */
  95 void dcom_add_server_credentials(struct com_context *ctx, const char *server, 
     /* [<][>][^][v][top][bottom][index][help] */
  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 
 129 void dcom_update_credentials_for_aliases(struct com_context *ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 150 struct dcom_client_context *dcom_client_init(struct com_context *ctx, struct cli_credentials *credentials)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 162 static NTSTATUS dcom_connect_host(struct com_context *ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 210 end:
 211         talloc_free(loc_ctx);
 212         return status;
 213 }
 214 
 215 struct dcom_object_exporter *object_exporter_by_oxid(struct com_context *ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 228 struct dcom_object_exporter *object_exporter_update_oxid(struct com_context *ctx, uint64_t oxid, struct DUALSTRINGARRAY *bindings)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 244 struct dcom_object_exporter *object_exporter_by_ip(struct com_context *ctx, struct IUnknown *ip)
     /* [<][>][^][v][top][bottom][index][help] */
 245 {
 246         return object_exporter_by_oxid(ctx, ip->obj.u_objref.u_standard.std.oxid);
 247 }
 248 
 249 WERROR dcom_create_object(struct com_context *ctx, struct GUID *clsid, const char *server, int num_ifaces, struct GUID *iid, struct IUnknown ***ip, WERROR *results)
     /* [<][>][^][v][top][bottom][index][help] */
 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;
 356 end:
 357         talloc_free(loc_ctx);
 358         return hr;
 359 }
 360 
 361 int find_similar_binding(struct STRINGBINDING **sb, const char *host)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 372 WERROR dcom_query_interface(struct IUnknown *d, uint32_t cRefs, uint16_t cIids, struct GUID *iids, struct IUnknown **ip, WERROR *results)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 409 int is_ip_binding(const char* s)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 420 NTSTATUS dcom_get_pipe(struct IUnknown *iface, struct dcerpc_pipe **pp)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 513 NTSTATUS dcom_OBJREF_from_IUnknown(TALLLOC_CTX *mem_ctx, struct OBJREF *o, struct IUnknown *p)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 540 enum ndr_err_code dcom_IUnknown_from_OBJREF(struct com_context *ctx, struct IUnknown **_p, struct OBJREF *o)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 598 uint64_t dcom_get_current_oxid(void)
     /* [<][>][^][v][top][bottom][index][help] */
 599 {
 600         return getpid();
 601 }
 602 
 603 /* FIXME:Fake async dcom_get_pipe_* */
 604 struct composite_context *dcom_get_pipe_send(struct IUnknown *d, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 617 NTSTATUS dcom_get_pipe_recv(struct composite_context *c, struct dcerpc_pipe **pp)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 628 struct IUnknown_Release_out {
 629         uint32_t result;
 630 };
 631 
 632 void dcom_release_continue(struct composite_context *cr)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 649 struct composite_context *dcom_release_send(struct IUnknown *d, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 669 uint32_t dcom_release_recv(struct composite_context *c)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 683 uint32_t dcom_release(void *interface, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 684 {
 685         struct composite_context *c;
 686 
 687         c = dcom_release_send(interface, mem_ctx);
 688         return dcom_release_recv(c);
 689 }
 690 
 691 void dcom_proxy_async_call_recv_pipe_send_rpc(struct composite_context *c_pipe)
     /* [<][>][^][v][top][bottom][index][help] */
 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 }

/* [<][>][^][v][top][bottom][index][help] */