librpc: prevent invalid NULL pointer derref in dcerpc_binding_get_auth_info().
[samba.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 GUID 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)) {
228                 o = s;
229                 s = talloc_asprintf_append_buffer(s, "%s@",
230                                     GUID_string(mem_ctx, &b->object));
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;
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         b->object = object;
526         return NT_STATUS_OK;
527 }
528
529 _PUBLIC_ enum dcerpc_transport_t dcerpc_binding_get_transport(const struct dcerpc_binding *b)
530 {
531         return b->transport;
532 }
533
534 _PUBLIC_ NTSTATUS dcerpc_binding_set_transport(struct dcerpc_binding *b,
535                                                enum dcerpc_transport_t transport)
536 {
537         NTSTATUS status;
538
539         /*
540          * TODO: we may want to check the transport value is
541          * wellknown.
542          */
543         if (b->transport == transport) {
544                 return NT_STATUS_OK;
545         }
546
547         /*
548          * This implicitly resets the endpoint
549          * as the endpoint is transport specific.
550          *
551          * It also resets the assoc group as it's
552          * also endpoint specific.
553          *
554          * TODO: in future we may reset more options
555          * here.
556          */
557         status = dcerpc_binding_set_string_option(b, "endpoint", NULL);
558         if (!NT_STATUS_IS_OK(status)) {
559                 return status;
560         }
561
562         b->assoc_group_id = 0;
563
564         b->transport = transport;
565         return NT_STATUS_OK;
566 }
567
568 _PUBLIC_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
569                                            enum dcerpc_AuthType *_auth_type,
570                                            enum dcerpc_AuthLevel *_auth_level)
571 {
572         enum dcerpc_AuthType auth_type;
573         enum dcerpc_AuthLevel auth_level;
574
575         if (b->flags & DCERPC_AUTH_SPNEGO) {
576                 auth_type = DCERPC_AUTH_TYPE_SPNEGO;
577         } else if (b->flags & DCERPC_AUTH_KRB5) {
578                 auth_type = DCERPC_AUTH_TYPE_KRB5;
579         } else if (b->flags & DCERPC_SCHANNEL) {
580                 auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
581         } else if (b->flags & DCERPC_AUTH_NTLM) {
582                 auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
583         } else {
584                 auth_type = DCERPC_AUTH_TYPE_NONE;
585         }
586
587         if (b->flags & DCERPC_SEAL) {
588                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
589         } else if (b->flags & DCERPC_SIGN) {
590                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
591         } else if (b->flags & DCERPC_CONNECT) {
592                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
593         } else if (auth_type != DCERPC_AUTH_TYPE_NONE) {
594                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
595         } else {
596                 auth_level = DCERPC_AUTH_LEVEL_NONE;
597         }
598
599         if (_auth_type != NULL) {
600                 *_auth_type = auth_type;
601         }
602
603         if (_auth_level != NULL) {
604                 *_auth_level = auth_level;
605         }
606 }
607
608 _PUBLIC_ uint32_t dcerpc_binding_get_assoc_group_id(const struct dcerpc_binding *b)
609 {
610         return b->assoc_group_id;
611 }
612
613 _PUBLIC_ NTSTATUS dcerpc_binding_set_assoc_group_id(struct dcerpc_binding *b,
614                                                     uint32_t assoc_group_id)
615 {
616         b->assoc_group_id = assoc_group_id;
617         return NT_STATUS_OK;
618 }
619
620 _PUBLIC_ struct ndr_syntax_id dcerpc_binding_get_abstract_syntax(const struct dcerpc_binding *b)
621 {
622         const char *s = dcerpc_binding_get_string_option(b, "abstract_syntax");
623         bool ok;
624         struct ndr_syntax_id id;
625
626         if (s == NULL) {
627                 return ndr_syntax_id_null;
628         }
629
630         ok = ndr_syntax_id_from_string(s, &id);
631         if (!ok) {
632                 return ndr_syntax_id_null;
633         }
634
635         return id;
636 }
637
638 _PUBLIC_ NTSTATUS dcerpc_binding_set_abstract_syntax(struct dcerpc_binding *b,
639                                                      const struct ndr_syntax_id *syntax)
640 {
641         NTSTATUS status;
642         char *s = NULL;
643
644         if (syntax == NULL) {
645                 status = dcerpc_binding_set_string_option(b, "abstract_syntax", NULL);
646                 if (!NT_STATUS_IS_OK(status)) {
647                         return status;
648                 }
649
650                 return NT_STATUS_OK;
651         }
652
653         if (ndr_syntax_id_equal(&ndr_syntax_id_null, syntax)) {
654                 status = dcerpc_binding_set_string_option(b, "abstract_syntax", NULL);
655                 if (!NT_STATUS_IS_OK(status)) {
656                         return status;
657                 }
658
659                 return NT_STATUS_OK;
660         }
661
662         s = ndr_syntax_id_to_string(b, syntax);
663         if (s == NULL) {
664                 return NT_STATUS_NO_MEMORY;
665         }
666
667         status = dcerpc_binding_set_string_option(b, "abstract_syntax", s);
668         TALLOC_FREE(s);
669         if (!NT_STATUS_IS_OK(status)) {
670                 return status;
671         }
672
673         return NT_STATUS_OK;
674 }
675
676 _PUBLIC_ const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
677                                                       const char *name)
678 {
679         struct {
680                 const char *name;
681                 const char *value;
682 #define _SPECIAL(x) { .name = #x, .value = b->x, }
683         } specials[] = {
684                 { .name = "object", .value = b->object_string, },
685                 _SPECIAL(host),
686                 _SPECIAL(endpoint),
687                 _SPECIAL(target_hostname),
688                 _SPECIAL(target_principal),
689 #undef _SPECIAL
690         };
691         const struct ncacn_option *no = NULL;
692         size_t name_len = strlen(name);
693         size_t i;
694         int ret;
695
696         ret = strcmp(name, "transport");
697         if (ret == 0) {
698                 return derpc_transport_string_by_transport(b->transport);
699         }
700
701         ret = strcmp(name, "assoc_group_id");
702         if (ret == 0) {
703                 char *tmp = discard_const_p(char, b->assoc_group_string);
704
705                 if (b->assoc_group_id == 0) {
706                         return NULL;
707                 }
708
709                 snprintf(tmp, sizeof(b->assoc_group_string),
710                          "0x%08x", b->assoc_group_id);
711                 return (const char *)b->assoc_group_string;
712         }
713
714         for (i=0; i < ARRAY_SIZE(specials); i++) {
715                 ret = strcmp(specials[i].name, name);
716                 if (ret != 0) {
717                         continue;
718                 }
719
720                 return specials[i].value;
721         }
722
723         no = ncacn_option_by_name(name);
724         if (no != NULL) {
725                 if (b->flags & no->flag) {
726                         return no->name;
727                 }
728
729                 return NULL;
730         }
731
732         if (b->options == NULL) {
733                 return NULL;
734         }
735
736         for (i=0; b->options[i]; i++) {
737                 const char *o = b->options[i];
738                 const char *vs = NULL;
739
740                 ret = strncmp(name, o, name_len);
741                 if (ret != 0) {
742                         continue;
743                 }
744
745                 if (o[name_len] != '=') {
746                         continue;
747                 }
748
749                 vs = &o[name_len + 1];
750
751                 return vs;
752         }
753
754         return NULL;
755 }
756
757 _PUBLIC_ char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
758                                                  const struct dcerpc_binding *b,
759                                                  const char *name)
760 {
761         const char *c = dcerpc_binding_get_string_option(b, name);
762         char *v;
763
764         if (c == NULL) {
765                 errno = ENOENT;
766                 return NULL;
767         }
768
769         v = talloc_strdup(mem_ctx, c);
770         if (v == NULL) {
771                 errno = ENOMEM;
772                 return NULL;
773         }
774
775         return v;
776 }
777
778 _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
779                                                    const char *name,
780                                                    const char *value)
781 {
782         struct {
783                 const char *name;
784                 const char **ptr;
785 #define _SPECIAL(x) { .name = #x, .ptr = &b->x, }
786         } specials[] = {
787                 _SPECIAL(host),
788                 _SPECIAL(endpoint),
789                 _SPECIAL(target_hostname),
790                 _SPECIAL(target_principal),
791 #undef _SPECIAL
792         };
793         const struct ncacn_option *no = NULL;
794         size_t name_len = strlen(name);
795         const char *opt = NULL;
796         char *tmp;
797         size_t i;
798         int ret;
799
800         /*
801          * Note: value == NULL, means delete it.
802          * value != NULL means add or reset.
803          */
804
805         ret = strcmp(name, "transport");
806         if (ret == 0) {
807                 enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
808
809                 if (t == NCA_UNKNOWN && value != NULL) {
810                         return NT_STATUS_INVALID_PARAMETER_MIX;
811                 }
812
813                 return dcerpc_binding_set_transport(b, t);
814         }
815
816         ret = strcmp(name, "object");
817         if (ret == 0) {
818                 NTSTATUS status;
819                 struct GUID uuid = GUID_zero();
820
821                 if (value != NULL) {
822                         DATA_BLOB blob;
823                         blob = data_blob_string_const(value);
824                         if (blob.length != 36) {
825                                 return NT_STATUS_INVALID_PARAMETER_MIX;
826                         }
827
828                         status = GUID_from_data_blob(&blob, &uuid);
829                         if (!NT_STATUS_IS_OK(status)) {
830                                 return status;
831                         }
832                 }
833
834                 return dcerpc_binding_set_object(b, uuid);
835         }
836
837         ret = strcmp(name, "assoc_group_id");
838         if (ret == 0) {
839                 uint32_t assoc_group_id = 0;
840
841                 if (value != NULL) {
842                         char c;
843
844                         ret = sscanf(value, "0x%08x%c", &assoc_group_id, &c);
845                         if (ret != 1) {
846                                 return NT_STATUS_INVALID_PARAMETER_MIX;
847                         }
848                 }
849
850                 return dcerpc_binding_set_assoc_group_id(b, assoc_group_id);
851         }
852
853         for (i=0; i < ARRAY_SIZE(specials); i++) {
854                 ret = strcmp(specials[i].name, name);
855                 if (ret != 0) {
856                         continue;
857                 }
858
859                 tmp = discard_const_p(char, *specials[i].ptr);
860
861                 if (value == NULL) {
862                         talloc_free(tmp);
863                         *specials[i].ptr = NULL;
864                         return NT_STATUS_OK;
865                 }
866
867                 if (value[0] == '\0') {
868                         return NT_STATUS_INVALID_PARAMETER_MIX;
869                 }
870
871                 *specials[i].ptr = talloc_strdup(b, value);
872                 if (*specials[i].ptr == NULL) {
873                         *specials[i].ptr = tmp;
874                         return NT_STATUS_NO_MEMORY;
875                 }
876                 talloc_free(tmp);
877
878                 return NT_STATUS_OK;
879         }
880
881         no = ncacn_option_by_name(name);
882         if (no != NULL) {
883                 if (value == NULL) {
884                         b->flags &= ~no->flag;
885                         return NT_STATUS_OK;
886                 }
887
888                 ret = strcasecmp(no->name, value);
889                 if (ret != 0) {
890                         return NT_STATUS_INVALID_PARAMETER_MIX;
891                 }
892
893                 b->flags |= no->flag;
894                 return NT_STATUS_OK;
895         }
896
897         for (i=0; b->options && b->options[i]; i++) {
898                 const char *o = b->options[i];
899
900                 ret = strncmp(name, o, name_len);
901                 if (ret != 0) {
902                         continue;
903                 }
904
905                 if (o[name_len] != '=') {
906                         continue;
907                 }
908
909                 opt = o;
910                 break;
911         }
912
913         if (opt == NULL) {
914                 const char **n;
915
916                 if (value == NULL) {
917                         return NT_STATUS_OK;
918                 }
919
920                 n = talloc_realloc(b, b->options, const char *, i + 2);
921                 if (n == NULL) {
922                         return NT_STATUS_NO_MEMORY;
923                 }
924                 n[i] = NULL;
925                 n[i + 1] = NULL;
926                 b->options = n;
927         }
928
929         tmp = discard_const_p(char, opt);
930
931         if (value == NULL) {
932                 for (;b->options[i];i++) {
933                         b->options[i] = b->options[i+1];
934                 }
935                 talloc_free(tmp);
936                 return NT_STATUS_OK;
937         }
938
939         b->options[i] = talloc_asprintf(b->options, "%s=%s",
940                                         name, value);
941         if (b->options[i] == NULL) {
942                 b->options[i] = tmp;
943                 return NT_STATUS_NO_MEMORY;
944         }
945
946         return NT_STATUS_OK;
947 }
948
949 _PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
950 {
951         return b->flags;
952 }
953
954 _PUBLIC_ NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
955                                            uint32_t additional,
956                                            uint32_t clear)
957 {
958         /*
959          * TODO: in future we may want to reject invalid combinations
960          */
961         b->flags &= ~clear;
962         b->flags |= additional;
963
964         return NT_STATUS_OK;
965 }
966
967 _PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor,
968                                             struct ndr_syntax_id *syntax)
969 {
970         TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
971         struct ndr_pull *ndr;
972         enum ndr_err_code ndr_err;
973         uint16_t if_version=0;
974
975         ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
976         if (ndr == NULL) {
977                 talloc_free(mem_ctx);
978                 return NT_STATUS_NO_MEMORY;
979         }
980         ndr->flags |= LIBNDR_FLAG_NOALIGN;
981
982         ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
983         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
984                 talloc_free(mem_ctx);
985                 return ndr_map_error2ntstatus(ndr_err);
986         }
987
988         ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
989         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
990                 talloc_free(mem_ctx);
991                 return ndr_map_error2ntstatus(ndr_err);
992         }
993
994         syntax->if_version = if_version;
995
996         talloc_free(mem_ctx);
997
998         return NT_STATUS_OK;
999 }
1000
1001 static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
1002 {
1003         DATA_BLOB blob;
1004         enum ndr_err_code ndr_err;
1005         struct ndr_push *ndr;
1006
1007         ndr = ndr_push_init_ctx(mem_ctx);
1008         if (ndr == NULL) {
1009                 return data_blob_null;
1010         }
1011
1012         ndr->flags |= LIBNDR_FLAG_NOALIGN;
1013
1014         ndr_err = ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
1015         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1016                 return data_blob_null;
1017         }
1018         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
1019         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1020                 return data_blob_null;
1021         }
1022
1023         blob = ndr_push_blob(ndr);
1024         talloc_steal(mem_ctx, blob.data);
1025         talloc_free(ndr);
1026         return blob;
1027 }
1028
1029 static bool dcerpc_floor_pack_rhs_if_version_data(
1030         TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax,
1031         DATA_BLOB *pblob)
1032 {
1033         DATA_BLOB blob;
1034         struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
1035         enum ndr_err_code ndr_err;
1036
1037         if (ndr == NULL) {
1038                 return false;
1039         }
1040
1041         ndr->flags |= LIBNDR_FLAG_NOALIGN;
1042
1043         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version >> 16);
1044         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1045                 return false;
1046         }
1047
1048         blob = ndr_push_blob(ndr);
1049         talloc_steal(mem_ctx, blob.data);
1050         talloc_free(ndr);
1051         *pblob = blob;
1052         return true;
1053 }
1054
1055 char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
1056 {
1057         switch (epm_floor->lhs.protocol) {
1058         case EPM_PROTOCOL_TCP:
1059                 if (epm_floor->rhs.tcp.port == 0) return NULL;
1060                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.tcp.port);
1061
1062         case EPM_PROTOCOL_UDP:
1063                 if (epm_floor->rhs.udp.port == 0) return NULL;
1064                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.udp.port);
1065
1066         case EPM_PROTOCOL_HTTP:
1067                 if (epm_floor->rhs.http.port == 0) return NULL;
1068                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.http.port);
1069
1070         case EPM_PROTOCOL_IP:
1071                 return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
1072
1073         case EPM_PROTOCOL_NCACN:
1074                 return NULL;
1075
1076         case EPM_PROTOCOL_NCADG:
1077                 return NULL;
1078
1079         case EPM_PROTOCOL_SMB:
1080                 if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
1081                 return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
1082
1083         case EPM_PROTOCOL_NAMED_PIPE:
1084                 if (strlen(epm_floor->rhs.named_pipe.path) == 0) return NULL;
1085                 return talloc_strdup(mem_ctx, epm_floor->rhs.named_pipe.path);
1086
1087         case EPM_PROTOCOL_NETBIOS:
1088                 if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
1089                 return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
1090
1091         case EPM_PROTOCOL_NCALRPC:
1092                 return NULL;
1093
1094         case EPM_PROTOCOL_VINES_SPP:
1095                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_spp.port);
1096
1097         case EPM_PROTOCOL_VINES_IPC:
1098                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_ipc.port);
1099
1100         case EPM_PROTOCOL_STREETTALK:
1101                 return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
1102
1103         case EPM_PROTOCOL_UNIX_DS:
1104                 if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
1105                 return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
1106
1107         case EPM_PROTOCOL_NULL:
1108                 return NULL;
1109
1110         default:
1111                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1112                 break;
1113         }
1114
1115         return NULL;
1116 }
1117
1118 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx, 
1119                                           struct epm_floor *epm_floor,  
1120                                           const char *data)
1121 {
1122         if (data == NULL) {
1123                 data = "";
1124         }
1125
1126         switch (epm_floor->lhs.protocol) {
1127         case EPM_PROTOCOL_TCP:
1128                 epm_floor->rhs.tcp.port = atoi(data);
1129                 return NT_STATUS_OK;
1130
1131         case EPM_PROTOCOL_UDP:
1132                 epm_floor->rhs.udp.port = atoi(data);
1133                 return NT_STATUS_OK;
1134
1135         case EPM_PROTOCOL_HTTP:
1136                 epm_floor->rhs.http.port = atoi(data);
1137                 return NT_STATUS_OK;
1138
1139         case EPM_PROTOCOL_IP:
1140                 if (!is_ipaddress_v4(data)) {
1141                         data = "0.0.0.0";
1142                 }
1143                 epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
1144                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
1145                 return NT_STATUS_OK;
1146
1147         case EPM_PROTOCOL_NCACN:
1148                 epm_floor->rhs.ncacn.minor_version = 0;
1149                 return NT_STATUS_OK;
1150
1151         case EPM_PROTOCOL_NCADG:
1152                 epm_floor->rhs.ncadg.minor_version = 0;
1153                 return NT_STATUS_OK;
1154
1155         case EPM_PROTOCOL_SMB:
1156                 epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
1157                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
1158                 return NT_STATUS_OK;
1159
1160         case EPM_PROTOCOL_NAMED_PIPE:
1161                 epm_floor->rhs.named_pipe.path = talloc_strdup(mem_ctx, data);
1162                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.named_pipe.path);
1163                 return NT_STATUS_OK;
1164
1165         case EPM_PROTOCOL_NETBIOS:
1166                 epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
1167                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
1168                 return NT_STATUS_OK;
1169
1170         case EPM_PROTOCOL_NCALRPC:
1171                 return NT_STATUS_OK;
1172
1173         case EPM_PROTOCOL_VINES_SPP:
1174                 epm_floor->rhs.vines_spp.port = atoi(data);
1175                 return NT_STATUS_OK;
1176
1177         case EPM_PROTOCOL_VINES_IPC:
1178                 epm_floor->rhs.vines_ipc.port = atoi(data);
1179                 return NT_STATUS_OK;
1180
1181         case EPM_PROTOCOL_STREETTALK:
1182                 epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
1183                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
1184                 return NT_STATUS_OK;
1185
1186         case EPM_PROTOCOL_UNIX_DS:
1187                 epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
1188                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
1189                 return NT_STATUS_OK;
1190
1191         case EPM_PROTOCOL_NULL:
1192                 return NT_STATUS_OK;
1193
1194         default:
1195                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
1196                 break;
1197         }
1198
1199         return NT_STATUS_NOT_SUPPORTED;
1200 }
1201
1202 enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
1203 {
1204         int i;
1205
1206         /* Find a transport that has 'prot' as 4th protocol */
1207         for (i=0;i<ARRAY_SIZE(transports);i++) {
1208                 if (transports[i].num_protocols >= 2 && 
1209                         transports[i].protseq[1] == prot) {
1210                         return transports[i].transport;
1211                 }
1212         }
1213
1214         /* Unknown transport */
1215         return (unsigned int)-1;
1216 }
1217
1218 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower)
1219 {
1220         int i;
1221
1222         /* Find a transport that matches this tower */
1223         for (i=0;i<ARRAY_SIZE(transports);i++) {
1224                 int j;
1225                 if (transports[i].num_protocols != tower->num_floors - 2) {
1226                         continue; 
1227                 }
1228
1229                 for (j = 0; j < transports[i].num_protocols; j++) {
1230                         if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
1231                                 break;
1232                         }
1233                 }
1234
1235                 if (j == transports[i].num_protocols) {
1236                         return transports[i].transport;
1237                 }
1238         }
1239
1240         /* Unknown transport */
1241         return (unsigned int)-1;
1242 }
1243
1244 _PUBLIC_ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t)
1245 {
1246         int i;
1247
1248         for (i=0; i<ARRAY_SIZE(transports); i++) {
1249                 if (t == transports[i].transport) {
1250                         return transports[i].name;
1251                 }
1252         }
1253         return NULL;
1254 }
1255
1256 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_name(const char *name)
1257 {
1258         size_t i;
1259
1260         if (name == NULL) {
1261                 return NCA_UNKNOWN;
1262         }
1263
1264         for (i=0; i<ARRAY_SIZE(transports);i++) {
1265                 if (strcasecmp(name, transports[i].name) == 0) {
1266                         return transports[i].transport;
1267                 }
1268         }
1269
1270         return NCA_UNKNOWN;
1271 }
1272
1273 _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
1274                                             struct epm_tower *tower,
1275                                             struct dcerpc_binding **b_out)
1276 {
1277         NTSTATUS status;
1278         struct dcerpc_binding *b;
1279         enum dcerpc_transport_t transport;
1280         struct ndr_syntax_id abstract_syntax;
1281         char *endpoint = NULL;
1282         char *host = NULL;
1283
1284         /*
1285          * A tower needs to have at least 4 floors to carry useful
1286          * information. Floor 3 is the transport identifier which defines
1287          * how many floors are required at least.
1288          */
1289         if (tower->num_floors < 4) {
1290                 return NT_STATUS_INVALID_PARAMETER;
1291         }
1292
1293         status = dcerpc_parse_binding(mem_ctx, "", &b);
1294         if (!NT_STATUS_IS_OK(status)) {
1295                 return status;
1296         }
1297
1298         transport = dcerpc_transport_by_tower(tower);
1299         if (transport == NCA_UNKNOWN) {
1300                 talloc_free(b);
1301                 return NT_STATUS_NOT_SUPPORTED;
1302         }
1303
1304         status = dcerpc_binding_set_transport(b, transport);
1305         if (!NT_STATUS_IS_OK(status)) {
1306                 talloc_free(b);
1307                 return status;
1308         }
1309
1310         /* Set abstract syntax */
1311         status = dcerpc_floor_get_lhs_data(&tower->floors[0], &abstract_syntax);
1312         if (!NT_STATUS_IS_OK(status)) {
1313                 talloc_free(b);
1314                 return status;
1315         }
1316
1317         status = dcerpc_binding_set_abstract_syntax(b, &abstract_syntax);
1318         if (!NT_STATUS_IS_OK(status)) {
1319                 talloc_free(b);
1320                 return status;
1321         }
1322
1323         /* Ignore floor 1, it contains the NDR version info */
1324
1325         /* Set endpoint */
1326         errno = 0;
1327         if (tower->num_floors >= 4) {
1328                 endpoint = dcerpc_floor_get_rhs_data(b, &tower->floors[3]);
1329         }
1330         if (errno != 0) {
1331                 int saved_errno = errno;
1332                 talloc_free(b);
1333                 return map_nt_error_from_unix_common(saved_errno);
1334         }
1335
1336         status = dcerpc_binding_set_string_option(b, "endpoint", endpoint);
1337         if (!NT_STATUS_IS_OK(status)) {
1338                 talloc_free(b);
1339                 return status;
1340         }
1341         TALLOC_FREE(endpoint);
1342
1343         /* Set network address */
1344         errno = 0;
1345         if (tower->num_floors >= 5) {
1346                 host = dcerpc_floor_get_rhs_data(b, &tower->floors[4]);
1347         }
1348         if (errno != 0) {
1349                 int saved_errno = errno;
1350                 talloc_free(b);
1351                 return map_nt_error_from_unix_common(saved_errno);
1352         }
1353
1354         status = dcerpc_binding_set_string_option(b, "host", host);
1355         if (!NT_STATUS_IS_OK(status)) {
1356                 talloc_free(b);
1357                 return status;
1358         }
1359         status = dcerpc_binding_set_string_option(b, "target_hostname", host);
1360         if (!NT_STATUS_IS_OK(status)) {
1361                 talloc_free(b);
1362                 return status;
1363         }
1364         TALLOC_FREE(host);
1365
1366         *b_out = b;
1367         return NT_STATUS_OK;
1368 }
1369
1370 _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
1371                                                    const struct dcerpc_binding *b)
1372 {
1373         struct dcerpc_binding *n;
1374         uint32_t count;
1375
1376         n = talloc_zero(mem_ctx, struct dcerpc_binding);
1377         if (n == NULL) {
1378                 return NULL;
1379         }
1380
1381         n->transport = b->transport;
1382         n->object = b->object;
1383         n->flags = b->flags;
1384         n->assoc_group_id = b->assoc_group_id;
1385
1386         if (b->object_string != NULL) {
1387                 n->object_string = talloc_strdup(n, b->object_string);
1388                 if (n->object_string == NULL) {
1389                         talloc_free(n);
1390                         return NULL;
1391                 }
1392         }
1393         if (b->host != NULL) {
1394                 n->host = talloc_strdup(n, b->host);
1395                 if (n->host == NULL) {
1396                         talloc_free(n);
1397                         return NULL;
1398                 }
1399         }
1400
1401         if (b->target_hostname != NULL) {
1402                 n->target_hostname = talloc_strdup(n, b->target_hostname);
1403                 if (n->target_hostname == NULL) {
1404                         talloc_free(n);
1405                         return NULL;
1406                 }
1407         }
1408
1409         if (b->target_principal != NULL) {
1410                 n->target_principal = talloc_strdup(n, b->target_principal);
1411                 if (n->target_principal == NULL) {
1412                         talloc_free(n);
1413                         return NULL;
1414                 }
1415         }
1416
1417         if (b->endpoint != NULL) {
1418                 n->endpoint = talloc_strdup(n, b->endpoint);
1419                 if (n->endpoint == NULL) {
1420                         talloc_free(n);
1421                         return NULL;
1422                 }
1423         }
1424
1425         for (count = 0; b->options && b->options[count]; count++);
1426
1427         if (count > 0) {
1428                 uint32_t i;
1429
1430                 n->options = talloc_array(n, const char *, count + 1);
1431                 if (n->options == NULL) {
1432                         talloc_free(n);
1433                         return NULL;
1434                 }
1435
1436                 for (i = 0; i < count; i++) {
1437                         n->options[i] = talloc_strdup(n->options, b->options[i]);
1438                         if (n->options[i] == NULL) {
1439                                 talloc_free(n);
1440                                 return NULL;
1441                         }
1442                 }
1443                 n->options[count] = NULL;
1444         }
1445
1446         return n;
1447 }
1448
1449 _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
1450                                              const struct dcerpc_binding *binding,
1451                                              struct epm_tower *tower)
1452 {
1453         const enum epm_protocol *protseq = NULL;
1454         int num_protocols = -1, i;
1455         struct ndr_syntax_id abstract_syntax;
1456         NTSTATUS status;
1457
1458         /* Find transport */
1459         for (i=0;i<ARRAY_SIZE(transports);i++) {
1460                 if (transports[i].transport == binding->transport) {
1461                         protseq = transports[i].protseq;
1462                         num_protocols = transports[i].num_protocols;
1463                         break;
1464                 }
1465         }
1466
1467         if (num_protocols == -1) {
1468                 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
1469                 return NT_STATUS_UNSUCCESSFUL;
1470         }
1471
1472         tower->num_floors = 2 + num_protocols;
1473         tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
1474
1475         /* Floor 0 */
1476         tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
1477
1478         abstract_syntax = dcerpc_binding_get_abstract_syntax(binding);
1479         tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors,
1480                                                                    &abstract_syntax);
1481
1482         if (!dcerpc_floor_pack_rhs_if_version_data(
1483                     tower->floors, &abstract_syntax,
1484                     &tower->floors[0].rhs.uuid.unknown)) {
1485                 return NT_STATUS_NO_MEMORY;
1486         }
1487
1488         /* Floor 1 */
1489         tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
1490
1491         tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors, 
1492                                                                 &ndr_transfer_syntax_ndr);
1493
1494         tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(tower->floors, 2);
1495
1496         /* Floor 2 to num_protocols */
1497         for (i = 0; i < num_protocols; i++) {
1498                 tower->floors[2 + i].lhs.protocol = protseq[i];
1499                 tower->floors[2 + i].lhs.lhs_data = data_blob_null;
1500                 ZERO_STRUCT(tower->floors[2 + i].rhs);
1501                 status = dcerpc_floor_set_rhs_data(tower->floors,
1502                                                    &tower->floors[2 + i],
1503                                                    NULL);
1504                 if (!NT_STATUS_IS_OK(status)) {
1505                         return status;
1506                 }
1507         }
1508
1509         /* The 4th floor contains the endpoint */
1510         if (num_protocols >= 2 && binding->endpoint) {
1511                 status = dcerpc_floor_set_rhs_data(tower->floors,
1512                                                    &tower->floors[3],
1513                                                    binding->endpoint);
1514                 if (!NT_STATUS_IS_OK(status)) {
1515                         return status;
1516                 }
1517         }
1518
1519         /* The 5th contains the network address */
1520         if (num_protocols >= 3 && binding->host) {
1521                 status = dcerpc_floor_set_rhs_data(tower->floors,
1522                                                    &tower->floors[4],
1523                                                    binding->host);
1524                 if (!NT_STATUS_IS_OK(status)) {
1525                         return status;
1526                 }
1527         }
1528
1529         return NT_STATUS_OK;
1530 }