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