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