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