ea00a3d798c9aa18d2f32aac341d07aa3c4104cd
[bbaumbach/samba-autobuild/.git] / librpc / rpc / binding.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    Copyright (C) Stefan Metzmacher 2014
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "../../lib/util/util_net.h"
28 #include "librpc/gen_ndr/ndr_epmapper.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/rpc/dcerpc.h"
31 #include "rpc_common.h"
32
33 #undef strcasecmp
34 #undef strncasecmp
35
36 #define MAX_PROTSEQ             10
37
38 struct dcerpc_binding {
39         enum dcerpc_transport_t transport;
40         struct ndr_syntax_id object;
41         const char *object_string;
42         const char *host;
43         const char *target_hostname;
44         const char *target_principal;
45         const char *endpoint;
46         const char **options;
47         uint32_t flags;
48         uint32_t assoc_group_id;
49         char assoc_group_string[11]; /* 0x3456789a + '\0' */
50 };
51
52 static const struct {
53         const char *name;
54         enum dcerpc_transport_t transport;
55         int num_protocols;
56         enum epm_protocol protseq[MAX_PROTSEQ];
57 } transports[] = {
58         { "ncacn_np",     NCACN_NP, 3, 
59                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB, EPM_PROTOCOL_NETBIOS }},
60         { "ncacn_ip_tcp", NCACN_IP_TCP, 3, 
61                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP, EPM_PROTOCOL_IP } }, 
62         { "ncacn_http", NCACN_HTTP, 3, 
63                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP, EPM_PROTOCOL_IP } }, 
64         { "ncadg_ip_udp", NCACN_IP_UDP, 3, 
65                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UDP, EPM_PROTOCOL_IP } },
66         { "ncalrpc", NCALRPC, 2, 
67                 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_NAMED_PIPE } },
68         { "ncacn_unix_stream", NCACN_UNIX_STREAM, 2, 
69                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_UNIX_DS } },
70         { "ncadg_unix_dgram", NCADG_UNIX_DGRAM, 2, 
71                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_UNIX_DS } },
72         { "ncacn_at_dsp", NCACN_AT_DSP, 3, 
73                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DSP } },
74         { "ncadg_at_ddp", NCADG_AT_DDP, 3, 
75                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_APPLETALK, EPM_PROTOCOL_DDP } },
76         { "ncacn_vns_ssp", NCACN_VNS_SPP, 3, 
77                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_SPP } },
78         { "ncacn_vns_ipc", NCACN_VNS_IPC, 3, 
79                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_STREETTALK, EPM_PROTOCOL_VINES_IPC }, },
80         { "ncadg_ipx", NCADG_IPX, 2,
81                 { EPM_PROTOCOL_NCADG, EPM_PROTOCOL_IPX },
82         },
83         { "ncacn_spx", NCACN_SPX, 3,
84                 /* I guess some MS programmer confused the identifier for 
85                  * EPM_PROTOCOL_UUID (0x0D or 13) with the one for 
86                  * EPM_PROTOCOL_SPX (0x13) here. -- jelmer*/
87                 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_UUID },
88         },
89 };
90
91 static const struct ncacn_option {
92         const char *name;
93         uint32_t flag;
94 } ncacn_options[] = {
95         {"sign", DCERPC_SIGN},
96         {"seal", DCERPC_SEAL},
97         {"connect", DCERPC_CONNECT},
98         {"spnego", DCERPC_AUTH_SPNEGO},
99         {"ntlm", DCERPC_AUTH_NTLM},
100         {"krb5", DCERPC_AUTH_KRB5},
101         {"schannel", DCERPC_SCHANNEL},
102         {"validate", DCERPC_DEBUG_VALIDATE_BOTH},
103         {"print", DCERPC_DEBUG_PRINT_BOTH},
104         {"padcheck", DCERPC_DEBUG_PAD_CHECK},
105         {"bigendian", DCERPC_PUSH_BIGENDIAN},
106         {"smb2", DCERPC_SMB2},
107         {"ndr64", DCERPC_NDR64},
108 };
109
110 static const struct ncacn_option *ncacn_option_by_name(const char *name)
111 {
112         size_t i;
113
114         for (i=0; i<ARRAY_SIZE(ncacn_options); i++) {
115                 int ret;
116
117                 ret = strcasecmp(ncacn_options[i].name, name);
118                 if (ret != 0) {
119                         continue;
120                 }
121
122                 return &ncacn_options[i];
123         }
124
125         return NULL;
126 }
127
128 const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
129 {
130         struct ndr_syntax_id syntax;
131         NTSTATUS status;
132
133         switch(epm_floor->lhs.protocol) {
134                 case EPM_PROTOCOL_UUID:
135                         status = dcerpc_floor_get_lhs_data(epm_floor, &syntax);
136                         if (NT_STATUS_IS_OK(status)) {
137                                 /* lhs is used: UUID */
138                                 char *uuidstr;
139
140                                 if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr.uuid)) {
141                                         return "NDR";
142                                 } 
143
144                                 if (GUID_equal(&syntax.uuid, &ndr_transfer_syntax_ndr64.uuid)) {
145                                         return "NDR64";
146                                 } 
147
148                                 uuidstr = GUID_string(mem_ctx, &syntax.uuid);
149
150                                 return talloc_asprintf(mem_ctx, " uuid %s/0x%02x", uuidstr, syntax.if_version);
151                         } else { /* IPX */
152                                 return talloc_asprintf(mem_ctx, "IPX:%s", 
153                                                 data_blob_hex_string_upper(mem_ctx, &epm_floor->rhs.uuid.unknown));
154                         }
155
156                 case EPM_PROTOCOL_NCACN:
157                         return "RPC-C";
158
159                 case EPM_PROTOCOL_NCADG:
160                         return "RPC";
161
162                 case EPM_PROTOCOL_NCALRPC:
163                         return "NCALRPC";
164
165                 case EPM_PROTOCOL_DNET_NSP:
166                         return "DNET/NSP";
167
168                 case EPM_PROTOCOL_IP:
169                         return talloc_asprintf(mem_ctx, "IP:%s", epm_floor->rhs.ip.ipaddr);
170
171                 case EPM_PROTOCOL_NAMED_PIPE:
172                         return talloc_asprintf(mem_ctx, "NAMED-PIPE:%s", epm_floor->rhs.named_pipe.path);
173
174                 case EPM_PROTOCOL_SMB:
175                         return talloc_asprintf(mem_ctx, "SMB:%s", epm_floor->rhs.smb.unc);
176
177                 case EPM_PROTOCOL_UNIX_DS:
178                         return talloc_asprintf(mem_ctx, "Unix:%s", epm_floor->rhs.unix_ds.path);
179
180                 case EPM_PROTOCOL_NETBIOS:
181                         return talloc_asprintf(mem_ctx, "NetBIOS:%s", epm_floor->rhs.netbios.name);
182
183                 case EPM_PROTOCOL_NETBEUI:
184                         return "NETBeui";
185
186                 case EPM_PROTOCOL_SPX:
187                         return "SPX";
188
189                 case EPM_PROTOCOL_NB_IPX:
190                         return "NB_IPX";
191
192                 case EPM_PROTOCOL_HTTP:
193                         return talloc_asprintf(mem_ctx, "HTTP:%d", epm_floor->rhs.http.port);
194
195                 case EPM_PROTOCOL_TCP:
196                         return talloc_asprintf(mem_ctx, "TCP:%d", epm_floor->rhs.tcp.port);
197
198                 case EPM_PROTOCOL_UDP:
199                         return talloc_asprintf(mem_ctx, "UDP:%d", epm_floor->rhs.udp.port);
200
201                 default:
202                         return talloc_asprintf(mem_ctx, "UNK(%02x):", epm_floor->lhs.protocol);
203         }
204 }
205
206
207 /*
208   form a binding string from a binding structure
209 */
210 _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
211 {
212         char *s = talloc_strdup(mem_ctx, "");
213         char *o = s;
214         int i;
215         const char *t_name = NULL;
216         bool option_section = false;
217         const char *target_hostname = NULL;
218
219         if (b->transport != NCA_UNKNOWN) {
220                 t_name = derpc_transport_string_by_transport(b->transport);
221                 if (!t_name) {
222                         talloc_free(o);
223                         return NULL;
224                 }
225         }
226
227         if (!GUID_all_zero(&b->object.uuid)) { 
228                 o = s;
229                 s = talloc_asprintf_append_buffer(s, "%s@",
230                                     GUID_string(mem_ctx, &b->object.uuid));
231                 if (s == NULL) {
232                         talloc_free(o);
233                         return NULL;
234                 }
235         }
236
237         if (t_name != NULL) {
238                 o = s;
239                 s = talloc_asprintf_append_buffer(s, "%s:", t_name);
240                 if (s == NULL) {
241                         talloc_free(o);
242                         return NULL;
243                 }
244         }
245
246         if (b->host) {
247                 o = s;
248                 s = talloc_asprintf_append_buffer(s, "%s", b->host);
249                 if (s == NULL) {
250                         talloc_free(o);
251                         return NULL;
252                 }
253         }
254
255         target_hostname = b->target_hostname;
256         if (target_hostname != NULL && b->host != NULL) {
257                 if (strcmp(target_hostname, b->host) == 0) {
258                         target_hostname = NULL;
259                 }
260         }
261
262         if (b->endpoint) {
263                 option_section = true;
264         } else if (target_hostname) {
265                 option_section = true;
266         } else if (b->target_principal) {
267                 option_section = true;
268         } else if (b->assoc_group_id != 0) {
269                 option_section = true;
270         } else if (b->options) {
271                 option_section = true;
272         } else if (b->flags) {
273                 option_section = true;
274         }
275
276         if (!option_section) {
277                 return s;
278         }
279
280         o = s;
281         s = talloc_asprintf_append_buffer(s, "[");
282         if (s == NULL) {
283                 talloc_free(o);
284                 return NULL;
285         }
286
287         if (b->endpoint) {
288                 o = s;
289                 s = talloc_asprintf_append_buffer(s, "%s", b->endpoint);
290                 if (s == NULL) {
291                         talloc_free(o);
292                         return NULL;
293                 }
294         }
295
296         for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
297                 if (!(b->flags & ncacn_options[i].flag)) {
298                         continue;
299                 }
300
301                 o = s;
302                 s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
303                 if (s == NULL) {
304                         talloc_free(o);
305                         return NULL;
306                 }
307         }
308
309         if (target_hostname) {
310                 o = s;
311                 s = talloc_asprintf_append_buffer(s, ",target_hostname=%s",
312                                                   b->target_hostname);
313                 if (s == NULL) {
314                         talloc_free(o);
315                         return NULL;
316                 }
317         }
318
319         if (b->target_principal) {
320                 o = s;
321                 s = talloc_asprintf_append_buffer(s, ",target_principal=%s",
322                                                   b->target_principal);
323                 if (s == NULL) {
324                         talloc_free(o);
325                         return NULL;
326                 }
327         }
328
329         if (b->assoc_group_id != 0) {
330                 o = s;
331                 s = talloc_asprintf_append_buffer(s, ",assoc_group_id=0x%08x",
332                                                   b->assoc_group_id);
333                 if (s == NULL) {
334                         talloc_free(o);
335                         return NULL;
336                 }
337         }
338
339         for (i=0;b->options && b->options[i];i++) {
340                 o = s;
341                 s = talloc_asprintf_append_buffer(s, ",%s", b->options[i]);
342                 if (s == NULL) {
343                         talloc_free(o);
344                         return NULL;
345                 }
346         }
347
348         o = s;
349         s = talloc_asprintf_append_buffer(s, "]");
350         if (s == NULL) {
351                 talloc_free(o);
352                 return NULL;
353         }
354
355         return s;
356 }
357
358 /*
359   parse a binding string into a dcerpc_binding structure
360 */
361 _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *_s, struct dcerpc_binding **b_out)
362 {
363         char *_t;
364         struct dcerpc_binding *b;
365         char *s;
366         char *options = NULL;
367         char *p;
368         size_t i;
369         NTSTATUS status;
370
371         b = talloc_zero(mem_ctx, struct dcerpc_binding);
372         if (!b) {
373                 return NT_STATUS_NO_MEMORY;
374         }
375
376         _t = talloc_strdup(b, _s);
377         if (_t == NULL) {
378                 talloc_free(b);
379                 return NT_STATUS_NO_MEMORY;
380         }
381
382         s = _t;
383
384         p = strchr(s, '[');
385         if (p) {
386                 *p = '\0';
387                 options = p + 1;
388                 if (options[strlen(options)-1] != ']') {
389                         talloc_free(b);
390                         return NT_STATUS_INVALID_PARAMETER_MIX;
391                 }
392                 options[strlen(options)-1] = 0;
393         }
394
395         p = strchr(s, '@');
396
397         if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
398                 *p = '\0';
399
400                 status = dcerpc_binding_set_string_option(b, "object", s);
401                 if (!NT_STATUS_IS_OK(status)) {
402                         talloc_free(b);
403                         return status;
404                 }
405
406                 s = p + 1;
407         }
408
409         p = strchr(s, ':');
410
411         if (p == NULL) {
412                 b->transport = NCA_UNKNOWN;
413         } else if (is_ipaddress_v6(s)) {
414                 b->transport = NCA_UNKNOWN;
415         } else {
416                 *p = '\0';
417
418                 status = dcerpc_binding_set_string_option(b, "transport", s);
419                 if (!NT_STATUS_IS_OK(status)) {
420                         talloc_free(b);
421                         return status;
422                 }
423
424                 s = p + 1;
425         }
426
427         if (strlen(s) > 0) {
428                 status = dcerpc_binding_set_string_option(b, "host", s);
429                 if (!NT_STATUS_IS_OK(status)) {
430                         talloc_free(b);
431                         return status;
432                 }
433
434                 b->target_hostname = talloc_strdup(b, b->host);
435                 if (b->target_hostname == NULL) {
436                         talloc_free(b);
437                         return NT_STATUS_NO_MEMORY;
438                 }
439         }
440
441         for (i=0; options != NULL; i++) {
442                 const char *name = options;
443                 const char *value = NULL;
444
445                 p = strchr(options, ',');
446                 if (p != NULL) {
447                         *p = '\0';
448                         options = p+1;
449                 } else {
450                         options = NULL;
451                 }
452
453                 p = strchr(name, '=');
454                 if (p != NULL) {
455                         *p = '\0';
456                         value = p + 1;
457                 }
458
459                 if (value == NULL) {
460                         /*
461                          * If it's not a key=value pair
462                          * it might be a ncacn_option
463                          * or if it's the first option
464                          * it's the endpoint.
465                          */
466                         const struct ncacn_option *no = NULL;
467
468                         value = name;
469
470                         no = ncacn_option_by_name(name);
471                         if (no == NULL) {
472                                 if (i > 0) {
473                                         /*
474                                          * we don't allow unknown options
475                                          */
476                                         return NT_STATUS_INVALID_PARAMETER_MIX;
477                                 }
478
479                                 /*
480                                  * This is the endpoint
481                                  */
482                                 name = "endpoint";
483                                 if (strlen(value) == 0) {
484                                         value = NULL;
485                                 }
486                         }
487                 }
488
489                 status = dcerpc_binding_set_string_option(b, name, value);
490                 if (!NT_STATUS_IS_OK(status)) {
491                         talloc_free(b);
492                         return status;
493                 }
494         }
495
496         talloc_free(_t);
497         *b_out = b;
498         return NT_STATUS_OK;
499 }
500
501 _PUBLIC_ struct GUID dcerpc_binding_get_object(const struct dcerpc_binding *b)
502 {
503         return b->object.uuid;
504 }
505
506 _PUBLIC_ NTSTATUS dcerpc_binding_set_object(struct dcerpc_binding *b,
507                                             struct GUID object)
508 {
509         char *tmp = discard_const_p(char, b->object_string);
510
511         if (GUID_all_zero(&object)) {
512                 talloc_free(tmp);
513                 b->object_string = NULL;
514                 ZERO_STRUCT(b->object);
515                 return NT_STATUS_OK;
516         }
517
518         b->object_string = GUID_string(b, &object);
519         if (b->object_string == NULL) {
520                 b->object_string = tmp;
521                 return NT_STATUS_NO_MEMORY;
522         }
523         talloc_free(tmp);
524
525         ZERO_STRUCT(b->object);
526         b->object.uuid = object;
527         return NT_STATUS_OK;
528 }
529
530 _PUBLIC_ enum dcerpc_transport_t dcerpc_binding_get_transport(const struct dcerpc_binding *b)
531 {
532         return b->transport;
533 }
534
535 _PUBLIC_ NTSTATUS dcerpc_binding_set_transport(struct dcerpc_binding *b,
536                                                enum dcerpc_transport_t transport)
537 {
538         NTSTATUS status;
539
540         /*
541          * TODO: we may want to check the transport value is
542          * wellknown.
543          */
544         if (b->transport == transport) {
545                 return NT_STATUS_OK;
546         }
547
548         /*
549          * This implicitly resets the endpoint
550          * as the endpoint is transport specific.
551          *
552          * It also resets the assoc group as it's
553          * also endpoint specific.
554          *
555          * TODO: in future we may reset more options
556          * here.
557          */
558         status = dcerpc_binding_set_string_option(b, "endpoint", NULL);
559         if (!NT_STATUS_IS_OK(status)) {
560                 return status;
561         }
562
563         b->assoc_group_id = 0;
564
565         b->transport = transport;
566         return NT_STATUS_OK;
567 }
568
569 _PUBLIC_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
570                                            enum dcerpc_AuthType *_auth_type,
571                                            enum dcerpc_AuthLevel *_auth_level)
572 {
573         enum dcerpc_AuthType auth_type;
574         enum dcerpc_AuthLevel auth_level;
575
576         if (b->flags & DCERPC_AUTH_SPNEGO) {
577                 auth_type = DCERPC_AUTH_TYPE_SPNEGO;
578         } else if (b->flags & DCERPC_AUTH_KRB5) {
579                 auth_type = DCERPC_AUTH_TYPE_KRB5;
580         } else if (b->flags & DCERPC_SCHANNEL) {
581                 auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
582         } else if (b->flags & DCERPC_AUTH_NTLM) {
583                 auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
584         } else {
585                 auth_type = DCERPC_AUTH_TYPE_NONE;
586         }
587
588         if (b->flags & DCERPC_SEAL) {
589                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
590         } else if (b->flags & DCERPC_SIGN) {
591                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
592         } else if (b->flags & DCERPC_CONNECT) {
593                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
594         } else if (auth_type != DCERPC_AUTH_TYPE_NONE) {
595                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
596         } else {
597                 auth_level = DCERPC_AUTH_LEVEL_NONE;
598         }
599
600         if (_auth_type == NULL) {
601                 *_auth_type = auth_type;
602         }
603
604         if (_auth_level == NULL) {
605                 *_auth_level = auth_level;
606         }
607 }
608
609 _PUBLIC_ uint32_t dcerpc_binding_get_assoc_group_id(const struct dcerpc_binding *b)
610 {
611         return b->assoc_group_id;
612 }
613
614 _PUBLIC_ NTSTATUS dcerpc_binding_set_assoc_group_id(struct dcerpc_binding *b,
615                                                     uint32_t assoc_group_id)
616 {
617         b->assoc_group_id = assoc_group_id;
618         return NT_STATUS_OK;
619 }
620
621 _PUBLIC_ struct ndr_syntax_id dcerpc_binding_get_abstract_syntax(const struct dcerpc_binding *b)
622 {
623         /*
624          * For now we just use object, until all callers are fixed.
625          */
626         return b->object;
627 }
628
629 _PUBLIC_ NTSTATUS dcerpc_binding_set_abstract_syntax(struct dcerpc_binding *b,
630                                                      const struct ndr_syntax_id *syntax)
631 {
632         NTSTATUS status;
633         struct GUID object;
634
635         /*
636          * For now we just use object, until all callers are fixed.
637          */
638
639         if (syntax != NULL) {
640                 object = syntax->uuid;
641         } else {
642                 object = GUID_zero();
643         }
644
645         /*
646          * This sets also the string
647          */
648         status = dcerpc_binding_set_object(b, object);
649         if (!NT_STATUS_IS_OK(status)) {
650                 return status;
651         }
652
653         if (syntax != NULL) {
654                 /*
655                  * Here we need to reset the whole ndr_syntax_id
656                  * structure including the .if_version
657                  */
658                 b->object = *syntax;
659         }
660
661         return NT_STATUS_OK;
662 }
663
664 _PUBLIC_ const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
665                                                       const char *name)
666 {
667         struct {
668                 const char *name;
669                 const char *value;
670 #define _SPECIAL(x) { .name = #x, .value = b->x, }
671         } specials[] = {
672                 { .name = "object", .value = b->object_string, },
673                 _SPECIAL(host),
674                 _SPECIAL(endpoint),
675                 _SPECIAL(target_hostname),
676                 _SPECIAL(target_principal),
677 #undef _SPECIAL
678         };
679         const struct ncacn_option *no = NULL;
680         size_t name_len = strlen(name);
681         size_t i;
682         int ret;
683
684         ret = strcmp(name, "transport");
685         if (ret == 0) {
686                 return derpc_transport_string_by_transport(b->transport);
687         }
688
689         ret = strcmp(name, "assoc_group_id");
690         if (ret == 0) {
691                 char *tmp = discard_const_p(char, b->assoc_group_string);
692
693                 if (b->assoc_group_id == 0) {
694                         return NULL;
695                 }
696
697                 snprintf(tmp, sizeof(b->assoc_group_string),
698                          "0x%08x", b->assoc_group_id);
699                 return (const char *)b->assoc_group_string;
700         }
701
702         for (i=0; i < ARRAY_SIZE(specials); i++) {
703                 ret = strcmp(specials[i].name, name);
704                 if (ret != 0) {
705                         continue;
706                 }
707
708                 return specials[i].value;
709         }
710
711         no = ncacn_option_by_name(name);
712         if (no != NULL) {
713                 if (b->flags & no->flag) {
714                         return no->name;
715                 }
716
717                 return NULL;
718         }
719
720         if (b->options == NULL) {
721                 return NULL;
722         }
723
724         for (i=0; b->options[i]; i++) {
725                 const char *o = b->options[i];
726                 const char *vs = NULL;
727
728                 ret = strncmp(name, o, name_len);
729                 if (ret != 0) {
730                         continue;
731                 }
732
733                 if (o[name_len] != '=') {
734                         continue;
735                 }
736
737                 vs = &o[name_len + 1];
738
739                 return vs;
740         }
741
742         return NULL;
743 }
744
745 _PUBLIC_ char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
746                                                  const struct dcerpc_binding *b,
747                                                  const char *name)
748 {
749         const char *c = dcerpc_binding_get_string_option(b, name);
750         char *v;
751
752         if (c == NULL) {
753                 errno = ENOENT;
754                 return NULL;
755         }
756
757         v = talloc_strdup(mem_ctx, c);
758         if (v == NULL) {
759                 errno = ENOMEM;
760                 return NULL;
761         }
762
763         return v;
764 }
765
766 _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
767                                                    const char *name,
768                                                    const char *value)
769 {
770         struct {
771                 const char *name;
772                 const char **ptr;
773 #define _SPECIAL(x) { .name = #x, .ptr = &b->x, }
774         } specials[] = {
775                 _SPECIAL(host),
776                 _SPECIAL(endpoint),
777                 _SPECIAL(target_hostname),
778                 _SPECIAL(target_principal),
779 #undef _SPECIAL
780         };
781         const struct ncacn_option *no = NULL;
782         size_t name_len = strlen(name);
783         const char *opt = NULL;
784         char *tmp;
785         size_t i;
786         int ret;
787
788         /*
789          * Note: value == NULL, means delete it.
790          * value != NULL means add or reset.
791          */
792
793         ret = strcmp(name, "transport");
794         if (ret == 0) {
795                 enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
796
797                 if (t == NCA_UNKNOWN && value != NULL) {
798                         return NT_STATUS_INVALID_PARAMETER_MIX;
799                 }
800
801                 return dcerpc_binding_set_transport(b, t);
802         }
803
804         ret = strcmp(name, "object");
805         if (ret == 0) {
806                 NTSTATUS status;
807                 struct GUID uuid = GUID_zero();
808
809                 if (value != NULL) {
810                         DATA_BLOB blob;
811                         blob = data_blob_string_const(value);
812                         if (blob.length != 36) {
813                                 return NT_STATUS_INVALID_PARAMETER_MIX;
814                         }
815
816                         status = GUID_from_data_blob(&blob, &uuid);
817                         if (!NT_STATUS_IS_OK(status)) {
818                                 return status;
819                         }
820                 }
821
822                 return dcerpc_binding_set_object(b, uuid);
823         }
824
825         ret = strcmp(name, "assoc_group_id");
826         if (ret == 0) {
827                 uint32_t assoc_group_id = 0;
828
829                 if (value != NULL) {
830                         char c;
831
832                         ret = sscanf(value, "0x%08x%c", &assoc_group_id, &c);
833                         if (ret != 1) {
834                                 return NT_STATUS_INVALID_PARAMETER_MIX;
835                         }
836                 }
837
838                 return dcerpc_binding_set_assoc_group_id(b, assoc_group_id);
839         }
840
841         for (i=0; i < ARRAY_SIZE(specials); i++) {
842                 ret = strcmp(specials[i].name, name);
843                 if (ret != 0) {
844                         continue;
845                 }
846
847                 tmp = discard_const_p(char, *specials[i].ptr);
848
849                 if (value == NULL) {
850                         talloc_free(tmp);
851                         *specials[i].ptr = NULL;
852                         return NT_STATUS_OK;
853                 }
854
855                 if (value[0] == '\0') {
856                         return NT_STATUS_INVALID_PARAMETER_MIX;
857                 }
858
859                 *specials[i].ptr = talloc_strdup(b, value);
860                 if (*specials[i].ptr == NULL) {
861                         *specials[i].ptr = tmp;
862                         return NT_STATUS_NO_MEMORY;
863                 }
864                 talloc_free(tmp);
865
866                 return NT_STATUS_OK;
867         }
868
869         no = ncacn_option_by_name(name);
870         if (no != NULL) {
871                 if (value == NULL) {
872                         b->flags &= ~no->flag;
873                         return NT_STATUS_OK;
874                 }
875
876                 ret = strcasecmp(no->name, value);
877                 if (ret != 0) {
878                         return NT_STATUS_INVALID_PARAMETER_MIX;
879                 }
880
881                 b->flags |= no->flag;
882                 return NT_STATUS_OK;
883         }
884
885         for (i=0; b->options && b->options[i]; i++) {
886                 const char *o = b->options[i];
887
888                 ret = strncmp(name, o, name_len);
889                 if (ret != 0) {
890                         continue;
891                 }
892
893                 if (o[name_len] != '=') {
894                         continue;
895                 }
896
897                 opt = o;
898                 break;
899         }
900
901         if (opt == NULL) {
902                 const char **n;
903
904                 if (value == NULL) {
905                         return NT_STATUS_OK;
906                 }
907
908                 n = talloc_realloc(b, b->options, const char *, i + 2);
909                 if (n == NULL) {
910                         return NT_STATUS_NO_MEMORY;
911                 }
912                 n[i] = NULL;
913                 n[i + 1] = NULL;
914                 b->options = n;
915         }
916
917         tmp = discard_const_p(char, opt);
918
919         if (value == NULL) {
920                 for (;b->options[i];i++) {
921                         b->options[i] = b->options[i+1];
922                 }
923                 talloc_free(tmp);
924                 return NT_STATUS_OK;
925         }
926
927         b->options[i] = talloc_asprintf(b->options, "%s=%s",
928                                         name, value);
929         if (b->options[i] == NULL) {
930                 b->options[i] = tmp;
931                 return NT_STATUS_NO_MEMORY;
932         }
933
934         return NT_STATUS_OK;
935 }
936
937 _PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
938 {
939         return b->flags;
940 }
941
942 _PUBLIC_ NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
943                                            uint32_t additional,
944                                            uint32_t clear)
945 {
946         /*
947          * TODO: in future we may want to reject invalid combinations
948          */
949         b->flags &= ~clear;
950         b->flags |= additional;
951
952         return NT_STATUS_OK;
953 }
954
955 _PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor,
956                                             struct ndr_syntax_id *syntax)
957 {
958         TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
959         struct ndr_pull *ndr;
960         enum ndr_err_code ndr_err;
961         uint16_t if_version=0;
962
963         ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
964         if (ndr == NULL) {
965                 talloc_free(mem_ctx);
966                 return NT_STATUS_NO_MEMORY;
967         }
968         ndr->flags |= LIBNDR_FLAG_NOALIGN;
969
970         ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
971         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
972                 talloc_free(mem_ctx);
973                 return ndr_map_error2ntstatus(ndr_err);
974         }
975
976         ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
977         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
978                 talloc_free(mem_ctx);
979                 return ndr_map_error2ntstatus(ndr_err);
980         }
981
982         syntax->if_version = if_version;
983
984         talloc_free(mem_ctx);
985
986         return NT_STATUS_OK;
987 }
988
989 static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
990 {
991         DATA_BLOB blob;
992         enum ndr_err_code ndr_err;
993         struct ndr_push *ndr;
994
995         ndr = ndr_push_init_ctx(mem_ctx);
996         if (ndr == NULL) {
997                 return data_blob_null;
998         }
999
1000         ndr->flags |= LIBNDR_FLAG_NOALIGN;
1001
1002         ndr_err = ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
1003         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1004                 return data_blob_null;
1005         }
1006         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
1007         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1008                 return data_blob_null;
1009         }
1010
1011         blob = ndr_push_blob(ndr);
1012         talloc_steal(mem_ctx, blob.data);
1013         talloc_free(ndr);
1014         return blob;
1015 }
1016
1017 static bool dcerpc_floor_pack_rhs_if_version_data(
1018         TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax,
1019         DATA_BLOB *pblob)
1020 {
1021         DATA_BLOB blob;
1022         struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
1023         enum ndr_err_code ndr_err;
1024
1025         if (ndr == NULL) {
1026                 return false;
1027         }
1028
1029         ndr->flags |= LIBNDR_FLAG_NOALIGN;
1030
1031         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version >> 16);
1032         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1033                 return false;
1034         }
1035
1036         blob = ndr_push_blob(ndr);
1037         talloc_steal(mem_ctx, blob.data);
1038         talloc_free(ndr);
1039         *pblob = blob;
1040         return true;
1041 }
1042
1043 char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
1044 {
1045         switch (epm_floor->lhs.protocol) {
1046         case EPM_PROTOCOL_TCP:
1047                 if (epm_floor->rhs.tcp.port == 0) return NULL;
1048                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.tcp.port);
1049
1050         case EPM_PROTOCOL_UDP:
1051                 if (epm_floor->rhs.udp.port == 0) return NULL;
1052                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.udp.port);
1053
1054         case EPM_PROTOCOL_HTTP:
1055                 if (epm_floor->rhs.http.port == 0) return NULL;
1056                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.http.port);
1057
1058         case EPM_PROTOCOL_IP:
1059                 return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
1060
1061         case EPM_PROTOCOL_NCACN:
1062                 return NULL;
1063
1064         case EPM_PROTOCOL_NCADG:
1065                 return NULL;
1066
1067         case EPM_PROTOCOL_SMB:
1068                 if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
1069                 return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
1070
1071         case EPM_PROTOCOL_NAMED_PIPE:
1072                 if (strlen(epm_floor->rhs.named_pipe.path) == 0) return NULL;
1073                 return talloc_strdup(mem_ctx, epm_floor->rhs.named_pipe.path);
1074
1075         case EPM_PROTOCOL_NETBIOS:
1076                 if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
1077                 return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
1078
1079         case EPM_PROTOCOL_NCALRPC:
1080                 return NULL;
1081
1082         case EPM_PROTOCOL_VINES_SPP:
1083                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_spp.port);
1084
1085         case EPM_PROTOCOL_VINES_IPC:
1086                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_ipc.port);
1087
1088         case EPM_PROTOCOL_STREETTALK:
1089                 return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
1090
1091         case EPM_PROTOCOL_UNIX_DS:
1092                 if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
1093                 return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
1094
1095         case EPM_PROTOCOL_NULL:
1096                 return NULL;
1097
1098         default:
1099                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1100                 break;
1101         }
1102
1103         return NULL;
1104 }
1105
1106 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx, 
1107                                           struct epm_floor *epm_floor,  
1108                                           const char *data)
1109 {
1110         if (data == NULL) {
1111                 data = "";
1112         }
1113
1114         switch (epm_floor->lhs.protocol) {
1115         case EPM_PROTOCOL_TCP:
1116                 epm_floor->rhs.tcp.port = atoi(data);
1117                 return NT_STATUS_OK;
1118
1119         case EPM_PROTOCOL_UDP:
1120                 epm_floor->rhs.udp.port = atoi(data);
1121                 return NT_STATUS_OK;
1122
1123         case EPM_PROTOCOL_HTTP:
1124                 epm_floor->rhs.http.port = atoi(data);
1125                 return NT_STATUS_OK;
1126
1127         case EPM_PROTOCOL_IP:
1128                 if (!is_ipaddress_v4(data)) {
1129                         data = "0.0.0.0";
1130                 }
1131                 epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
1132                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
1133                 return NT_STATUS_OK;
1134
1135         case EPM_PROTOCOL_NCACN:
1136                 epm_floor->rhs.ncacn.minor_version = 0;
1137                 return NT_STATUS_OK;
1138
1139         case EPM_PROTOCOL_NCADG:
1140                 epm_floor->rhs.ncadg.minor_version = 0;
1141                 return NT_STATUS_OK;
1142
1143         case EPM_PROTOCOL_SMB:
1144                 epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
1145                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
1146                 return NT_STATUS_OK;
1147
1148         case EPM_PROTOCOL_NAMED_PIPE:
1149                 epm_floor->rhs.named_pipe.path = talloc_strdup(mem_ctx, data);
1150                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.named_pipe.path);
1151                 return NT_STATUS_OK;
1152
1153         case EPM_PROTOCOL_NETBIOS:
1154                 epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
1155                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
1156                 return NT_STATUS_OK;
1157
1158         case EPM_PROTOCOL_NCALRPC:
1159                 return NT_STATUS_OK;
1160
1161         case EPM_PROTOCOL_VINES_SPP:
1162                 epm_floor->rhs.vines_spp.port = atoi(data);
1163                 return NT_STATUS_OK;
1164
1165         case EPM_PROTOCOL_VINES_IPC:
1166                 epm_floor->rhs.vines_ipc.port = atoi(data);
1167                 return NT_STATUS_OK;
1168
1169         case EPM_PROTOCOL_STREETTALK:
1170                 epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
1171                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
1172                 return NT_STATUS_OK;
1173
1174         case EPM_PROTOCOL_UNIX_DS:
1175                 epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
1176                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
1177                 return NT_STATUS_OK;
1178
1179         case EPM_PROTOCOL_NULL:
1180                 return NT_STATUS_OK;
1181
1182         default:
1183                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1184                 break;
1185         }
1186
1187         return NT_STATUS_NOT_SUPPORTED;
1188 }
1189
1190 enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
1191 {
1192         int i;
1193
1194         /* Find a transport that has 'prot' as 4th protocol */
1195         for (i=0;i<ARRAY_SIZE(transports);i++) {
1196                 if (transports[i].num_protocols >= 2 && 
1197                         transports[i].protseq[1] == prot) {
1198                         return transports[i].transport;
1199                 }
1200         }
1201
1202         /* Unknown transport */
1203         return (unsigned int)-1;
1204 }
1205
1206 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower)
1207 {
1208         int i;
1209
1210         /* Find a transport that matches this tower */
1211         for (i=0;i<ARRAY_SIZE(transports);i++) {
1212                 int j;
1213                 if (transports[i].num_protocols != tower->num_floors - 2) {
1214                         continue; 
1215                 }
1216
1217                 for (j = 0; j < transports[i].num_protocols; j++) {
1218                         if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
1219                                 break;
1220                         }
1221                 }
1222
1223                 if (j == transports[i].num_protocols) {
1224                         return transports[i].transport;
1225                 }
1226         }
1227
1228         /* Unknown transport */
1229         return (unsigned int)-1;
1230 }
1231
1232 _PUBLIC_ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t)
1233 {
1234         int i;
1235
1236         for (i=0; i<ARRAY_SIZE(transports); i++) {
1237                 if (t == transports[i].transport) {
1238                         return transports[i].name;
1239                 }
1240         }
1241         return NULL;
1242 }
1243
1244 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_name(const char *name)
1245 {
1246         size_t i;
1247
1248         if (name == NULL) {
1249                 return NCA_UNKNOWN;
1250         }
1251
1252         for (i=0; i<ARRAY_SIZE(transports);i++) {
1253                 if (strcasecmp(name, transports[i].name) == 0) {
1254                         return transports[i].transport;
1255                 }
1256         }
1257
1258         return NCA_UNKNOWN;
1259 }
1260
1261 _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
1262                                             struct epm_tower *tower,
1263                                             struct dcerpc_binding **b_out)
1264 {
1265         NTSTATUS status;
1266         struct dcerpc_binding *b;
1267         enum dcerpc_transport_t transport;
1268         struct ndr_syntax_id abstract_syntax;
1269         char *endpoint = NULL;
1270         char *host = NULL;
1271
1272         /*
1273          * A tower needs to have at least 4 floors to carry useful
1274          * information. Floor 3 is the transport identifier which defines
1275          * how many floors are required at least.
1276          */
1277         if (tower->num_floors < 4) {
1278                 return NT_STATUS_INVALID_PARAMETER;
1279         }
1280
1281         status = dcerpc_parse_binding(mem_ctx, "", &b);
1282         if (!NT_STATUS_IS_OK(status)) {
1283                 return status;
1284         }
1285
1286         transport = dcerpc_transport_by_tower(tower);
1287         if (transport == NCA_UNKNOWN) {
1288                 talloc_free(b);
1289                 return NT_STATUS_NOT_SUPPORTED;
1290         }
1291
1292         status = dcerpc_binding_set_transport(b, transport);
1293         if (!NT_STATUS_IS_OK(status)) {
1294                 talloc_free(b);
1295                 return status;
1296         }
1297
1298         /* Set abstract syntax */
1299         status = dcerpc_floor_get_lhs_data(&tower->floors[0], &abstract_syntax);
1300         if (!NT_STATUS_IS_OK(status)) {
1301                 talloc_free(b);
1302                 return status;
1303         }
1304
1305         status = dcerpc_binding_set_abstract_syntax(b, &abstract_syntax);
1306         if (!NT_STATUS_IS_OK(status)) {
1307                 talloc_free(b);
1308                 return status;
1309         }
1310
1311         /* Ignore floor 1, it contains the NDR version info */
1312
1313         /* Set endpoint */
1314         errno = 0;
1315         if (tower->num_floors >= 4) {
1316                 endpoint = dcerpc_floor_get_rhs_data(b, &tower->floors[3]);
1317         }
1318         if (errno != 0) {
1319                 int saved_errno = errno;
1320                 talloc_free(b);
1321                 return map_nt_error_from_unix_common(saved_errno);
1322         }
1323
1324         status = dcerpc_binding_set_string_option(b, "endpoint", endpoint);
1325         if (!NT_STATUS_IS_OK(status)) {
1326                 talloc_free(b);
1327                 return status;
1328         }
1329         TALLOC_FREE(endpoint);
1330
1331         /* Set network address */
1332         errno = 0;
1333         if (tower->num_floors >= 5) {
1334                 host = dcerpc_floor_get_rhs_data(b, &tower->floors[4]);
1335         }
1336         if (errno != 0) {
1337                 int saved_errno = errno;
1338                 talloc_free(b);
1339                 return map_nt_error_from_unix_common(saved_errno);
1340         }
1341
1342         status = dcerpc_binding_set_string_option(b, "host", host);
1343         if (!NT_STATUS_IS_OK(status)) {
1344                 talloc_free(b);
1345                 return status;
1346         }
1347         status = dcerpc_binding_set_string_option(b, "target_hostname", host);
1348         if (!NT_STATUS_IS_OK(status)) {
1349                 talloc_free(b);
1350                 return status;
1351         }
1352         TALLOC_FREE(host);
1353
1354         *b_out = b;
1355         return NT_STATUS_OK;
1356 }
1357
1358 _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
1359                                                    const struct dcerpc_binding *b)
1360 {
1361         struct dcerpc_binding *n;
1362         uint32_t count;
1363
1364         n = talloc_zero(mem_ctx, struct dcerpc_binding);
1365         if (n == NULL) {
1366                 return NULL;
1367         }
1368
1369         n->transport = b->transport;
1370         n->object = b->object;
1371         n->flags = b->flags;
1372         n->assoc_group_id = b->assoc_group_id;
1373
1374         if (b->object_string != NULL) {
1375                 n->object_string = talloc_strdup(n, b->object_string);
1376                 if (n->object_string == NULL) {
1377                         talloc_free(n);
1378                         return NULL;
1379                 }
1380         }
1381         if (b->host != NULL) {
1382                 n->host = talloc_strdup(n, b->host);
1383                 if (n->host == NULL) {
1384                         talloc_free(n);
1385                         return NULL;
1386                 }
1387         }
1388
1389         if (b->target_hostname != NULL) {
1390                 n->target_hostname = talloc_strdup(n, b->target_hostname);
1391                 if (n->target_hostname == NULL) {
1392                         talloc_free(n);
1393                         return NULL;
1394                 }
1395         }
1396
1397         if (b->target_principal != NULL) {
1398                 n->target_principal = talloc_strdup(n, b->target_principal);
1399                 if (n->target_principal == NULL) {
1400                         talloc_free(n);
1401                         return NULL;
1402                 }
1403         }
1404
1405         if (b->endpoint != NULL) {
1406                 n->endpoint = talloc_strdup(n, b->endpoint);
1407                 if (n->endpoint == NULL) {
1408                         talloc_free(n);
1409                         return NULL;
1410                 }
1411         }
1412
1413         for (count = 0; b->options && b->options[count]; count++);
1414
1415         if (count > 0) {
1416                 uint32_t i;
1417
1418                 n->options = talloc_array(n, const char *, count + 1);
1419                 if (n->options == NULL) {
1420                         talloc_free(n);
1421                         return NULL;
1422                 }
1423
1424                 for (i = 0; i < count; i++) {
1425                         n->options[i] = talloc_strdup(n->options, b->options[i]);
1426                         if (n->options[i] == NULL) {
1427                                 talloc_free(n);
1428                                 return NULL;
1429                         }
1430                 }
1431                 n->options[count] = NULL;
1432         }
1433
1434         return n;
1435 }
1436
1437 _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
1438                                              const struct dcerpc_binding *binding,
1439                                              struct epm_tower *tower)
1440 {
1441         const enum epm_protocol *protseq = NULL;
1442         int num_protocols = -1, i;
1443         struct ndr_syntax_id abstract_syntax;
1444         NTSTATUS status;
1445
1446         /* Find transport */
1447         for (i=0;i<ARRAY_SIZE(transports);i++) {
1448                 if (transports[i].transport == binding->transport) {
1449                         protseq = transports[i].protseq;
1450                         num_protocols = transports[i].num_protocols;
1451                         break;
1452                 }
1453         }
1454
1455         if (num_protocols == -1) {
1456                 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
1457                 return NT_STATUS_UNSUCCESSFUL;
1458         }
1459
1460         tower->num_floors = 2 + num_protocols;
1461         tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
1462
1463         /* Floor 0 */
1464         tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
1465
1466         abstract_syntax = dcerpc_binding_get_abstract_syntax(binding);
1467         tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors,
1468                                                                    &abstract_syntax);
1469
1470         if (!dcerpc_floor_pack_rhs_if_version_data(
1471                     tower->floors, &abstract_syntax,
1472                     &tower->floors[0].rhs.uuid.unknown)) {
1473                 return NT_STATUS_NO_MEMORY;
1474         }
1475
1476         /* Floor 1 */
1477         tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
1478
1479         tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors, 
1480                                                                 &ndr_transfer_syntax_ndr);
1481
1482         tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(tower->floors, 2);
1483
1484         /* Floor 2 to num_protocols */
1485         for (i = 0; i < num_protocols; i++) {
1486                 tower->floors[2 + i].lhs.protocol = protseq[i];
1487                 tower->floors[2 + i].lhs.lhs_data = data_blob_null;
1488                 ZERO_STRUCT(tower->floors[2 + i].rhs);
1489                 status = dcerpc_floor_set_rhs_data(tower->floors,
1490                                                    &tower->floors[2 + i],
1491                                                    NULL);
1492                 if (!NT_STATUS_IS_OK(status)) {
1493                         return status;
1494                 }
1495         }
1496
1497         /* The 4th floor contains the endpoint */
1498         if (num_protocols >= 2 && binding->endpoint) {
1499                 status = dcerpc_floor_set_rhs_data(tower->floors,
1500                                                    &tower->floors[3],
1501                                                    binding->endpoint);
1502                 if (!NT_STATUS_IS_OK(status)) {
1503                         return status;
1504                 }
1505         }
1506
1507         /* The 5th contains the network address */
1508         if (num_protocols >= 3 && binding->host) {
1509                 status = dcerpc_floor_set_rhs_data(tower->floors,
1510                                                    &tower->floors[4],
1511                                                    binding->host);
1512                 if (!NT_STATUS_IS_OK(status)) {
1513                         return status;
1514                 }
1515         }
1516
1517         return NT_STATUS_OK;
1518 }