r8073: a successful rpc call from ejs!
[amitay/samba.git] / source4 / librpc / rpc / dcerpc_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc utility functions
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Jelmer Vernooij 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "system/network.h"
27 #include "librpc/gen_ndr/ndr_epmapper.h"
28
29 /*
30   find the pipe name for a local IDL interface
31 */
32 const char *idl_pipe_name(const char *uuid, uint32_t if_version)
33 {
34         const struct dcerpc_interface_list *l;
35         for (l=librpc_dcerpc_pipes();l;l=l->next) {
36                 if (strcasecmp(l->table->uuid, uuid) == 0 &&
37                     l->table->if_version == if_version) {
38                         return l->table->name;
39                 }
40         }
41         return "UNKNOWN";
42 }
43
44 /*
45   find the number of calls defined by local IDL
46 */
47 int idl_num_calls(const char *uuid, uint32_t if_version)
48 {
49         const struct dcerpc_interface_list *l;
50         for (l=librpc_dcerpc_pipes();l;l=l->next){
51                 if (strcasecmp(l->table->uuid, uuid) == 0 &&
52                     l->table->if_version == if_version) {
53                         return l->table->num_calls;
54                 }
55         }
56         return -1;
57 }
58
59
60 /*
61   find a dcerpc interface by name
62 */
63 const struct dcerpc_interface_table *idl_iface_by_name(const char *name)
64 {
65         const struct dcerpc_interface_list *l;
66         for (l=librpc_dcerpc_pipes();l;l=l->next) {
67                 if (strcasecmp(l->table->name, name) == 0) {
68                         return l->table;
69                 }
70         }
71         return NULL;
72 }
73
74 /*
75   find a dcerpc interface by uuid
76 */
77 const struct dcerpc_interface_table *idl_iface_by_uuid(const char *uuid)
78 {
79         const struct dcerpc_interface_list *l;
80         for (l=librpc_dcerpc_pipes();l;l=l->next) {
81                 if (strcasecmp(l->table->uuid, uuid) == 0) {
82                         return l->table;
83                 }
84         }
85         return NULL;
86 }
87
88 /*
89   find a dcerpc call on an interface by name
90 */
91 const struct dcerpc_interface_call *dcerpc_iface_find_call(const struct dcerpc_interface_table *iface,
92                                                            const char *name)
93 {
94         int i;
95         for (i=0;i<iface->num_calls;i++) {
96                 if (strcmp(iface->calls[i].name, name) == 0) {
97                         return &iface->calls[i];
98                 }
99         }
100         return NULL;
101 }
102
103 /* 
104    push a ncacn_packet into a blob, potentially with auth info
105 */
106 NTSTATUS ncacn_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
107                           struct ncacn_packet *pkt,
108                           struct dcerpc_auth *auth_info)
109 {
110         NTSTATUS status;
111         struct ndr_push *ndr;
112
113         ndr = ndr_push_init_ctx(mem_ctx);
114         if (!ndr) {
115                 return NT_STATUS_NO_MEMORY;
116         }
117
118         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
119                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
120         }
121
122         if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
123                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
124         }
125
126         if (auth_info) {
127                 pkt->auth_length = auth_info->credentials.length;
128         } else {
129                 pkt->auth_length = 0;
130         }
131
132         status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
133         if (!NT_STATUS_IS_OK(status)) {
134                 return status;
135         }
136
137         if (auth_info) {
138                 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
139         }
140
141         *blob = ndr_push_blob(ndr);
142
143         /* fill in the frag length */
144         dcerpc_set_frag_length(blob, blob->length);
145
146         return NT_STATUS_OK;
147 }
148
149 #define MAX_PROTSEQ             10
150
151 static const struct {
152         const char *name;
153         enum dcerpc_transport_t transport;
154         int num_protocols;
155         enum epm_protocol protseq[MAX_PROTSEQ];
156 } transports[] = {
157         { "ncacn_np",     NCACN_NP, 3, 
158                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NETBIOS }},
159         { "ncacn_ip_tcp", NCACN_IP_TCP, 3, 
160                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP, EPM_PROTOCOL_IP } }, 
161         { "ncacn_http", NCACN_HTTP, 3, 
162                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP, EPM_PROTOCOL_IP } }, 
163         { "ncadg_ip_udp", NCACN_IP_UDP, 3, 
164                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UDP, EPM_PROTOCOL_IP } },
165         { "ncalrpc", NCALRPC, 2, 
166                 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE } },
167         { "ncacn_unix_stream", NCACN_UNIX_STREAM, 2, 
168                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } },
169         { "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2, 
170                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UNIX_DS } },
171         { "ncacn_at_dsp", NCACN_AT_DSP, 3, 
172                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DSP } },
173         { "ncadg_at_ddp", NCADG_AT_DDP, 3, 
174                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DDP } },
175         { "ncacn_vns_ssp", NCACN_VNS_SPP, 3, 
176                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_SPP } },
177         { "ncacn_vns_ipc", NCACN_VNS_IPC, 3, 
178                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_IPC }, },
179         { "ncadg_ipx", NCADG_IPX, 2,
180                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_IPX },
181         },
182         { "ncacn_spx", NCACN_SPX, 3,
183                 /* I guess some MS programmer confused the identifier for 
184                  * EPM_PROTOCOL_UUID (0x0D or 13) with the one for 
185                  * EPM_PROTOCOL_SPX (0x13) here. -- jelmer*/
186                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID },
187         },
188 };
189
190 static const struct {
191         const char *name;
192         uint32_t flag;
193 } ncacn_options[] = {
194         {"sign", DCERPC_SIGN},
195         {"seal", DCERPC_SEAL},
196         {"connect", DCERPC_CONNECT},
197         {"spnego", DCERPC_AUTH_SPNEGO},
198         {"krb5", DCERPC_AUTH_KRB5},
199         {"validate", DCERPC_DEBUG_VALIDATE_BOTH},
200         {"print", DCERPC_DEBUG_PRINT_BOTH},
201         {"padcheck", DCERPC_DEBUG_PAD_CHECK},
202         {"bigendian", DCERPC_PUSH_BIGENDIAN}
203 };
204
205 const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *fl)
206 {
207         struct GUID uuid;
208         uint16_t if_version;
209         NTSTATUS status;
210
211         switch(fl->lhs.protocol) {
212                 case EPM_PROTOCOL_UUID:
213                         status = dcerpc_floor_get_lhs_data(fl, &uuid, &if_version);
214                         if (NT_STATUS_IS_OK(status)) {
215                                 /* lhs is used: UUID */
216                                 char *uuidstr;
217
218                                 uuidstr = GUID_string(mem_ctx, &uuid);
219
220                                 if (strcasecmp(uuidstr, NDR_GUID) == 0) {
221                                         return "NDR";
222                                 } 
223
224                                 return talloc_asprintf(mem_ctx, " uuid %s/0x%02x", uuidstr, if_version);
225                         } else { /* IPX */
226                                 return talloc_asprintf(mem_ctx, "IPX:%s", 
227                                                 data_blob_hex_string(mem_ctx, &fl->rhs.uuid.unknown));
228                         }
229
230                 case EPM_PROTOCOL_NCACN:
231                         return "RPC-C";
232
233                 case EPM_PROTOCOL_NCADG:
234                         return "RPC";
235
236                 case EPM_PROTOCOL_NCALRPC:
237                         return "NCALRPC";
238
239                 case EPM_PROTOCOL_DNET_NSP:
240                         return "DNET/NSP";
241
242                 case EPM_PROTOCOL_IP:
243                         return talloc_asprintf(mem_ctx, "IP:%s", fl->rhs.ip.ipaddr);
244
245                 case EPM_PROTOCOL_PIPE:
246                         return talloc_asprintf(mem_ctx, "PIPE:%s", fl->rhs.pipe.path);
247
248                 case EPM_PROTOCOL_SMB:
249                         return talloc_asprintf(mem_ctx, "SMB:%s", fl->rhs.smb.unc);
250
251                 case EPM_PROTOCOL_UNIX_DS:
252                         return talloc_asprintf(mem_ctx, "Unix:%s", fl->rhs.unix_ds.path);
253
254                 case EPM_PROTOCOL_NETBIOS:
255                         return talloc_asprintf(mem_ctx, "NetBIOS:%s", fl->rhs.netbios.name);
256
257                 case EPM_PROTOCOL_NETBEUI:
258                         return "NETBeui";
259
260                 case EPM_PROTOCOL_SPX:
261                         return "SPX";
262
263                 case EPM_PROTOCOL_NB_IPX:
264                         return "NB_IPX";
265
266                 case EPM_PROTOCOL_HTTP:
267                         return talloc_asprintf(mem_ctx, "HTTP:%d", fl->rhs.http.port);
268
269                 case EPM_PROTOCOL_TCP:
270                         return talloc_asprintf(mem_ctx, "TCP:%d", fl->rhs.tcp.port);
271
272                 case EPM_PROTOCOL_UDP:
273                         return talloc_asprintf(mem_ctx, "UDP:%d", fl->rhs.udp.port);
274
275                 default:
276                         return talloc_asprintf(mem_ctx, "UNK(%02x):", fl->lhs.protocol);
277         }
278 }
279
280
281 /*
282   form a binding string from a binding structure
283 */
284 const char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
285 {
286         char *s = talloc_strdup(mem_ctx, "");
287         int i;
288         const char *t_name=NULL;
289
290         for (i=0;i<ARRAY_SIZE(transports);i++) {
291                 if (transports[i].transport == b->transport) {
292                         t_name = transports[i].name;
293                 }
294         }
295         if (!t_name) {
296                 return NULL;
297         }
298
299         if (!GUID_all_zero(&b->object)) { 
300                 s = talloc_asprintf(s, "%s@",
301                                     GUID_string(mem_ctx, &b->object));
302         }
303
304         s = talloc_asprintf_append(s, "%s:", t_name);
305         if (!s) return NULL;
306
307         if (b->host) {
308                 s = talloc_asprintf_append(s, "%s", b->host);
309         }
310
311         if (!b->endpoint && !b->options && !b->flags) {
312                 return s;
313         }
314
315         s = talloc_asprintf_append(s, "[");
316
317         if (b->endpoint) {
318                 s = talloc_asprintf_append(s, "%s", b->endpoint);
319         }
320
321         /* this is a *really* inefficent way of dealing with strings,
322            but this is rarely called and the strings are always short,
323            so I don't care */
324         for (i=0;b->options && b->options[i];i++) {
325                 s = talloc_asprintf_append(s, ",%s", b->options[i]);
326                 if (!s) return NULL;
327         }
328
329         for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
330                 if (b->flags & ncacn_options[i].flag) {
331                         s = talloc_asprintf_append(s, ",%s", ncacn_options[i].name);
332                         if (!s) return NULL;
333                 }
334         }
335
336         s = talloc_asprintf_append(s, "]");
337
338         return s;
339 }
340
341 /*
342   parse a binding string into a dcerpc_binding structure
343 */
344 NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_binding **b_out)
345 {
346         struct dcerpc_binding *b;
347         char *options, *type;
348         char *p;
349         int i, j, comma_count;
350
351         b = talloc(mem_ctx, struct dcerpc_binding);
352         if (!b) {
353                 return NT_STATUS_NO_MEMORY;
354         }
355
356         b->authservice = NULL;
357
358         p = strchr(s, '@');
359
360         if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
361                 NTSTATUS status;
362
363                 status = GUID_from_string(s, &b->object);
364
365                 if (NT_STATUS_IS_ERR(status)) {
366                         DEBUG(0, ("Failed parsing UUID\n"));
367                         return status;
368                 }
369
370                 s = p + 1;
371         } else {
372                 ZERO_STRUCT(b->object);
373         }
374
375         b->object_version = 0;
376
377         p = strchr(s, ':');
378         if (!p) {
379                 return NT_STATUS_INVALID_PARAMETER;
380         }
381
382         type = talloc_strndup(mem_ctx, s, PTR_DIFF(p, s));
383         if (!type) {
384                 return NT_STATUS_NO_MEMORY;
385         }
386
387         for (i=0;i<ARRAY_SIZE(transports);i++) {
388                 if (strcasecmp(type, transports[i].name) == 0) {
389                         b->transport = transports[i].transport;
390                         break;
391                 }
392         }
393         if (i==ARRAY_SIZE(transports)) {
394                 DEBUG(0,("Unknown dcerpc transport '%s'\n", type));
395                 return NT_STATUS_INVALID_PARAMETER;
396         }
397         
398         s = p+1;
399
400         p = strchr(s, '[');
401         if (p) {
402                 b->host = talloc_strndup(b, s, PTR_DIFF(p, s));
403                 options = talloc_strdup(mem_ctx, p+1);
404                 if (options[strlen(options)-1] != ']') {
405                         return NT_STATUS_INVALID_PARAMETER;
406                 }
407                 options[strlen(options)-1] = 0;
408         } else {
409                 b->host = talloc_strdup(b, s);
410                 options = NULL;
411         }
412
413         if (!b->host) {
414                 return NT_STATUS_NO_MEMORY;
415         }
416
417         b->options = NULL;
418         b->flags = 0;
419         b->endpoint = NULL;
420
421         if (!options) {
422                 *b_out = b;
423                 return NT_STATUS_OK;
424         }
425
426         comma_count = count_chars(options, ',');
427
428         b->options = talloc_array(b, const char *, comma_count+2);
429         if (!b->options) {
430                 return NT_STATUS_NO_MEMORY;
431         }
432
433         for (i=0; (p = strchr(options, ',')); i++) {
434                 b->options[i] = talloc_strndup(b, options, PTR_DIFF(p, options));
435                 if (!b->options[i]) {
436                         return NT_STATUS_NO_MEMORY;
437                 }
438                 options = p+1;
439         }
440         b->options[i] = options;
441         b->options[i+1] = NULL;
442
443         /* some options are pre-parsed for convenience */
444         for (i=0;b->options[i];i++) {
445                 for (j=0;j<ARRAY_SIZE(ncacn_options);j++) {
446                         if (strcasecmp(ncacn_options[j].name, b->options[i]) == 0) {
447                                 int k;
448                                 b->flags |= ncacn_options[j].flag;
449                                 for (k=i;b->options[k];k++) {
450                                         b->options[k] = b->options[k+1];
451                                 }
452                                 i--;
453                                 break;
454                         }
455                 }
456         }
457
458         if (b->options[0]) {
459                 /* Endpoint is first option */
460                 b->endpoint = b->options[0];
461                 if (strlen(b->endpoint) == 0) b->endpoint = NULL;
462
463                 for (i=0;b->options[i];i++) {
464                         b->options[i] = b->options[i+1];
465                 }
466         }
467
468         if (b->options[0] == NULL)
469                 b->options = NULL;
470         
471         *b_out = b;
472         return NT_STATUS_OK;
473 }
474
475 NTSTATUS dcerpc_floor_get_lhs_data(struct epm_floor *floor, struct GUID *uuid, uint16_t *if_version)
476 {
477         TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
478         struct ndr_pull *ndr = ndr_pull_init_blob(&floor->lhs.lhs_data, mem_ctx);
479         NTSTATUS status;
480         
481         ndr->flags |= LIBNDR_FLAG_NOALIGN;
482
483         status = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, uuid);
484         if (NT_STATUS_IS_ERR(status)) {
485                 talloc_free(mem_ctx);
486                 return status;
487         }
488
489         status = ndr_pull_uint16(ndr, NDR_SCALARS, if_version);
490
491         talloc_free(mem_ctx);
492
493         return status;
494 }
495
496 static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, struct GUID *uuid, uint32_t if_version)
497 {
498         struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
499
500         ndr->flags |= LIBNDR_FLAG_NOALIGN;
501
502         ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, uuid);
503         ndr_push_uint16(ndr, NDR_SCALARS, if_version);
504
505         return ndr_push_blob(ndr);
506 }
507
508 const char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *floor)
509 {
510         switch (floor->lhs.protocol) {
511         case EPM_PROTOCOL_TCP:
512                 if (floor->rhs.tcp.port == 0) return NULL;
513                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.tcp.port);
514                 
515         case EPM_PROTOCOL_UDP:
516                 if (floor->rhs.udp.port == 0) return NULL;
517                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.udp.port);
518
519         case EPM_PROTOCOL_HTTP:
520                 if (floor->rhs.http.port == 0) return NULL;
521                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.http.port);
522
523         case EPM_PROTOCOL_IP:
524                 return talloc_strdup(mem_ctx, floor->rhs.ip.ipaddr);
525
526         case EPM_PROTOCOL_NCACN:
527                 return NULL;
528
529         case EPM_PROTOCOL_NCADG:
530                 return NULL;
531
532         case EPM_PROTOCOL_SMB:
533                 if (strlen(floor->rhs.smb.unc) == 0) return NULL;
534                 return talloc_strdup(mem_ctx, floor->rhs.smb.unc);
535
536         case EPM_PROTOCOL_PIPE:
537                 if (strlen(floor->rhs.pipe.path) == 0) return NULL;
538                 return talloc_strdup(mem_ctx, floor->rhs.pipe.path);
539
540         case EPM_PROTOCOL_NETBIOS:
541                 if (strlen(floor->rhs.netbios.name) == 0) return NULL;
542                 return talloc_strdup(mem_ctx, floor->rhs.netbios.name);
543
544         case EPM_PROTOCOL_NCALRPC:
545                 return NULL;
546                 
547         case EPM_PROTOCOL_VINES_SPP:
548                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.vines_spp.port);
549                 
550         case EPM_PROTOCOL_VINES_IPC:
551                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.vines_ipc.port);
552                 
553         case EPM_PROTOCOL_STREETTALK:
554                 return talloc_strdup(mem_ctx, floor->rhs.streettalk.streettalk);
555                 
556         case EPM_PROTOCOL_UNIX_DS:
557                 if (strlen(floor->rhs.unix_ds.path) == 0) return NULL;
558                 return talloc_strdup(mem_ctx, floor->rhs.unix_ds.path);
559                 
560         case EPM_PROTOCOL_NULL:
561                 return NULL;
562
563         default:
564                 DEBUG(0,("Unsupported lhs protocol %d\n", floor->lhs.protocol));
565                 break;
566         }
567
568         return NULL;
569 }
570
571 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *floor,  const char *data)
572 {
573         switch (floor->lhs.protocol) {
574         case EPM_PROTOCOL_TCP:
575                 floor->rhs.tcp.port = atoi(data);
576                 return NT_STATUS_OK;
577                 
578         case EPM_PROTOCOL_UDP:
579                 floor->rhs.udp.port = atoi(data);
580                 return NT_STATUS_OK;
581
582         case EPM_PROTOCOL_HTTP:
583                 floor->rhs.http.port = atoi(data);
584                 return NT_STATUS_OK;
585
586         case EPM_PROTOCOL_IP:
587                 floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
588                 NT_STATUS_HAVE_NO_MEMORY(floor->rhs.ip.ipaddr);
589                 return NT_STATUS_OK;
590
591         case EPM_PROTOCOL_NCACN:
592                 floor->rhs.ncacn.minor_version = 0;
593                 return NT_STATUS_OK;
594
595         case EPM_PROTOCOL_NCADG:
596                 floor->rhs.ncadg.minor_version = 0;
597                 return NT_STATUS_OK;
598
599         case EPM_PROTOCOL_SMB:
600                 floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
601                 NT_STATUS_HAVE_NO_MEMORY(floor->rhs.smb.unc);
602                 return NT_STATUS_OK;
603
604         case EPM_PROTOCOL_PIPE:
605                 floor->rhs.pipe.path = talloc_strdup(mem_ctx, data);
606                 NT_STATUS_HAVE_NO_MEMORY(floor->rhs.pipe.path);
607                 return NT_STATUS_OK;
608
609         case EPM_PROTOCOL_NETBIOS:
610                 floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
611                 NT_STATUS_HAVE_NO_MEMORY(floor->rhs.netbios.name);
612                 return NT_STATUS_OK;
613
614         case EPM_PROTOCOL_NCALRPC:
615                 return NT_STATUS_OK;
616                 
617         case EPM_PROTOCOL_VINES_SPP:
618                 floor->rhs.vines_spp.port = atoi(data);
619                 return NT_STATUS_OK;
620                 
621         case EPM_PROTOCOL_VINES_IPC:
622                 floor->rhs.vines_ipc.port = atoi(data);
623                 return NT_STATUS_OK;
624                 
625         case EPM_PROTOCOL_STREETTALK:
626                 floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
627                 NT_STATUS_HAVE_NO_MEMORY(floor->rhs.streettalk.streettalk);
628                 return NT_STATUS_OK;
629                 
630         case EPM_PROTOCOL_UNIX_DS:
631                 floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
632                 NT_STATUS_HAVE_NO_MEMORY(floor->rhs.unix_ds.path);
633                 return NT_STATUS_OK;
634                 
635         case EPM_PROTOCOL_NULL:
636                 return NT_STATUS_OK;
637
638         default:
639                 DEBUG(0,("Unsupported lhs protocol %d\n", floor->lhs.protocol));
640                 break;
641         }
642
643         return NT_STATUS_NOT_SUPPORTED;
644 }
645
646 enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
647 {
648         int i;
649
650         /* Find a transport that has 'prot' as 4th protocol */
651         for (i=0;i<ARRAY_SIZE(transports);i++) {
652                 if (transports[i].num_protocols >= 2 && 
653                         transports[i].protseq[1] == prot) {
654                         return transports[i].transport;
655                 }
656         }
657         
658         /* Unknown transport */
659         return -1;
660 }
661
662 enum dcerpc_transport_t dcerpc_transport_by_tower(struct epm_tower *tower)
663 {
664         int i;
665
666         /* Find a transport that matches this tower */
667         for (i=0;i<ARRAY_SIZE(transports);i++) {
668                 int j;
669                 if (transports[i].num_protocols != tower->num_floors - 2) {
670                         continue; 
671                 }
672
673                 for (j = 0; j < transports[i].num_protocols; j++) {
674                         if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
675                                 break;
676                         }
677                 }
678
679                 if (j == transports[i].num_protocols) {
680                         return transports[i].transport;
681                 }
682         }
683         
684         /* Unknown transport */
685         return -1;
686 }
687
688 NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx, struct epm_tower *tower, struct dcerpc_binding **b_out)
689 {
690         NTSTATUS status;
691         struct dcerpc_binding *binding;
692
693         binding = talloc(mem_ctx, struct dcerpc_binding);
694         NT_STATUS_HAVE_NO_MEMORY(binding);
695
696         ZERO_STRUCT(binding->object);
697         binding->options = NULL;
698         binding->host = NULL;
699         binding->flags = 0;
700
701         binding->transport = dcerpc_transport_by_tower(tower);
702
703         if (binding->transport == -1) {
704                 return NT_STATUS_NOT_SUPPORTED;
705         }
706
707         if (tower->num_floors < 1) {
708                 return NT_STATUS_OK;
709         }
710
711         /* Set object uuid */
712         status = dcerpc_floor_get_lhs_data(&tower->floors[0], &binding->object, &binding->object_version);
713         
714         if (!NT_STATUS_IS_OK(status)) {
715                 DEBUG(1, ("Error pulling object uuid and version: %s", nt_errstr(status)));     
716                 return status;
717         }
718
719         /* Ignore floor 1, it contains the NDR version info */
720         
721         binding->options = NULL;
722
723         /* Set endpoint */
724         if (tower->num_floors >= 4) {
725                 binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[3]);
726         } else {
727                 binding->endpoint = NULL;
728         }
729
730         /* Set network address */
731         if (tower->num_floors >= 5) {
732                 binding->host = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[4]);
733         }
734         *b_out = binding;
735         return NT_STATUS_OK;
736 }
737
738 NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, struct epm_tower *tower)
739 {
740         const enum epm_protocol *protseq = NULL;
741         int num_protocols = -1, i;
742         struct GUID ndr_guid;
743         NTSTATUS status;
744         
745         /* Find transport */
746         for (i=0;i<ARRAY_SIZE(transports);i++) {
747                 if (transports[i].transport == binding->transport) {
748                         protseq = transports[i].protseq;
749                         num_protocols = transports[i].num_protocols;
750                         break;
751                 }
752         }
753
754         if (num_protocols == -1) {
755                 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
756                 return NT_STATUS_UNSUCCESSFUL;
757         }
758
759         tower->num_floors = 2 + num_protocols;
760         tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
761
762         /* Floor 0 */
763         tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
764
765         tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx, &binding->object, binding->object_version);
766
767         tower->floors[0].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2);
768         
769         /* Floor 1 */
770         tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
771
772         status = GUID_from_string(NDR_GUID, &ndr_guid);
773         if (NT_STATUS_IS_ERR(status)) {
774                 return status;
775         }
776
777         tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx, &ndr_guid, NDR_GUID_VERSION);
778         
779         tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2);
780         
781         /* Floor 2 to num_protocols */
782         for (i = 0; i < num_protocols; i++) {
783                 tower->floors[2 + i].lhs.protocol = protseq[i];
784                 tower->floors[2 + i].lhs.lhs_data = data_blob_talloc(mem_ctx, NULL, 0);
785                 ZERO_STRUCT(tower->floors[2 + i].rhs);
786                 dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[2 + i], "");
787         }
788
789         /* The 4th floor contains the endpoint */
790         if (num_protocols >= 2 && binding->endpoint) {
791                 status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[3], binding->endpoint);
792                 if (NT_STATUS_IS_ERR(status)) {
793                         return status;
794                 }
795         }
796         
797         /* The 5th contains the network address */
798         if (num_protocols >= 3 && binding->host) {
799                 status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4], binding->host);
800                 if (NT_STATUS_IS_ERR(status)) {
801                         return status;
802                 }
803         }
804
805         return NT_STATUS_OK;
806 }
807
808 NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding,
809                                 const char *uuid, uint_t version, struct event_context *ev)
810 {
811         struct dcerpc_pipe *p;
812         NTSTATUS status;
813         struct epm_Map r;
814         struct policy_handle handle;
815         struct GUID guid;
816         struct epm_twr_t twr, *twr_r;
817         struct dcerpc_binding *epmapper_binding;
818         const struct dcerpc_interface_table *table = idl_iface_by_uuid(uuid);
819         int i;
820
821         struct cli_credentials *anon_creds
822                 = cli_credentials_init(mem_ctx);
823         cli_credentials_set_conf(anon_creds);
824         cli_credentials_set_anonymous(anon_creds);
825
826         /* First, check if there is a default endpoint specified in the IDL */
827
828         if (table) {
829                 struct dcerpc_binding *default_binding;
830
831                 binding->authservice = talloc_strdup(binding, table->authservices->names[0]);
832
833                 /* Find one of the default pipes for this interface */
834                 for (i = 0; i < table->endpoints->count; i++) {
835                         status = dcerpc_parse_binding(mem_ctx, table->endpoints->names[i], &default_binding);
836
837                         if (NT_STATUS_IS_OK(status)) {
838                                 if (default_binding->transport == binding->transport && default_binding->endpoint) {
839                                         binding->endpoint = talloc_reference(binding, default_binding->endpoint);
840                                         talloc_free(default_binding);
841                                         return NT_STATUS_OK;
842                                 } else {
843                                         talloc_free(default_binding);
844                                 }
845                         }
846                 }
847         }
848
849         epmapper_binding = talloc_zero(mem_ctx, struct dcerpc_binding);
850         if (!epmapper_binding) {
851                 return NT_STATUS_NO_MEMORY;
852         }
853
854         epmapper_binding->transport = binding->transport;
855         epmapper_binding->host = talloc_reference(epmapper_binding, 
856                                                   binding->host);
857         epmapper_binding->options = NULL;
858         epmapper_binding->flags = 0;
859         epmapper_binding->endpoint = NULL;
860         epmapper_binding->authservice = NULL;
861         
862         status = dcerpc_pipe_connect_b(mem_ctx, 
863                                        &p,
864                                        epmapper_binding,
865                                        DCERPC_EPMAPPER_UUID,
866                                        DCERPC_EPMAPPER_VERSION,
867                                        anon_creds, ev);
868
869         if (!NT_STATUS_IS_OK(status)) {
870                 return status;
871         }
872
873         ZERO_STRUCT(handle);
874         ZERO_STRUCT(guid);
875
876         status = GUID_from_string(uuid, &binding->object);
877         if (NT_STATUS_IS_ERR(status)) {
878                 return status;
879         }
880
881         binding->object_version = version;
882
883         status = dcerpc_binding_build_tower(p, binding, &twr.tower);
884         if (NT_STATUS_IS_ERR(status)) {
885                 return status;
886         }
887
888         /* with some nice pretty paper around it of course */
889         r.in.object = &guid;
890         r.in.map_tower = &twr;
891         r.in.entry_handle = &handle;
892         r.in.max_towers = 1;
893         r.out.entry_handle = &handle;
894
895         status = dcerpc_epm_Map(p, p, &r);
896         if (!NT_STATUS_IS_OK(status)) {
897                 talloc_free(p);
898                 return status;
899         }
900         if (r.out.result != 0 || r.out.num_towers != 1) {
901                 talloc_free(p);
902                 return NT_STATUS_PORT_UNREACHABLE;
903         }
904
905         twr_r = r.out.towers[0].twr;
906         if (!twr_r) {
907                 talloc_free(p);
908                 return NT_STATUS_PORT_UNREACHABLE;
909         }
910
911         if (twr_r->tower.num_floors != twr.tower.num_floors ||
912             twr_r->tower.floors[3].lhs.protocol != twr.tower.floors[3].lhs.protocol) {
913                 talloc_free(p);
914                 return NT_STATUS_PORT_UNREACHABLE;
915         }
916
917         binding->endpoint = talloc_reference(binding, dcerpc_floor_get_rhs_data(mem_ctx, &twr_r->tower.floors[3]));
918
919         talloc_free(p);
920
921         return NT_STATUS_OK;
922 }
923
924
925 /* 
926    perform an authenticated bind if needed
927 */
928 NTSTATUS dcerpc_pipe_auth(struct dcerpc_pipe *p, 
929                           struct dcerpc_binding *binding,
930                           const char *pipe_uuid, 
931                           uint32_t pipe_version,
932                           struct cli_credentials *credentials)
933 {
934         NTSTATUS status;
935         TALLOC_CTX *tmp_ctx;
936         tmp_ctx = talloc_new(p);
937
938         p->conn->flags = binding->flags;
939
940         /* remember the binding string for possible secondary connections */
941         p->conn->binding_string = dcerpc_binding_string(p, binding);
942
943         if (!cli_credentials_is_anonymous(credentials) &&
944                 (binding->flags & DCERPC_SCHANNEL) && 
945                 !cli_credentials_get_netlogon_creds(credentials)) {
946                 
947                 /* If we don't already have netlogon credentials for
948                  * the schannel bind, then we have to get these
949                  * first */
950                 status = dcerpc_bind_auth_schannel(tmp_ctx, 
951                                                    p, pipe_uuid, pipe_version, 
952                                                    credentials);
953         } else if (!cli_credentials_is_anonymous(credentials) &&
954                 !(binding->transport == NCACN_NP &&
955                   !(binding->flags & DCERPC_SIGN) &&
956                   !(binding->flags & DCERPC_SEAL))) {   
957         
958                 /* Perform an authenticated DCE-RPC bind, except where
959                  * we ask for a connection on NCACN_NP, and that
960                  * connection is not signed or sealed.  For that case
961                  * we rely on the already authenicated CIFS connection
962                  */
963
964                 uint8_t auth_type;
965                 if (binding->flags & DCERPC_AUTH_SPNEGO) {
966                         auth_type = DCERPC_AUTH_TYPE_SPNEGO;
967                 } else if (binding->flags & DCERPC_AUTH_KRB5) {
968                         auth_type = DCERPC_AUTH_TYPE_KRB5;
969                 } else if (binding->flags & DCERPC_SCHANNEL) {
970                         auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
971                 } else {
972                         auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
973                 }
974
975                 status = dcerpc_bind_auth_password(p, pipe_uuid, pipe_version, 
976                                                    credentials, auth_type,
977                                                    binding->authservice);
978         } else {
979                 status = dcerpc_bind_auth_none(p, pipe_uuid, pipe_version);
980         }
981
982         if (!NT_STATUS_IS_OK(status)) {
983                 DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
984         }
985         talloc_free(tmp_ctx);
986         return status;
987 }
988
989
990 /* open a rpc connection to a rpc pipe on SMB using the binding
991    structure to determine the endpoint and options */
992 static NTSTATUS dcerpc_pipe_connect_ncacn_np(TALLOC_CTX *tmp_ctx, 
993                                              struct dcerpc_pipe *p, 
994                                              struct dcerpc_binding *binding,
995                                              const char *pipe_uuid, 
996                                              uint32_t pipe_version,
997                                              struct cli_credentials *credentials)
998 {
999         NTSTATUS status;
1000         struct smbcli_state *cli;
1001         const char *pipe_name = NULL;
1002
1003         if (binding->flags & DCERPC_SCHANNEL) {
1004                 struct cli_credentials *anon_creds
1005                         = cli_credentials_init(tmp_ctx);
1006                 cli_credentials_set_anonymous(anon_creds);
1007                 cli_credentials_guess(anon_creds);
1008                 status = smbcli_full_connection(p->conn, &cli, 
1009                                                 binding->host, 
1010                                                 "IPC$", NULL, 
1011                                                 anon_creds, p->conn->event_ctx);
1012         } else {
1013                 status = smbcli_full_connection(p->conn, &cli, 
1014                                                 binding->host, 
1015                                                 "IPC$", NULL,
1016                                                 credentials, p->conn->event_ctx);
1017         }
1018         if (!NT_STATUS_IS_OK(status)) {
1019                 DEBUG(0,("Failed to connect to %s - %s\n", binding->host, nt_errstr(status)));
1020                 return status;
1021         }
1022
1023         /* Look up identifier using the epmapper */
1024         if (!binding->endpoint) {
1025                 status = dcerpc_epm_map_binding(tmp_ctx, binding, 
1026                                                 pipe_uuid, pipe_version, 
1027                                                 p->conn->event_ctx);
1028                 if (!NT_STATUS_IS_OK(status)) {
1029                         DEBUG(0,("Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s\n", 
1030                                  pipe_uuid, nt_errstr(status)));
1031                         return status;
1032                 }
1033                 DEBUG(2,("Mapped to DCERPC/NP pipe %s\n", binding->endpoint));
1034         }
1035
1036         pipe_name = binding->endpoint;
1037
1038         status = dcerpc_pipe_open_smb(p->conn, cli->tree, pipe_name);
1039         if (!NT_STATUS_IS_OK(status)) {
1040                 DEBUG(0,("Failed to open pipe %s - %s\n", pipe_name, nt_errstr(status)));
1041                 return status;
1042         }
1043
1044         return NT_STATUS_OK;
1045 }
1046
1047 /* open a rpc connection to a rpc pipe on SMP using the binding
1048    structure to determine the endpoint and options */
1049 static NTSTATUS dcerpc_pipe_connect_ncalrpc(TALLOC_CTX *tmp_ctx, 
1050                                             struct dcerpc_pipe *p, 
1051                                             struct dcerpc_binding *binding,
1052                                             const char *pipe_uuid, 
1053                                             uint32_t pipe_version)
1054 {
1055         NTSTATUS status;
1056
1057         /* Look up identifier using the epmapper */
1058         if (!binding->endpoint) {
1059                 status = dcerpc_epm_map_binding(tmp_ctx, binding, 
1060                                                 pipe_uuid, pipe_version, 
1061                                                 p->conn->event_ctx);
1062                 if (!NT_STATUS_IS_OK(status)) {
1063                         DEBUG(0,("Failed to map DCERPC/TCP NCALRPC identifier for '%s' - %s\n", 
1064                                  pipe_uuid, nt_errstr(status)));
1065                         return status;
1066                 }
1067                 DEBUG(2,("Mapped to DCERPC/LRPC identifier %s\n", binding->endpoint));
1068         }
1069
1070         status = dcerpc_pipe_open_pipe(p->conn, binding->endpoint);
1071         if (!NT_STATUS_IS_OK(status)) {
1072                 DEBUG(0,("Failed to open ncalrpc pipe '%s' - %s\n", 
1073                          binding->endpoint, nt_errstr(status)));
1074                 return status;
1075         }
1076
1077         return status;
1078 }
1079
1080
1081
1082 /* open a rpc connection to a rpc pipe on SMP using the binding
1083    structure to determine the endpoint and options */
1084 static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream(TALLOC_CTX *tmp_ctx, 
1085                                                       struct dcerpc_pipe *p, 
1086                                                       struct dcerpc_binding *binding,
1087                                                       const char *pipe_uuid, 
1088                                                       uint32_t pipe_version)
1089 {
1090         NTSTATUS status;
1091
1092         if (!binding->endpoint) {
1093                 DEBUG(0, ("Path to unix socket not specified\n"));
1094                 return NT_STATUS_INVALID_PARAMETER;
1095         }
1096
1097         status = dcerpc_pipe_open_unix_stream(p->conn, binding->endpoint);
1098         if (!NT_STATUS_IS_OK(status)) {
1099                 DEBUG(0,("Failed to open unix socket %s - %s\n", 
1100                          binding->endpoint, nt_errstr(status)));
1101                 talloc_free(p);
1102                 return status;
1103         }
1104
1105         return status;
1106 }
1107
1108 /* open a rpc connection to a rpc pipe on TCP/IP sockets using the binding
1109    structure to determine the endpoint and options */
1110 static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(TALLOC_CTX *tmp_ctx, 
1111                                                  struct dcerpc_pipe *p, 
1112                                                  struct dcerpc_binding *binding,
1113                                                  const char *pipe_uuid, 
1114                                                  uint32_t pipe_version)
1115 {
1116         NTSTATUS status;
1117         uint32_t port = 0;
1118
1119         if (!binding->endpoint) {
1120                 status = dcerpc_epm_map_binding(tmp_ctx, binding, 
1121                                                 pipe_uuid, pipe_version, 
1122                                                 p->conn->event_ctx);
1123                 if (!NT_STATUS_IS_OK(status)) {
1124                         DEBUG(0,("Failed to map DCERPC/TCP port for '%s' - %s\n", 
1125                                  pipe_uuid, nt_errstr(status)));
1126                         return status;
1127                 }
1128                 DEBUG(2,("Mapped to DCERPC/TCP port %s\n", binding->endpoint));
1129         }
1130
1131         port = atoi(binding->endpoint);
1132
1133         status = dcerpc_pipe_open_tcp(p->conn, binding->host, port);
1134         if (!NT_STATUS_IS_OK(status)) {
1135                 DEBUG(0,("Failed to connect to %s:%d - %s\n", 
1136                          binding->host, port, nt_errstr(status)));
1137                 return status;
1138         }
1139
1140         return status;
1141 }
1142
1143
1144 /* open a rpc connection to a rpc pipe, using the specified 
1145    binding structure to determine the endpoint and options */
1146 NTSTATUS dcerpc_pipe_connect_b(TALLOC_CTX *parent_ctx, 
1147                                struct dcerpc_pipe **pp, 
1148                                struct dcerpc_binding *binding,
1149                                const char *pipe_uuid, 
1150                                uint32_t pipe_version,
1151                                struct cli_credentials *credentials,
1152                                struct event_context *ev)
1153 {
1154         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
1155         struct dcerpc_pipe *p; 
1156         
1157         TALLOC_CTX *tmp_ctx;
1158
1159         (*pp) = NULL;
1160
1161         p = dcerpc_pipe_init(parent_ctx, ev);
1162         if (p == NULL) {
1163                 return NT_STATUS_NO_MEMORY;
1164         }
1165         tmp_ctx = talloc_named(p, 0, "dcerpc_pipe_connect_b tmp_ctx");
1166
1167         switch (binding->transport) {
1168         case NCACN_NP:
1169                 status = dcerpc_pipe_connect_ncacn_np(tmp_ctx, 
1170                                                       p, binding, pipe_uuid, pipe_version, credentials);
1171                 break;
1172         case NCACN_IP_TCP:
1173                 status = dcerpc_pipe_connect_ncacn_ip_tcp(tmp_ctx, 
1174                                                           p, binding, pipe_uuid, pipe_version);
1175                 break;
1176         case NCACN_UNIX_STREAM:
1177                 status = dcerpc_pipe_connect_ncacn_unix_stream(tmp_ctx, 
1178                                                                p, binding, pipe_uuid, pipe_version);
1179                 break;
1180         case NCALRPC:
1181                 status = dcerpc_pipe_connect_ncalrpc(tmp_ctx, 
1182                                                      p, binding, pipe_uuid, pipe_version);
1183                 break;
1184         default:
1185                 return NT_STATUS_NOT_SUPPORTED;
1186         }
1187
1188         if (!NT_STATUS_IS_OK(status)) {
1189                 talloc_free(p);
1190                 return status;
1191         }
1192
1193         status = dcerpc_pipe_auth(p, binding, pipe_uuid, pipe_version, credentials);
1194         if (!NT_STATUS_IS_OK(status)) {
1195                 talloc_free(p);
1196                 return status;
1197         }
1198         *pp = p;
1199         talloc_free(tmp_ctx);
1200
1201         return status;
1202 }
1203
1204
1205 /* open a rpc connection to a rpc pipe, using the specified string
1206    binding to determine the endpoint and options */
1207 NTSTATUS dcerpc_pipe_connect(TALLOC_CTX *parent_ctx, 
1208                              struct dcerpc_pipe **pp, 
1209                              const char *binding,
1210                              const char *pipe_uuid, 
1211                              uint32_t pipe_version,
1212                              struct cli_credentials *credentials,
1213                              struct event_context *ev)
1214 {
1215         struct dcerpc_binding *b;
1216         NTSTATUS status;
1217         TALLOC_CTX *tmp_ctx;
1218
1219         tmp_ctx = talloc_named(parent_ctx, 0, "dcerpc_pipe_connect tmp_ctx");
1220         if (!tmp_ctx) {
1221                 return NT_STATUS_NO_MEMORY;
1222         }
1223
1224         status = dcerpc_parse_binding(tmp_ctx, binding, &b);
1225         if (!NT_STATUS_IS_OK(status)) {
1226                 DEBUG(0,("Failed to parse dcerpc binding '%s'\n", binding));
1227                 talloc_free(tmp_ctx);
1228                 return status;
1229         }
1230
1231         DEBUG(3,("Using binding %s\n", dcerpc_binding_string(tmp_ctx, b)));
1232
1233         status = dcerpc_pipe_connect_b(tmp_ctx,
1234                                        pp, b, pipe_uuid, pipe_version, 
1235                                        credentials, ev);
1236
1237         if (NT_STATUS_IS_OK(status)) {
1238                 *pp = talloc_reference(parent_ctx, *pp);
1239         }
1240         talloc_free(tmp_ctx);
1241
1242         return status;
1243 }
1244
1245
1246 /*
1247   create a secondary dcerpc connection from a primary connection
1248
1249   if the primary is a SMB connection then the secondary connection
1250   will be on the same SMB connection, but use a new fnum
1251 */
1252 NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe **p2,
1253                                      struct dcerpc_binding *b)
1254
1255
1256 {
1257         struct smbcli_tree *tree;
1258         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
1259
1260         (*p2) = dcerpc_pipe_init(p, p->conn->event_ctx);
1261         if (*p2 == NULL) {
1262                 return NT_STATUS_NO_MEMORY;
1263         }
1264         
1265         switch (p->conn->transport.transport) {
1266         case NCACN_NP:
1267                 tree = dcerpc_smb_tree(p->conn);
1268                 if (!tree) {
1269                         return NT_STATUS_INVALID_PARAMETER;
1270                 }
1271                 status = dcerpc_pipe_open_smb((*p2)->conn, tree, b->endpoint);
1272                 break;
1273
1274         case NCACN_IP_TCP:
1275                 status = dcerpc_pipe_open_tcp((*p2)->conn, b->host, atoi(b->endpoint));
1276                 break;
1277
1278         case NCALRPC:
1279                 status = dcerpc_pipe_open_pipe((*p2)->conn, b->endpoint);
1280                 break;
1281
1282         default:
1283                 return NT_STATUS_NOT_SUPPORTED;
1284         }
1285
1286         if (!NT_STATUS_IS_OK(status)) {
1287                 talloc_free(*p2);
1288                 return status;
1289         }
1290
1291         (*p2)->conn->flags = p->conn->flags;
1292
1293         return NT_STATUS_OK;
1294 }
1295
1296 NTSTATUS dcerpc_generic_session_key(struct dcerpc_connection *c,
1297                                     DATA_BLOB *session_key)
1298 {
1299         /* this took quite a few CPU cycles to find ... */
1300         session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC");
1301         session_key->length = 16;
1302         return NT_STATUS_OK;
1303 }
1304
1305 /*
1306   fetch the user session key - may be default (above) or the SMB session key
1307 */
1308 NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
1309                                   DATA_BLOB *session_key)
1310 {
1311         return p->conn->security_state.session_key(p->conn, session_key);
1312 }
1313
1314
1315 /*
1316   log a rpc packet in a format suitable for ndrdump. This is especially useful
1317   for sealed packets, where ethereal cannot easily see the contents
1318
1319   this triggers on a debug level of >= 10
1320 */
1321 void dcerpc_log_packet(const struct dcerpc_interface_table *ndr,
1322                        uint32_t opnum, uint32_t flags, DATA_BLOB *pkt)
1323 {
1324         const int num_examples = 20;
1325         int i;
1326
1327         if (DEBUGLEVEL < 10) return;
1328
1329         for (i=0;i<num_examples;i++) {
1330                 char *name=NULL;
1331                 asprintf(&name, "%s/rpclog/%s-%u.%d.%s", 
1332                          lp_lockdir(), ndr->name, opnum, i,
1333                          (flags&NDR_IN)?"in":"out");
1334                 if (name == NULL) {
1335                         return;
1336                 }
1337                 if (!file_exist(name)) {
1338                         if (file_save(name, pkt->data, pkt->length)) {
1339                                 DEBUG(10,("Logged rpc packet to %s\n", name));
1340                         }
1341                         free(name);
1342                         break;
1343                 }
1344                 free(name);
1345         }
1346 }
1347
1348
1349
1350 /*
1351   create a secondary context from a primary connection
1352
1353   this uses dcerpc_alter_context() to create a new dcerpc context_id
1354 */
1355 NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p, 
1356                                   struct dcerpc_pipe **pp2,
1357                                   const char *pipe_uuid,
1358                                   uint32_t pipe_version)
1359 {
1360         NTSTATUS status;
1361         struct dcerpc_pipe *p2;
1362         
1363         p2 = talloc_zero(p, struct dcerpc_pipe);
1364         if (p2 == NULL) {
1365                 return NT_STATUS_NO_MEMORY;
1366         }
1367         p2->conn = talloc_reference(p2, p->conn);
1368         p2->request_timeout = p->request_timeout;
1369
1370         p2->context_id = ++p->conn->next_context_id;
1371
1372         status = GUID_from_string(pipe_uuid, &p2->syntax.uuid);
1373         if (!NT_STATUS_IS_OK(status)) {
1374                 talloc_free(p2);
1375                 return status;
1376         }
1377         p2->syntax.if_version = pipe_version;
1378
1379         status = GUID_from_string(NDR_GUID, &p2->transfer_syntax.uuid);
1380         if (!NT_STATUS_IS_OK(status)) {
1381                 talloc_free(p2);
1382                 return status;
1383         }
1384         p2->transfer_syntax.if_version = NDR_GUID_VERSION;
1385
1386         status = dcerpc_alter_context(p2, p2, &p2->syntax, &p2->transfer_syntax);
1387         if (!NT_STATUS_IS_OK(status)) {
1388                 talloc_free(p2);
1389                 return status;
1390         }
1391
1392         *pp2 = p2;
1393
1394         return status;
1395 }