r4037: fixed a bunch of "might be uninitialised" warnings after enabling -O1 in my...
[metze/samba/wip.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         struct dcerpc_interface_list *l;
34         for (l=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         struct dcerpc_interface_list *l;
49         for (l=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         struct dcerpc_interface_list *l;
65         for (l=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         struct dcerpc_interface_list *l;
79         for (l=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_protocols 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, 2,
168                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SPX },
169         },
170 };
171
172 static const struct {
173         const char *name;
174         uint32_t flag;
175 } ncacn_options[] = {
176         {"sign", DCERPC_SIGN},
177         {"seal", DCERPC_SEAL},
178         {"connect", DCERPC_CONNECT},
179         {"validate", DCERPC_DEBUG_VALIDATE_BOTH},
180         {"print", DCERPC_DEBUG_PRINT_BOTH},
181         {"padcheck", DCERPC_DEBUG_PAD_CHECK},
182         {"bigendian", DCERPC_PUSH_BIGENDIAN}
183 };
184
185
186
187 /*
188   form a binding string from a binding structure
189 */
190 const char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
191 {
192         char *s = talloc_strdup(mem_ctx, "");
193         int i;
194         const char *t_name=NULL;
195
196         for (i=0;i<ARRAY_SIZE(transports);i++) {
197                 if (transports[i].transport == b->transport) {
198                         t_name = transports[i].name;
199                 }
200         }
201         if (!t_name) {
202                 return NULL;
203         }
204
205         if (!GUID_all_zero(&b->object)) { 
206                 s = talloc_asprintf(s, "%s@",
207                                     GUID_string(mem_ctx, &b->object));
208         }
209
210         s = talloc_asprintf_append(s, "%s:", t_name);
211         if (!s) return NULL;
212
213         if (b->host) {
214                 s = talloc_asprintf_append(s, "%s", b->host);
215         }
216
217         if (!b->endpoint && !b->options && !b->flags) {
218                 return s;
219         }
220
221         s = talloc_asprintf_append(s, "[");
222
223         if (b->endpoint) {
224                 s = talloc_asprintf_append(s, "%s", b->endpoint);
225         }
226
227         /* this is a *really* inefficent way of dealing with strings,
228            but this is rarely called and the strings are always short,
229            so I don't care */
230         for (i=0;b->options && b->options[i];i++) {
231                 s = talloc_asprintf_append(s, ",%s", b->options[i]);
232                 if (!s) return NULL;
233         }
234
235         for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
236                 if (b->flags & ncacn_options[i].flag) {
237                         s = talloc_asprintf_append(s, ",%s", ncacn_options[i].name);
238                         if (!s) return NULL;
239                 }
240         }
241
242         s = talloc_asprintf_append(s, "]");
243
244         return s;
245 }
246
247 /*
248   parse a binding string into a dcerpc_binding structure
249 */
250 NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struct dcerpc_binding *b)
251 {
252         char *options, *type;
253         char *p;
254         int i, j, comma_count;
255
256         p = strchr(s, '@');
257
258         if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
259                 NTSTATUS status;
260
261                 status = GUID_from_string(s, &b->object);
262
263                 if (NT_STATUS_IS_ERR(status)) {
264                         DEBUG(0, ("Failed parsing UUID\n"));
265                         return status;
266                 }
267
268                 s = p + 1;
269         } else {
270                 ZERO_STRUCT(b->object);
271         }
272
273         b->object_version = 0;
274
275         p = strchr(s, ':');
276         if (!p) {
277                 return NT_STATUS_INVALID_PARAMETER;
278         }
279
280         type = talloc_strndup(mem_ctx, s, PTR_DIFF(p, s));
281         if (!type) {
282                 return NT_STATUS_NO_MEMORY;
283         }
284
285         for (i=0;i<ARRAY_SIZE(transports);i++) {
286                 if (strcasecmp(type, transports[i].name) == 0) {
287                         b->transport = transports[i].transport;
288                         break;
289                 }
290         }
291         if (i==ARRAY_SIZE(transports)) {
292                 DEBUG(0,("Unknown dcerpc transport '%s'\n", type));
293                 return NT_STATUS_INVALID_PARAMETER;
294         }
295         
296         s = p+1;
297
298         p = strchr(s, '[');
299         if (p) {
300                 b->host = talloc_strndup(mem_ctx, s, PTR_DIFF(p, s));
301                 options = talloc_strdup(mem_ctx, p+1);
302                 if (options[strlen(options)-1] != ']') {
303                         return NT_STATUS_INVALID_PARAMETER;
304                 }
305                 options[strlen(options)-1] = 0;
306         } else {
307                 b->host = talloc_strdup(mem_ctx, s);
308                 options = NULL;
309         }
310
311         if (!b->host) {
312                 return NT_STATUS_NO_MEMORY;
313         }
314
315         b->options = NULL;
316         b->flags = 0;
317         b->endpoint = NULL;
318
319         if (!options) {
320                 return NT_STATUS_OK;
321         }
322
323         comma_count = count_chars(options, ',');
324
325         b->options = talloc_array_p(mem_ctx, const char *, comma_count+2);
326         if (!b->options) {
327                 return NT_STATUS_NO_MEMORY;
328         }
329
330         for (i=0; (p = strchr(options, ',')); i++) {
331                 b->options[i] = talloc_strndup(mem_ctx, options, PTR_DIFF(p, options));
332                 if (!b->options[i]) {
333                         return NT_STATUS_NO_MEMORY;
334                 }
335                 options = p+1;
336         }
337         b->options[i] = options;
338         b->options[i+1] = NULL;
339
340         /* some options are pre-parsed for convenience */
341         for (i=0;b->options[i];i++) {
342                 for (j=0;j<ARRAY_SIZE(ncacn_options);j++) {
343                         if (strcasecmp(ncacn_options[j].name, b->options[i]) == 0) {
344                                 int k;
345                                 b->flags |= ncacn_options[j].flag;
346                                 for (k=i;b->options[k];k++) {
347                                         b->options[k] = b->options[k+1];
348                                 }
349                                 i--;
350                                 break;
351                         }
352                 }
353         }
354
355         if (b->options[0]) {
356                 /* Endpoint is first option */
357                 b->endpoint = b->options[0];
358                 if (strlen(b->endpoint) == 0) b->endpoint = NULL;
359
360                 for (i=0;b->options[i];i++) {
361                         b->options[i] = b->options[i+1];
362                 }
363         }
364
365         if (b->options[0] == NULL)
366                 b->options = NULL;
367         
368         return NT_STATUS_OK;
369 }
370
371 const char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *floor)
372 {
373         switch (floor->lhs.protocol) {
374         case EPM_PROTOCOL_TCP:
375                 if (floor->rhs.tcp.port == 0) return NULL;
376                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.tcp.port);
377                 
378         case EPM_PROTOCOL_UDP:
379                 if (floor->rhs.udp.port == 0) return NULL;
380                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.udp.port);
381
382         case EPM_PROTOCOL_HTTP:
383                 if (floor->rhs.http.port == 0) return NULL;
384                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.http.port);
385
386         case EPM_PROTOCOL_IP:
387                 if (floor->rhs.ip.address == 0) {
388                         return NULL; 
389                 }
390
391                 {
392                         struct ipv4_addr in;
393                         in.addr = htonl(floor->rhs.ip.address);
394                         return talloc_strdup(mem_ctx, sys_inet_ntoa(in));
395                 }
396
397         case EPM_PROTOCOL_NCACN:
398                 return NULL;
399
400         case EPM_PROTOCOL_NCADG:
401                 return NULL;
402
403         case EPM_PROTOCOL_SMB:
404                 if (strlen(floor->rhs.smb.unc) == 0) return NULL;
405                 return talloc_strdup(mem_ctx, floor->rhs.smb.unc);
406
407         case EPM_PROTOCOL_PIPE:
408                 if (strlen(floor->rhs.pipe.path) == 0) return NULL;
409                 return talloc_strdup(mem_ctx, floor->rhs.pipe.path);
410
411         case EPM_PROTOCOL_NETBIOS:
412                 if (strlen(floor->rhs.netbios.name) == 0) return NULL;
413                 return talloc_strdup(mem_ctx, floor->rhs.netbios.name);
414
415         case EPM_PROTOCOL_NCALRPC:
416                 return NULL;
417                 
418         case EPM_PROTOCOL_VINES_SPP:
419                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.vines_spp.port);
420                 
421         case EPM_PROTOCOL_VINES_IPC:
422                 return talloc_asprintf(mem_ctx, "%d", floor->rhs.vines_ipc.port);
423                 
424         case EPM_PROTOCOL_STREETTALK:
425                 return talloc_strdup(mem_ctx, floor->rhs.streettalk.streettalk);
426                 
427         case EPM_PROTOCOL_UNIX_DS:
428                 if (strlen(floor->rhs.unix_ds.path) == 0) return NULL;
429                 return talloc_strdup(mem_ctx, floor->rhs.unix_ds.path);
430                 
431         case EPM_PROTOCOL_NULL:
432                 return NULL;
433         }
434
435         return NULL;
436 }
437
438 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *floor,  const char *data)
439 {
440         switch (floor->lhs.protocol) {
441         case EPM_PROTOCOL_TCP:
442                 floor->rhs.tcp.port = atoi(data);
443                 return NT_STATUS_OK;
444                 
445         case EPM_PROTOCOL_UDP:
446                 floor->rhs.udp.port = atoi(data);
447                 return NT_STATUS_OK;
448
449         case EPM_PROTOCOL_HTTP:
450                 floor->rhs.http.port = atoi(data);
451                 return NT_STATUS_OK;
452
453         case EPM_PROTOCOL_IP:
454                 if (strlen(data) > 0) {
455                         floor->rhs.ip.address = ntohl(interpret_addr(data));
456                 } else {
457                         floor->rhs.ip.address = 0;
458                 }
459                 return NT_STATUS_OK;
460
461         case EPM_PROTOCOL_NCACN:
462                 floor->rhs.ncacn.minor_version = 0;
463                 return NT_STATUS_OK;
464
465         case EPM_PROTOCOL_NCADG:
466                 floor->rhs.ncadg.minor_version = 0;
467                 return NT_STATUS_OK;
468
469         case EPM_PROTOCOL_SMB:
470                 floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
471                 if (!floor->rhs.smb.unc) {
472                         return NT_STATUS_NO_MEMORY;
473                 }
474                 return NT_STATUS_OK;
475
476         case EPM_PROTOCOL_PIPE:
477                 floor->rhs.pipe.path = talloc_strdup(mem_ctx, data);
478                 if (!floor->rhs.pipe.path) {
479                         return NT_STATUS_NO_MEMORY;
480                 }
481                 return NT_STATUS_OK;
482
483         case EPM_PROTOCOL_NETBIOS:
484                 floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
485                 if (!floor->rhs.netbios.name) {
486                         return NT_STATUS_NO_MEMORY;
487                 }
488                 return NT_STATUS_OK;
489
490         case EPM_PROTOCOL_NCALRPC:
491                 return NT_STATUS_OK;
492                 
493         case EPM_PROTOCOL_VINES_SPP:
494                 floor->rhs.vines_spp.port = atoi(data);
495                 return NT_STATUS_OK;
496                 
497         case EPM_PROTOCOL_VINES_IPC:
498                 floor->rhs.vines_ipc.port = atoi(data);
499                 return NT_STATUS_OK;
500                 
501         case EPM_PROTOCOL_STREETTALK:
502                 floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
503                 if (!floor->rhs.streettalk.streettalk) {
504                         return NT_STATUS_NO_MEMORY;
505                 }
506                 return NT_STATUS_OK;
507                 
508         case EPM_PROTOCOL_UNIX_DS:
509                 floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
510                 if (!floor->rhs.unix_ds.path) {
511                         return NT_STATUS_NO_MEMORY;
512                 }
513                 return NT_STATUS_OK;
514                 
515         case EPM_PROTOCOL_NULL:
516                 return NT_STATUS_OK;
517         }
518
519         return NT_STATUS_NOT_SUPPORTED;
520 }
521
522 enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
523 {
524         int i;
525
526         /* Find a transport that has 'prot' as 4th protocol */
527         for (i=0;i<ARRAY_SIZE(transports);i++) {
528                 if (transports[i].num_protocols >= 2 && 
529                         transports[i].protseq[1] == prot) {
530                         return transports[i].transport;
531                 }
532         }
533         
534         /* Unknown transport */
535         return -1;
536 }
537
538 enum dcerpc_transport_t dcerpc_transport_by_tower(struct epm_tower *tower)
539 {
540         int i;
541
542         /* Find a transport that matches this tower */
543         for (i=0;i<ARRAY_SIZE(transports);i++) {
544                 int j;
545                 if (transports[i].num_protocols != tower->num_floors - 2) {
546                         continue; 
547                 }
548
549                 for (j = 0; j < transports[i].num_protocols; j++) {
550                         if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
551                                 break;
552                         }
553                 }
554
555                 if (j == transports[i].num_protocols) {
556                         return transports[i].transport;
557                 }
558         }
559         
560         /* Unknown transport */
561         return -1;
562 }
563
564 NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx, struct epm_tower *tower, struct dcerpc_binding *binding)
565 {
566         ZERO_STRUCT(binding->object);
567         binding->options = NULL;
568         binding->host = NULL;
569         binding->flags = 0;
570
571         binding->transport = dcerpc_transport_by_tower(tower);
572
573         if (binding->transport == -1) {
574                 return NT_STATUS_NOT_SUPPORTED;
575         }
576
577         if (tower->num_floors < 1) {
578                 return NT_STATUS_OK;
579         }
580
581         /* Set object uuid */
582         binding->object = tower->floors[0].lhs.info.uuid.uuid;
583         binding->object_version = tower->floors[0].lhs.info.uuid.version;
584
585         /* Ignore floor 1, it contains the NDR version info */
586         
587         binding->options = NULL;
588
589         /* Set endpoint */
590         if (tower->num_floors >= 4) {
591                 binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[3]);
592         } else {
593                 binding->endpoint = NULL;
594         }
595
596         /* Set network address */
597         if (tower->num_floors >= 5) {
598                 binding->host = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[4]);
599         }
600         return NT_STATUS_OK;
601 }
602
603 NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding, struct epm_tower *tower)
604 {
605         const enum epm_protocols *protseq = NULL;
606         int num_protocols = -1, i;
607         NTSTATUS status;
608         
609         /* Find transport */
610         for (i=0;i<ARRAY_SIZE(transports);i++) {
611                 if (transports[i].transport == binding->transport) {
612                         protseq = transports[i].protseq;
613                         num_protocols = transports[i].num_protocols;
614                         break;
615                 }
616         }
617
618         if (num_protocols == -1) {
619                 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
620                 return NT_STATUS_UNSUCCESSFUL;
621         }
622
623         tower->num_floors = 2 + num_protocols;
624         tower->floors = talloc_array_p(mem_ctx, struct epm_floor, tower->num_floors);
625
626         /* Floor 0 */
627         tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
628         tower->floors[0].lhs.info.uuid.uuid = binding->object;
629         tower->floors[0].lhs.info.uuid.version = binding->object_version;
630         tower->floors[0].rhs.uuid.unknown = 0;
631         
632         /* Floor 1 */
633         tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
634         tower->floors[1].lhs.info.uuid.version = NDR_GUID_VERSION;
635         tower->floors[1].rhs.uuid.unknown = 0;
636         status = GUID_from_string(NDR_GUID, &tower->floors[1].lhs.info.uuid.uuid);
637         if (NT_STATUS_IS_ERR(status)) {
638                 return status;
639         }
640
641         /* Floor 2 to num_protocols */
642         for (i = 0; i < num_protocols; i++) {
643                 tower->floors[2 + i].lhs.protocol = protseq[i];
644                 tower->floors[2 + i].lhs.info.lhs_data = data_blob_talloc(mem_ctx, NULL, 0);
645                 ZERO_STRUCT(tower->floors[2 + i].rhs);
646                 dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[2 + i], "");
647         }
648
649         /* The 4th floor contains the endpoint */
650         if (num_protocols >= 2 && binding->endpoint) {
651                 status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[3], binding->endpoint);
652                 if (NT_STATUS_IS_ERR(status)) {
653                         return status;
654                 }
655         }
656         
657         /* The 5th contains the network address */
658         if (num_protocols >= 3 && binding->host) {
659                 status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4], binding->host);
660                 if (NT_STATUS_IS_ERR(status)) {
661                         return status;
662                 }
663         }
664
665         return NT_STATUS_OK;
666 }
667
668 NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding,
669                                  const char *uuid, uint_t version)
670 {
671         struct dcerpc_pipe *p;
672         NTSTATUS status;
673         struct epm_Map r;
674         struct policy_handle handle;
675         struct GUID guid;
676         struct epm_twr_t twr, *twr_r;
677         struct dcerpc_binding epmapper_binding;
678         const struct dcerpc_interface_table *table = idl_iface_by_uuid(uuid);
679         int i;
680
681         /* First, check if there is a default endpoint specified in the IDL */
682
683         if (table) {
684                 struct dcerpc_binding default_binding;
685                 
686                 /* Find one of the default pipes for this interface */
687                 for (i = 0; i < table->endpoints->count; i++) {
688                         status = dcerpc_parse_binding(mem_ctx, table->endpoints->names[i], &default_binding);
689
690                         if (NT_STATUS_IS_OK(status) && default_binding.transport == binding->transport && default_binding.endpoint) {
691                                 binding->endpoint = talloc_strdup(mem_ctx, default_binding.endpoint);   
692                                 return NT_STATUS_OK;
693                         }
694                 }
695         }
696
697
698         ZERO_STRUCT(epmapper_binding);
699         epmapper_binding.transport = binding->transport;
700         epmapper_binding.host = binding->host;
701         epmapper_binding.options = NULL;
702         epmapper_binding.flags = 0;
703         epmapper_binding.endpoint = NULL;
704         
705         status = dcerpc_pipe_connect_b(&p,
706                                         &epmapper_binding,
707                                    DCERPC_EPMAPPER_UUID,
708                                    DCERPC_EPMAPPER_VERSION,
709                                    NULL, NULL, NULL);
710
711         if (!NT_STATUS_IS_OK(status)) {
712                 return status;
713         }
714
715         ZERO_STRUCT(handle);
716         ZERO_STRUCT(guid);
717
718         status = GUID_from_string(uuid, &binding->object);
719         if (NT_STATUS_IS_ERR(status)) {
720                 return status;
721         }
722
723         binding->object_version = version;
724
725         status = dcerpc_binding_build_tower(p, binding, &twr.tower);
726         if (NT_STATUS_IS_ERR(status)) {
727                 return status;
728         }
729
730         /* with some nice pretty paper around it of course */
731         r.in.object = &guid;
732         r.in.map_tower = &twr;
733         r.in.entry_handle = &handle;
734         r.in.max_towers = 1;
735         r.out.entry_handle = &handle;
736
737         status = dcerpc_epm_Map(p, p, &r);
738         if (!NT_STATUS_IS_OK(status)) {
739                 dcerpc_pipe_close(p);
740                 return status;
741         }
742         if (r.out.result != 0 || r.out.num_towers != 1) {
743                 dcerpc_pipe_close(p);
744                 return NT_STATUS_PORT_UNREACHABLE;
745         }
746
747         twr_r = r.out.towers[0].twr;
748         if (!twr_r) {
749                 dcerpc_pipe_close(p);
750                 return NT_STATUS_PORT_UNREACHABLE;
751         }
752
753         if (twr_r->tower.num_floors != twr.tower.num_floors ||
754             twr_r->tower.floors[3].lhs.protocol != twr.tower.floors[3].lhs.protocol) {
755                 dcerpc_pipe_close(p);
756                 return NT_STATUS_PORT_UNREACHABLE;
757         }
758
759         binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &twr_r->tower.floors[3]);
760
761         dcerpc_pipe_close(p);
762
763         return NT_STATUS_OK;
764 }
765
766
767 /* open a rpc connection to a rpc pipe on SMB using the binding
768    structure to determine the endpoint and options */
769 static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p, 
770                                              struct dcerpc_binding *binding,
771                                              const char *pipe_uuid, 
772                                              uint32_t pipe_version,
773                                              const char *domain,
774                                              const char *username,
775                                              const char *password)
776 {
777         NTSTATUS status;
778         BOOL retry;
779         struct smbcli_state *cli;
780         const char *pipe_name = NULL;
781         TALLOC_CTX *mem_ctx = talloc_init("dcerpc_pipe_connect_ncacn_np");
782         
783         /* Look up identifier using the epmapper */
784         if (!binding->endpoint) {
785                 status = dcerpc_epm_map_binding(mem_ctx, binding, pipe_uuid, pipe_version);
786                 if (!NT_STATUS_IS_OK(status)) {
787                         DEBUG(0,("Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s\n", 
788                                  pipe_uuid, nt_errstr(status)));
789                         talloc_destroy(mem_ctx);
790                         return status;
791                 }
792                 DEBUG(1,("Mapped to DCERPC/NP pipe %s\n", binding->endpoint));
793         }
794
795         pipe_name = binding->endpoint;
796
797         if (!strncasecmp(pipe_name, "/pipe/", 6) || 
798                 !strncasecmp(pipe_name, "\\pipe\\", 6)) {
799                 pipe_name+=6;
800         }
801
802         if (pipe_name[0] != '\\') {
803                 pipe_name = talloc_asprintf(mem_ctx, "\\%s", pipe_name);
804         }
805         
806         if (!username || !username[0] || 
807             (binding->flags & DCERPC_SCHANNEL_ANY)) {
808                 status = smbcli_full_connection(NULL, &cli, lp_netbios_name(),
809                                              binding->host, NULL, 
810                                              "ipc$", "?????", 
811                                              "", "", NULL, 0, &retry);
812         } else {
813                 status = smbcli_full_connection(NULL, &cli, lp_netbios_name(),
814                                              binding->host, NULL, 
815                                              "ipc$", "?????", 
816                                              username, domain,
817                                              password, 0, &retry);
818         }
819         if (!NT_STATUS_IS_OK(status)) {
820                 DEBUG(0,("Failed to connect to %s - %s\n", binding->host, nt_errstr(status)));
821                 talloc_destroy(mem_ctx);
822                 return status;
823         }
824
825         status = dcerpc_pipe_open_smb(p, cli->tree, pipe_name);
826         if (!NT_STATUS_IS_OK(status)) {
827                 DEBUG(0,("Failed to open pipe %s - %s\n", pipe_name, nt_errstr(status)));
828                 smbcli_tdis(cli);
829                 smbcli_shutdown(cli);
830                 talloc_destroy(mem_ctx);
831                 return status;
832         }
833         
834         /* this ensures that the reference count is decremented so
835            a pipe close will really close the link */
836         talloc_steal(*p, cli);
837
838         (*p)->flags = binding->flags;
839
840         /* remember the binding string for possible secondary connections */
841         (*p)->binding_string = dcerpc_binding_string((*p), binding);
842
843         talloc_destroy(mem_ctx);
844
845         if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
846                 status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version, 
847                                                    domain, username, password);
848         } else if (username && username[0] &&
849                    (binding->flags & (DCERPC_CONNECT|DCERPC_SIGN|DCERPC_SEAL))) {
850                 status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
851         } else {    
852                 status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
853
854         }
855
856         if (!NT_STATUS_IS_OK(status)) {
857                 DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
858                 dcerpc_pipe_close(*p);
859                 *p = NULL;
860                 return status;
861         }
862
863         return NT_STATUS_OK;
864 }
865
866 /* open a rpc connection to a rpc pipe on SMP using the binding
867    structure to determine the endpoint and options */
868 static NTSTATUS dcerpc_pipe_connect_ncalrpc(struct dcerpc_pipe **p, 
869                                                  struct dcerpc_binding *binding,
870                                                  const char *pipe_uuid, 
871                                                  uint32_t pipe_version,
872                                                  const char *domain,
873                                                  const char *username,
874                                                  const char *password)
875 {
876         NTSTATUS status;
877         TALLOC_CTX *mem_ctx = talloc_init("dcerpc_pipe_connect_ncalrpc");
878
879         /* Look up identifier using the epmapper */
880         if (!binding->endpoint) {
881                 status = dcerpc_epm_map_binding(mem_ctx, binding, pipe_uuid, pipe_version);
882                 if (!NT_STATUS_IS_OK(status)) {
883                         DEBUG(0,("Failed to map DCERPC/TCP NCALRPC identifier for '%s' - %s\n", 
884                                  pipe_uuid, nt_errstr(status)));
885                         talloc_destroy(mem_ctx);
886                         return status;
887                 }
888                 DEBUG(1,("Mapped to DCERPC/LRPC identifier %s\n", binding->endpoint));
889         }
890
891         status = dcerpc_pipe_open_pipe(p, binding->endpoint);
892
893         if (!NT_STATUS_IS_OK(status)) {
894                 DEBUG(0,("Failed to open ncalrpc pipe '%s' - %s\n", binding->endpoint, nt_errstr(status)));
895                 talloc_destroy(mem_ctx);
896                 return status;
897     }
898
899         (*p)->flags = binding->flags;
900
901         /* remember the binding string for possible secondary connections */
902         (*p)->binding_string = dcerpc_binding_string((*p), binding);
903
904         if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
905                 status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version, 
906                                                    domain, username, password);
907         } else if (username && username[0]) {
908                 status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
909         } else {    
910                 status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
911         }
912
913         if (!NT_STATUS_IS_OK(status)) {
914                 DEBUG(0,("Failed to bind to uuid %s - %s\n", 
915                          pipe_uuid, nt_errstr(status)));
916                 dcerpc_pipe_close(*p);
917                 *p = NULL;
918                 talloc_destroy(mem_ctx);
919                 return status;
920         }
921  
922         talloc_destroy(mem_ctx);
923     return status;
924 }
925
926
927
928 /* open a rpc connection to a rpc pipe on SMP using the binding
929    structure to determine the endpoint and options */
930 static NTSTATUS dcerpc_pipe_connect_ncacn_unix_stream(struct dcerpc_pipe **p, 
931                                                  struct dcerpc_binding *binding,
932                                                  const char *pipe_uuid, 
933                                                  uint32_t pipe_version,
934                                                  const char *domain,
935                                                  const char *username,
936                                                  const char *password)
937 {
938         NTSTATUS status;
939
940         if (!binding->endpoint) {
941                 DEBUG(0, ("Path to unix socket not specified\n"));
942                 return NT_STATUS_INVALID_PARAMETER;
943         }
944
945         status = dcerpc_pipe_open_unix_stream(p, binding->endpoint);
946         if (!NT_STATUS_IS_OK(status)) {
947                 DEBUG(0,("Failed to open unix socket %s - %s\n", 
948                          binding->endpoint, nt_errstr(status)));
949                 return status;
950         }
951
952         (*p)->flags = binding->flags;
953
954         /* remember the binding string for possible secondary connections */
955         (*p)->binding_string = dcerpc_binding_string((*p), binding);
956
957         if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
958                 status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version, 
959                                                    domain, username, password);
960         } else if (username && username[0]) {
961                 status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
962         } else {    
963                 status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
964         }
965
966         if (!NT_STATUS_IS_OK(status)) {
967                 DEBUG(0,("Failed to bind to uuid %s - %s\n", 
968                          pipe_uuid, nt_errstr(status)));
969                 dcerpc_pipe_close(*p);
970                 *p = NULL;
971                 return status;
972         }
973  
974     return status;
975 }
976
977 /* open a rpc connection to a rpc pipe on SMP using the binding
978    structure to determine the endpoint and options */
979 static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p, 
980                                                  struct dcerpc_binding *binding,
981                                                  const char *pipe_uuid, 
982                                                  uint32_t pipe_version,
983                                                  const char *domain,
984                                                  const char *username,
985                                                  const char *password)
986 {
987         NTSTATUS status;
988         uint32_t port = 0;
989         TALLOC_CTX *mem_ctx = talloc_init("connect_ncacn_ip_tcp");
990
991         if (!binding->endpoint) {
992                 status = dcerpc_epm_map_binding(mem_ctx, binding, 
993                                                  pipe_uuid, pipe_version);
994                 if (!NT_STATUS_IS_OK(status)) {
995                         DEBUG(0,("Failed to map DCERPC/TCP port for '%s' - %s\n", 
996                                  pipe_uuid, nt_errstr(status)));
997                         return status;
998                 }
999                 DEBUG(1,("Mapped to DCERPC/TCP port %s\n", binding->endpoint));
1000         }
1001
1002         port = atoi(binding->endpoint);
1003
1004         status = dcerpc_pipe_open_tcp(p, binding->host, port);
1005         if (!NT_STATUS_IS_OK(status)) {
1006                 DEBUG(0,("Failed to connect to %s:%d - %s\n", 
1007                          binding->host, port, nt_errstr(status)));
1008                 return status;
1009         }
1010
1011         (*p)->flags = binding->flags;
1012
1013         /* remember the binding string for possible secondary connections */
1014         (*p)->binding_string = dcerpc_binding_string((*p), binding);
1015
1016         if (username && username[0] && (binding->flags & DCERPC_SCHANNEL_ANY)) {
1017                 status = dcerpc_bind_auth_schannel(*p, pipe_uuid, pipe_version, 
1018                                                    domain, username, password);
1019         } else if (username && username[0]) {
1020                 status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version, domain, username, password);
1021         } else {    
1022                 status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
1023         }
1024
1025         if (!NT_STATUS_IS_OK(status)) {
1026                 DEBUG(0,("Failed to bind to uuid %s - %s\n", 
1027                          pipe_uuid, nt_errstr(status)));
1028                 dcerpc_pipe_close(*p);
1029                 *p = NULL;
1030                 return status;
1031         }
1032  
1033         return status;
1034 }
1035
1036
1037 /* open a rpc connection to a rpc pipe, using the specified 
1038    binding structure to determine the endpoint and options */
1039 NTSTATUS dcerpc_pipe_connect_b(struct dcerpc_pipe **p, 
1040                                struct dcerpc_binding *binding,
1041                                const char *pipe_uuid, 
1042                                uint32_t pipe_version,
1043                                const char *domain,
1044                                const char *username,
1045                                const char *password)
1046 {
1047         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
1048
1049         switch (binding->transport) {
1050         case NCACN_NP:
1051                 status = dcerpc_pipe_connect_ncacn_np(p, binding, pipe_uuid, pipe_version,
1052                                                       domain, username, password);
1053                 break;
1054         case NCACN_IP_TCP:
1055                 status = dcerpc_pipe_connect_ncacn_ip_tcp(p, binding, pipe_uuid, pipe_version,
1056                                                           domain, username, password);
1057                 break;
1058         case NCACN_UNIX_STREAM:
1059                 status = dcerpc_pipe_connect_ncacn_unix_stream(p, binding, pipe_uuid, pipe_version, domain, username, password);
1060                 break;
1061         case NCALRPC:
1062                 status = dcerpc_pipe_connect_ncalrpc(p, binding, pipe_uuid, pipe_version, domain, username, password);
1063                 break;
1064         default:
1065                 return NT_STATUS_NOT_SUPPORTED;
1066         }
1067
1068         return status;
1069 }
1070
1071
1072 /* open a rpc connection to a rpc pipe, using the specified string
1073    binding to determine the endpoint and options */
1074 NTSTATUS dcerpc_pipe_connect(struct dcerpc_pipe **p, 
1075                              const char *binding,
1076                              const char *pipe_uuid, 
1077                              uint32_t pipe_version,
1078                              const char *domain,
1079                              const char *username,
1080                              const char *password)
1081 {
1082         struct dcerpc_binding b;
1083         NTSTATUS status;
1084         TALLOC_CTX *mem_ctx;
1085
1086         mem_ctx = talloc_init("dcerpc_pipe_connect");
1087         if (!mem_ctx) return NT_STATUS_NO_MEMORY;
1088
1089         status = dcerpc_parse_binding(mem_ctx, binding, &b);
1090         if (!NT_STATUS_IS_OK(status)) {
1091                 DEBUG(0,("Failed to parse dcerpc binding '%s'\n", binding));
1092                 talloc_destroy(mem_ctx);
1093                 return status;
1094         }
1095
1096         DEBUG(3,("Using binding %s\n", dcerpc_binding_string(mem_ctx, &b)));
1097
1098         status = dcerpc_pipe_connect_b(p, &b, pipe_uuid, pipe_version, domain, username, password);
1099
1100         talloc_destroy(mem_ctx);
1101         return status;
1102 }
1103
1104
1105 /*
1106   create a secondary dcerpc connection from a primary connection
1107
1108   if the primary is a SMB connection then the secondary connection
1109   will be on the same SMB connection, but use a new fnum
1110 */
1111 NTSTATUS dcerpc_secondary_connection(struct dcerpc_pipe *p, struct dcerpc_pipe **p2,
1112                                      const char *pipe_name,
1113                                      const char *pipe_uuid,
1114                                      uint32_t pipe_version)
1115 {
1116         struct smbcli_tree *tree;
1117         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
1118         struct dcerpc_binding b;
1119
1120         switch (p->transport.transport) {
1121         case NCACN_NP:
1122                 tree = dcerpc_smb_tree(p);
1123                 if (!tree) {
1124                         return NT_STATUS_INVALID_PARAMETER;
1125                 }
1126
1127                 status = dcerpc_pipe_open_smb(p2, tree, pipe_name);
1128                 break;
1129
1130         case NCACN_IP_TCP:
1131                 status = dcerpc_parse_binding(p, p->binding_string, &b);
1132                 if (!NT_STATUS_IS_OK(status)) {
1133                         return status;
1134                 }
1135                 b.flags &= ~DCERPC_AUTH_OPTIONS;
1136                 status = dcerpc_pipe_connect_ncacn_ip_tcp(p2, &b, pipe_uuid,
1137                                                           pipe_version, NULL, 
1138                                                           NULL, NULL);
1139                 break;
1140
1141         case NCALRPC:
1142                 status = dcerpc_parse_binding(p, p->binding_string, &b);
1143                 if (!NT_STATUS_IS_OK(status)) {
1144                         return status;
1145                 }
1146                 b.flags &= ~DCERPC_AUTH_OPTIONS;
1147                 status = dcerpc_pipe_connect_ncalrpc(p2, &b, pipe_uuid, pipe_version, NULL, NULL, NULL);
1148                 break;
1149
1150         default:
1151                 return NT_STATUS_NOT_SUPPORTED;
1152         }
1153
1154         if (!NT_STATUS_IS_OK(status)) {
1155                 return status;
1156         }
1157
1158         talloc_steal(p, *p2);
1159
1160         (*p2)->flags = p->flags;
1161
1162         status = dcerpc_bind_auth_none(*p2, pipe_uuid, pipe_version);
1163         if (!NT_STATUS_IS_OK(status)) {
1164                 return status;
1165         }
1166
1167         return NT_STATUS_OK;
1168 }
1169
1170 NTSTATUS dcerpc_generic_session_key(struct dcerpc_pipe *p,
1171                                     DATA_BLOB *session_key)
1172 {
1173         /* this took quite a few CPU cycles to find ... */
1174         session_key->data = discard_const_p(unsigned char, "SystemLibraryDTC");
1175         session_key->length = 16;
1176         return NT_STATUS_OK;
1177 }
1178
1179 /*
1180   fetch the user session key - may be default (above) or the SMB session key
1181 */
1182 NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
1183                                   DATA_BLOB *session_key)
1184 {
1185         return p->security_state.session_key(p, session_key);
1186 }
1187
1188
1189 /*
1190   log a rpc packet in a format suitable for ndrdump. This is especially useful
1191   for sealed packets, where ethereal cannot easily see the contents
1192
1193   this triggers on a debug level of >= 10
1194 */
1195 void dcerpc_log_packet(const struct dcerpc_interface_table *ndr,
1196                        uint32_t opnum, uint32_t flags, DATA_BLOB *pkt)
1197 {
1198         const int num_examples = 20;
1199         int i;
1200
1201         if (DEBUGLEVEL < 10) return;
1202
1203         for (i=0;i<num_examples;i++) {
1204                 char *name=NULL;
1205                 asprintf(&name, "%s/rpclog/%s-%u.%d.%s", 
1206                          lp_lockdir(), ndr->name, opnum, i,
1207                          (flags&NDR_IN)?"in":"out");
1208                 if (name == NULL) {
1209                         return;
1210                 }
1211                 if (!file_exist(name, NULL)) {
1212                         if (file_save(name, pkt->data, pkt->length)) {
1213                                 DEBUG(10,("Logged rpc packet to %s\n", name));
1214                         }
1215                         free(name);
1216                         break;
1217                 }
1218                 free(name);
1219         }
1220 }
1221