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