librpc/rpc: add dcerpc_binding_[g|s]et_object()
[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
202         if (b->transport != NCA_UNKNOWN) {
203                 t_name = derpc_transport_string_by_transport(b->transport);
204                 if (!t_name) {
205                         talloc_free(o);
206                         return NULL;
207                 }
208         }
209
210         if (!GUID_all_zero(&b->object.uuid)) { 
211                 o = s;
212                 s = talloc_asprintf_append_buffer(s, "%s@",
213                                     GUID_string(mem_ctx, &b->object.uuid));
214                 if (s == NULL) {
215                         talloc_free(o);
216                         return NULL;
217                 }
218         }
219
220         if (t_name != NULL) {
221                 o = s;
222                 s = talloc_asprintf_append_buffer(s, "%s:", t_name);
223                 if (s == NULL) {
224                         talloc_free(o);
225                         return NULL;
226                 }
227         }
228
229         if (b->host) {
230                 o = s;
231                 s = talloc_asprintf_append_buffer(s, "%s", b->host);
232                 if (s == NULL) {
233                         talloc_free(o);
234                         return NULL;
235                 }
236         }
237
238         if (!b->endpoint && !b->options && !b->flags) {
239                 return s;
240         }
241
242         o = s;
243         s = talloc_asprintf_append_buffer(s, "[");
244         if (s == NULL) {
245                 talloc_free(o);
246                 return NULL;
247         }
248
249         if (b->endpoint) {
250                 o = s;
251                 s = talloc_asprintf_append_buffer(s, "%s", b->endpoint);
252                 if (s == NULL) {
253                         talloc_free(o);
254                         return NULL;
255                 }
256         }
257
258         for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
259                 if (!(b->flags & ncacn_options[i].flag)) {
260                         continue;
261                 }
262
263                 o = s;
264                 s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
265                 if (s == NULL) {
266                         talloc_free(o);
267                         return NULL;
268                 }
269         }
270
271         for (i=0;b->options && b->options[i];i++) {
272                 o = s;
273                 s = talloc_asprintf_append_buffer(s, ",%s", b->options[i]);
274                 if (s == NULL) {
275                         talloc_free(o);
276                         return NULL;
277                 }
278         }
279
280         o = s;
281         s = talloc_asprintf_append_buffer(s, "]");
282         if (s == NULL) {
283                 talloc_free(o);
284                 return NULL;
285         }
286
287         return s;
288 }
289
290 /*
291   parse a binding string into a dcerpc_binding structure
292 */
293 _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *_s, struct dcerpc_binding **b_out)
294 {
295         char *_t;
296         struct dcerpc_binding *b;
297         char *s;
298         char *options = NULL;
299         char *p;
300         size_t i;
301         NTSTATUS status;
302
303         b = talloc_zero(mem_ctx, struct dcerpc_binding);
304         if (!b) {
305                 return NT_STATUS_NO_MEMORY;
306         }
307
308         _t = talloc_strdup(b, _s);
309         if (_t == NULL) {
310                 talloc_free(b);
311                 return NT_STATUS_NO_MEMORY;
312         }
313
314         s = _t;
315
316         p = strchr(s, '[');
317         if (p) {
318                 *p = '\0';
319                 options = p + 1;
320                 if (options[strlen(options)-1] != ']') {
321                         talloc_free(b);
322                         return NT_STATUS_INVALID_PARAMETER_MIX;
323                 }
324                 options[strlen(options)-1] = 0;
325         }
326
327         p = strchr(s, '@');
328
329         if (p && PTR_DIFF(p, s) == 36) { /* 36 is the length of a UUID */
330                 *p = '\0';
331
332                 status = dcerpc_binding_set_string_option(b, "object", s);
333                 if (!NT_STATUS_IS_OK(status)) {
334                         talloc_free(b);
335                         return status;
336                 }
337
338                 s = p + 1;
339         }
340
341         p = strchr(s, ':');
342
343         if (p == NULL) {
344                 b->transport = NCA_UNKNOWN;
345         } else {
346                 *p = '\0';
347
348                 status = dcerpc_binding_set_string_option(b, "transport", s);
349                 if (!NT_STATUS_IS_OK(status)) {
350                         talloc_free(b);
351                         return status;
352                 }
353
354                 s = p + 1;
355         }
356
357         if (strlen(s) > 0) {
358                 status = dcerpc_binding_set_string_option(b, "host", s);
359                 if (!NT_STATUS_IS_OK(status)) {
360                         talloc_free(b);
361                         return status;
362                 }
363
364                 b->target_hostname = talloc_strdup(b, b->host);
365                 if (b->target_hostname == NULL) {
366                         talloc_free(b);
367                         return NT_STATUS_NO_MEMORY;
368                 }
369         }
370
371         for (i=0; options != NULL; i++) {
372                 const char *name = options;
373                 const char *value = NULL;
374
375                 p = strchr(options, ',');
376                 if (p != NULL) {
377                         *p = '\0';
378                         options = p+1;
379                 } else {
380                         options = NULL;
381                 }
382
383                 p = strchr(name, '=');
384                 if (p != NULL) {
385                         *p = '\0';
386                         value = p + 1;
387                 }
388
389                 if (value == NULL) {
390                         /*
391                          * If it's not a key=value pair
392                          * it might be a ncacn_option
393                          * or if it's the first option
394                          * it's the endpoint.
395                          */
396                         const struct ncacn_option *no = NULL;
397
398                         value = name;
399
400                         no = ncacn_option_by_name(name);
401                         if (no == NULL) {
402                                 if (i > 0) {
403                                         /*
404                                          * we don't allow unknown options
405                                          */
406                                         return NT_STATUS_INVALID_PARAMETER_MIX;
407                                 }
408
409                                 /*
410                                  * This is the endpoint
411                                  */
412                                 name = "endpoint";
413                                 if (strlen(value) == 0) {
414                                         value = NULL;
415                                 }
416                         }
417                 }
418
419                 status = dcerpc_binding_set_string_option(b, name, value);
420                 if (!NT_STATUS_IS_OK(status)) {
421                         talloc_free(b);
422                         return status;
423                 }
424         }
425
426         talloc_free(_t);
427         *b_out = b;
428         return NT_STATUS_OK;
429 }
430
431 _PUBLIC_ struct GUID dcerpc_binding_get_object(const struct dcerpc_binding *b)
432 {
433         return b->object.uuid;
434 }
435
436 _PUBLIC_ NTSTATUS dcerpc_binding_set_object(struct dcerpc_binding *b,
437                                             struct GUID object)
438 {
439         char *tmp = discard_const_p(char, b->object_string);
440
441         if (GUID_all_zero(&object)) {
442                 talloc_free(tmp);
443                 b->object_string = NULL;
444                 ZERO_STRUCT(b->object);
445                 return NT_STATUS_OK;
446         }
447
448         b->object_string = GUID_string(b, &object);
449         if (b->object_string == NULL) {
450                 b->object_string = tmp;
451                 return NT_STATUS_NO_MEMORY;
452         }
453         talloc_free(tmp);
454
455         ZERO_STRUCT(b->object);
456         b->object.uuid = object;
457         return NT_STATUS_OK;
458 }
459
460 _PUBLIC_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
461                                            enum dcerpc_AuthType *_auth_type,
462                                            enum dcerpc_AuthLevel *_auth_level)
463 {
464         enum dcerpc_AuthType auth_type;
465         enum dcerpc_AuthLevel auth_level;
466
467         if (b->flags & DCERPC_AUTH_SPNEGO) {
468                 auth_type = DCERPC_AUTH_TYPE_SPNEGO;
469         } else if (b->flags & DCERPC_AUTH_KRB5) {
470                 auth_type = DCERPC_AUTH_TYPE_KRB5;
471         } else if (b->flags & DCERPC_SCHANNEL) {
472                 auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
473         } else if (b->flags & DCERPC_AUTH_NTLM) {
474                 auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
475         } else {
476                 auth_type = DCERPC_AUTH_TYPE_NONE;
477         }
478
479         if (b->flags & DCERPC_SEAL) {
480                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
481         } else if (b->flags & DCERPC_SIGN) {
482                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
483         } else if (b->flags & DCERPC_CONNECT) {
484                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
485         } else if (auth_type != DCERPC_AUTH_TYPE_NONE) {
486                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
487         } else {
488                 auth_level = DCERPC_AUTH_LEVEL_NONE;
489         }
490
491         if (_auth_type == NULL) {
492                 *_auth_type = auth_type;
493         }
494
495         if (_auth_level == NULL) {
496                 *_auth_level = auth_level;
497         }
498 }
499
500 _PUBLIC_ const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
501                                                       const char *name)
502 {
503         struct {
504                 const char *name;
505                 const char *value;
506 #define _SPECIAL(x) { .name = #x, .value = b->x, }
507         } specials[] = {
508                 { .name = "object", .value = b->object_string, },
509                 _SPECIAL(host),
510                 _SPECIAL(endpoint),
511                 _SPECIAL(target_hostname),
512                 _SPECIAL(target_principal),
513 #undef _SPECIAL
514         };
515         const struct ncacn_option *no = NULL;
516         size_t name_len = strlen(name);
517         size_t i;
518         int ret;
519
520         ret = strcmp(name, "transport");
521         if (ret == 0) {
522                 return derpc_transport_string_by_transport(b->transport);
523         }
524
525         for (i=0; i < ARRAY_SIZE(specials); i++) {
526                 ret = strcmp(specials[i].name, name);
527                 if (ret != 0) {
528                         continue;
529                 }
530
531                 return specials[i].value;
532         }
533
534         no = ncacn_option_by_name(name);
535         if (no != NULL) {
536                 if (b->flags & no->flag) {
537                         return no->name;
538                 }
539
540                 return NULL;
541         }
542
543         if (b->options == NULL) {
544                 return NULL;
545         }
546
547         for (i=0; b->options[i]; i++) {
548                 const char *o = b->options[i];
549                 const char *vs = NULL;
550
551                 ret = strncmp(name, o, name_len);
552                 if (ret != 0) {
553                         continue;
554                 }
555
556                 if (o[name_len] != '=') {
557                         continue;
558                 }
559
560                 vs = &o[name_len + 1];
561
562                 return vs;
563         }
564
565         return NULL;
566 }
567
568 _PUBLIC_ char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
569                                                  const struct dcerpc_binding *b,
570                                                  const char *name)
571 {
572         const char *c = dcerpc_binding_get_string_option(b, name);
573         char *v;
574
575         if (c == NULL) {
576                 errno = ENOENT;
577                 return NULL;
578         }
579
580         v = talloc_strdup(mem_ctx, c);
581         if (v == NULL) {
582                 errno = ENOMEM;
583                 return NULL;
584         }
585
586         return v;
587 }
588
589 _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
590                                                    const char *name,
591                                                    const char *value)
592 {
593         struct {
594                 const char *name;
595                 const char **ptr;
596 #define _SPECIAL(x) { .name = #x, .ptr = &b->x, }
597         } specials[] = {
598                 _SPECIAL(host),
599                 _SPECIAL(endpoint),
600                 _SPECIAL(target_hostname),
601                 _SPECIAL(target_principal),
602 #undef _SPECIAL
603         };
604         const struct ncacn_option *no = NULL;
605         size_t name_len = strlen(name);
606         const char *opt = NULL;
607         char *tmp;
608         size_t i;
609         int ret;
610
611         /*
612          * Note: value == NULL, means delete it.
613          * value != NULL means add or reset.
614          */
615
616         ret = strcmp(name, "transport");
617         if (ret == 0) {
618                 enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
619
620                 if (t == NCA_UNKNOWN && value != NULL) {
621                         return NT_STATUS_INVALID_PARAMETER_MIX;
622                 }
623
624                 b->transport = t;
625                 return NT_STATUS_OK;
626         }
627
628         ret = strcmp(name, "object");
629         if (ret == 0) {
630                 NTSTATUS status;
631                 struct GUID uuid = GUID_zero();
632
633                 if (value != NULL) {
634                         DATA_BLOB blob;
635                         blob = data_blob_string_const(value);
636                         if (blob.length != 36) {
637                                 return NT_STATUS_INVALID_PARAMETER_MIX;
638                         }
639
640                         status = GUID_from_data_blob(&blob, &uuid);
641                         if (!NT_STATUS_IS_OK(status)) {
642                                 return status;
643                         }
644                 }
645
646                 return dcerpc_binding_set_object(b, uuid);
647         }
648
649         for (i=0; i < ARRAY_SIZE(specials); i++) {
650                 ret = strcmp(specials[i].name, name);
651                 if (ret != 0) {
652                         continue;
653                 }
654
655                 tmp = discard_const_p(char, *specials[i].ptr);
656
657                 if (value == NULL) {
658                         talloc_free(tmp);
659                         *specials[i].ptr = NULL;
660                         return NT_STATUS_OK;
661                 }
662
663                 if (value[0] == '\0') {
664                         return NT_STATUS_INVALID_PARAMETER_MIX;
665                 }
666
667                 *specials[i].ptr = talloc_strdup(b, value);
668                 if (*specials[i].ptr == NULL) {
669                         *specials[i].ptr = tmp;
670                         return NT_STATUS_NO_MEMORY;
671                 }
672                 talloc_free(tmp);
673
674                 return NT_STATUS_OK;
675         }
676
677         no = ncacn_option_by_name(name);
678         if (no != NULL) {
679                 if (value == NULL) {
680                         b->flags &= ~no->flag;
681                         return NT_STATUS_OK;
682                 }
683
684                 ret = strcasecmp(no->name, value);
685                 if (ret != 0) {
686                         return NT_STATUS_INVALID_PARAMETER_MIX;
687                 }
688
689                 b->flags |= no->flag;
690                 return NT_STATUS_OK;
691         }
692
693         for (i=0; b->options && b->options[i]; i++) {
694                 const char *o = b->options[i];
695
696                 ret = strncmp(name, o, name_len);
697                 if (ret != 0) {
698                         continue;
699                 }
700
701                 if (o[name_len] != '=') {
702                         continue;
703                 }
704
705                 opt = o;
706                 break;
707         }
708
709         if (opt == NULL) {
710                 const char **n;
711
712                 if (value == NULL) {
713                         return NT_STATUS_OK;
714                 }
715
716                 n = talloc_realloc(b, b->options, const char *, i + 2);
717                 if (n == NULL) {
718                         return NT_STATUS_NO_MEMORY;
719                 }
720                 n[i] = NULL;
721                 n[i + 1] = NULL;
722                 b->options = n;
723         }
724
725         tmp = discard_const_p(char, opt);
726
727         if (value == NULL) {
728                 for (;b->options[i];i++) {
729                         b->options[i] = b->options[i+1];
730                 }
731                 talloc_free(tmp);
732                 return NT_STATUS_OK;
733         }
734
735         b->options[i] = talloc_asprintf(b->options, "%s=%s",
736                                         name, value);
737         if (b->options[i] == NULL) {
738                 b->options[i] = tmp;
739                 return NT_STATUS_NO_MEMORY;
740         }
741
742         return NT_STATUS_OK;
743 }
744
745 _PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
746 {
747         return b->flags;
748 }
749
750 _PUBLIC_ NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
751                                            uint32_t additional,
752                                            uint32_t clear)
753 {
754         /*
755          * TODO: in future we may want to reject invalid combinations
756          */
757         b->flags &= ~clear;
758         b->flags |= additional;
759
760         return NT_STATUS_OK;
761 }
762
763 _PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor,
764                                             struct ndr_syntax_id *syntax)
765 {
766         TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
767         struct ndr_pull *ndr;
768         enum ndr_err_code ndr_err;
769         uint16_t if_version=0;
770
771         ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
772         if (ndr == NULL) {
773                 talloc_free(mem_ctx);
774                 return NT_STATUS_NO_MEMORY;
775         }
776         ndr->flags |= LIBNDR_FLAG_NOALIGN;
777
778         ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
779         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
780                 talloc_free(mem_ctx);
781                 return ndr_map_error2ntstatus(ndr_err);
782         }
783
784         ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
785         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
786                 talloc_free(mem_ctx);
787                 return ndr_map_error2ntstatus(ndr_err);
788         }
789
790         syntax->if_version = if_version;
791
792         talloc_free(mem_ctx);
793
794         return NT_STATUS_OK;
795 }
796
797 static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
798 {
799         DATA_BLOB blob;
800         enum ndr_err_code ndr_err;
801         struct ndr_push *ndr;
802
803         ndr = ndr_push_init_ctx(mem_ctx);
804         if (ndr == NULL) {
805                 return data_blob_null;
806         }
807
808         ndr->flags |= LIBNDR_FLAG_NOALIGN;
809
810         ndr_err = ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
811         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
812                 return data_blob_null;
813         }
814         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
815         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
816                 return data_blob_null;
817         }
818
819         blob = ndr_push_blob(ndr);
820         talloc_steal(mem_ctx, blob.data);
821         talloc_free(ndr);
822         return blob;
823 }
824
825 static bool dcerpc_floor_pack_rhs_if_version_data(
826         TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax,
827         DATA_BLOB *pblob)
828 {
829         DATA_BLOB blob;
830         struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
831         enum ndr_err_code ndr_err;
832
833         if (ndr == NULL) {
834                 return false;
835         }
836
837         ndr->flags |= LIBNDR_FLAG_NOALIGN;
838
839         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version >> 16);
840         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
841                 return false;
842         }
843
844         blob = ndr_push_blob(ndr);
845         talloc_steal(mem_ctx, blob.data);
846         talloc_free(ndr);
847         *pblob = blob;
848         return true;
849 }
850
851 char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
852 {
853         switch (epm_floor->lhs.protocol) {
854         case EPM_PROTOCOL_TCP:
855                 if (epm_floor->rhs.tcp.port == 0) return NULL;
856                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.tcp.port);
857
858         case EPM_PROTOCOL_UDP:
859                 if (epm_floor->rhs.udp.port == 0) return NULL;
860                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.udp.port);
861
862         case EPM_PROTOCOL_HTTP:
863                 if (epm_floor->rhs.http.port == 0) return NULL;
864                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.http.port);
865
866         case EPM_PROTOCOL_IP:
867                 return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
868
869         case EPM_PROTOCOL_NCACN:
870                 return NULL;
871
872         case EPM_PROTOCOL_NCADG:
873                 return NULL;
874
875         case EPM_PROTOCOL_SMB:
876                 if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
877                 return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
878
879         case EPM_PROTOCOL_NAMED_PIPE:
880                 if (strlen(epm_floor->rhs.named_pipe.path) == 0) return NULL;
881                 return talloc_strdup(mem_ctx, epm_floor->rhs.named_pipe.path);
882
883         case EPM_PROTOCOL_NETBIOS:
884                 if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
885                 return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
886
887         case EPM_PROTOCOL_NCALRPC:
888                 return NULL;
889
890         case EPM_PROTOCOL_VINES_SPP:
891                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_spp.port);
892
893         case EPM_PROTOCOL_VINES_IPC:
894                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_ipc.port);
895
896         case EPM_PROTOCOL_STREETTALK:
897                 return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
898
899         case EPM_PROTOCOL_UNIX_DS:
900                 if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
901                 return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
902
903         case EPM_PROTOCOL_NULL:
904                 return NULL;
905
906         default:
907                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
908                 break;
909         }
910
911         return NULL;
912 }
913
914 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx, 
915                                           struct epm_floor *epm_floor,  
916                                           const char *data)
917 {
918         if (data == NULL) {
919                 data = "";
920         }
921
922         switch (epm_floor->lhs.protocol) {
923         case EPM_PROTOCOL_TCP:
924                 epm_floor->rhs.tcp.port = atoi(data);
925                 return NT_STATUS_OK;
926
927         case EPM_PROTOCOL_UDP:
928                 epm_floor->rhs.udp.port = atoi(data);
929                 return NT_STATUS_OK;
930
931         case EPM_PROTOCOL_HTTP:
932                 epm_floor->rhs.http.port = atoi(data);
933                 return NT_STATUS_OK;
934
935         case EPM_PROTOCOL_IP:
936                 if (!is_ipaddress_v4(data)) {
937                         data = "0.0.0.0";
938                 }
939                 epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
940                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
941                 return NT_STATUS_OK;
942
943         case EPM_PROTOCOL_NCACN:
944                 epm_floor->rhs.ncacn.minor_version = 0;
945                 return NT_STATUS_OK;
946
947         case EPM_PROTOCOL_NCADG:
948                 epm_floor->rhs.ncadg.minor_version = 0;
949                 return NT_STATUS_OK;
950
951         case EPM_PROTOCOL_SMB:
952                 epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
953                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
954                 return NT_STATUS_OK;
955
956         case EPM_PROTOCOL_NAMED_PIPE:
957                 epm_floor->rhs.named_pipe.path = talloc_strdup(mem_ctx, data);
958                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.named_pipe.path);
959                 return NT_STATUS_OK;
960
961         case EPM_PROTOCOL_NETBIOS:
962                 epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
963                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
964                 return NT_STATUS_OK;
965
966         case EPM_PROTOCOL_NCALRPC:
967                 return NT_STATUS_OK;
968
969         case EPM_PROTOCOL_VINES_SPP:
970                 epm_floor->rhs.vines_spp.port = atoi(data);
971                 return NT_STATUS_OK;
972
973         case EPM_PROTOCOL_VINES_IPC:
974                 epm_floor->rhs.vines_ipc.port = atoi(data);
975                 return NT_STATUS_OK;
976
977         case EPM_PROTOCOL_STREETTALK:
978                 epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
979                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
980                 return NT_STATUS_OK;
981
982         case EPM_PROTOCOL_UNIX_DS:
983                 epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
984                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
985                 return NT_STATUS_OK;
986
987         case EPM_PROTOCOL_NULL:
988                 return NT_STATUS_OK;
989
990         default:
991                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
992                 break;
993         }
994
995         return NT_STATUS_NOT_SUPPORTED;
996 }
997
998 enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
999 {
1000         int i;
1001
1002         /* Find a transport that has 'prot' as 4th protocol */
1003         for (i=0;i<ARRAY_SIZE(transports);i++) {
1004                 if (transports[i].num_protocols >= 2 && 
1005                         transports[i].protseq[1] == prot) {
1006                         return transports[i].transport;
1007                 }
1008         }
1009
1010         /* Unknown transport */
1011         return (unsigned int)-1;
1012 }
1013
1014 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower)
1015 {
1016         int i;
1017
1018         /* Find a transport that matches this tower */
1019         for (i=0;i<ARRAY_SIZE(transports);i++) {
1020                 int j;
1021                 if (transports[i].num_protocols != tower->num_floors - 2) {
1022                         continue; 
1023                 }
1024
1025                 for (j = 0; j < transports[i].num_protocols; j++) {
1026                         if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
1027                                 break;
1028                         }
1029                 }
1030
1031                 if (j == transports[i].num_protocols) {
1032                         return transports[i].transport;
1033                 }
1034         }
1035
1036         /* Unknown transport */
1037         return (unsigned int)-1;
1038 }
1039
1040 _PUBLIC_ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t)
1041 {
1042         int i;
1043
1044         for (i=0; i<ARRAY_SIZE(transports); i++) {
1045                 if (t == transports[i].transport) {
1046                         return transports[i].name;
1047                 }
1048         }
1049         return NULL;
1050 }
1051
1052 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_name(const char *name)
1053 {
1054         size_t i;
1055
1056         if (name == NULL) {
1057                 return NCA_UNKNOWN;
1058         }
1059
1060         for (i=0; i<ARRAY_SIZE(transports);i++) {
1061                 if (strcasecmp(name, transports[i].name) == 0) {
1062                         return transports[i].transport;
1063                 }
1064         }
1065
1066         return NCA_UNKNOWN;
1067 }
1068
1069 _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
1070                                             struct epm_tower *tower,
1071                                             struct dcerpc_binding **b_out)
1072 {
1073         NTSTATUS status;
1074         struct dcerpc_binding *binding;
1075
1076         /*
1077          * A tower needs to have at least 4 floors to carry useful
1078          * information. Floor 3 is the transport identifier which defines
1079          * how many floors are required at least.
1080          */
1081         if (tower->num_floors < 4) {
1082                 return NT_STATUS_INVALID_PARAMETER;
1083         }
1084
1085         binding = talloc_zero(mem_ctx, struct dcerpc_binding);
1086         NT_STATUS_HAVE_NO_MEMORY(binding);
1087
1088         ZERO_STRUCT(binding->object);
1089         binding->options = NULL;
1090         binding->host = NULL;
1091         binding->target_hostname = NULL;
1092         binding->flags = 0;
1093         binding->assoc_group_id = 0;
1094
1095         binding->transport = dcerpc_transport_by_tower(tower);
1096
1097         if (binding->transport == (unsigned int)-1) {
1098                 talloc_free(binding);
1099                 return NT_STATUS_NOT_SUPPORTED;
1100         }
1101
1102         /* Set object uuid */
1103         status = dcerpc_floor_get_lhs_data(&tower->floors[0], &binding->object);
1104
1105         if (!NT_STATUS_IS_OK(status)) {
1106                 DEBUG(1, ("Error pulling object uuid and version: %s", nt_errstr(status)));
1107                 talloc_free(binding);
1108                 return status;
1109         }
1110
1111         /* Ignore floor 1, it contains the NDR version info */
1112
1113         binding->options = NULL;
1114
1115         /* Set endpoint */
1116         errno = 0;
1117         if (tower->num_floors >= 4) {
1118                 binding->endpoint = dcerpc_floor_get_rhs_data(binding, &tower->floors[3]);
1119         }
1120         if (errno != 0) {
1121                 int saved_errno = errno;
1122                 talloc_free(binding);
1123                 return map_nt_error_from_unix_common(saved_errno);
1124         }
1125
1126         /* Set network address */
1127         errno = 0;
1128         if (tower->num_floors >= 5) {
1129                 binding->host = dcerpc_floor_get_rhs_data(binding, &tower->floors[4]);
1130         }
1131         if (errno != 0) {
1132                 int saved_errno = errno;
1133                 talloc_free(binding);
1134                 return map_nt_error_from_unix_common(saved_errno);
1135         }
1136         binding->target_hostname = binding->host;
1137
1138         *b_out = binding;
1139         return NT_STATUS_OK;
1140 }
1141
1142 _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
1143                                                    const struct dcerpc_binding *b)
1144 {
1145         struct dcerpc_binding *n;
1146         uint32_t count;
1147
1148         n = talloc_zero(mem_ctx, struct dcerpc_binding);
1149         if (n == NULL) {
1150                 return NULL;
1151         }
1152
1153         n->transport = b->transport;
1154         n->object = b->object;
1155         n->flags = b->flags;
1156         n->assoc_group_id = b->assoc_group_id;
1157
1158         if (b->object_string != NULL) {
1159                 n->object_string = talloc_strdup(n, b->object_string);
1160                 if (n->object_string == NULL) {
1161                         talloc_free(n);
1162                         return NULL;
1163                 }
1164         }
1165         if (b->host != NULL) {
1166                 n->host = talloc_strdup(n, b->host);
1167                 if (n->host == NULL) {
1168                         talloc_free(n);
1169                         return NULL;
1170                 }
1171         }
1172
1173         if (b->target_hostname != NULL) {
1174                 n->target_hostname = talloc_strdup(n, b->target_hostname);
1175                 if (n->target_hostname == NULL) {
1176                         talloc_free(n);
1177                         return NULL;
1178                 }
1179         }
1180
1181         if (b->target_principal != NULL) {
1182                 n->target_principal = talloc_strdup(n, b->target_principal);
1183                 if (n->target_principal == NULL) {
1184                         talloc_free(n);
1185                         return NULL;
1186                 }
1187         }
1188
1189         if (b->endpoint != NULL) {
1190                 n->endpoint = talloc_strdup(n, b->endpoint);
1191                 if (n->endpoint == NULL) {
1192                         talloc_free(n);
1193                         return NULL;
1194                 }
1195         }
1196
1197         for (count = 0; b->options && b->options[count]; count++);
1198
1199         if (count > 0) {
1200                 uint32_t i;
1201
1202                 n->options = talloc_array(n, const char *, count + 1);
1203                 if (n->options == NULL) {
1204                         talloc_free(n);
1205                         return NULL;
1206                 }
1207
1208                 for (i = 0; i < count; i++) {
1209                         n->options[i] = talloc_strdup(n->options, b->options[i]);
1210                         if (n->options[i] == NULL) {
1211                                 talloc_free(n);
1212                                 return NULL;
1213                         }
1214                 }
1215                 n->options[count] = NULL;
1216         }
1217
1218         return n;
1219 }
1220
1221 _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
1222                                              const struct dcerpc_binding *binding,
1223                                              struct epm_tower *tower)
1224 {
1225         const enum epm_protocol *protseq = NULL;
1226         int num_protocols = -1, i;
1227         NTSTATUS status;
1228
1229         /* Find transport */
1230         for (i=0;i<ARRAY_SIZE(transports);i++) {
1231                 if (transports[i].transport == binding->transport) {
1232                         protseq = transports[i].protseq;
1233                         num_protocols = transports[i].num_protocols;
1234                         break;
1235                 }
1236         }
1237
1238         if (num_protocols == -1) {
1239                 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
1240                 return NT_STATUS_UNSUCCESSFUL;
1241         }
1242
1243         tower->num_floors = 2 + num_protocols;
1244         tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
1245
1246         /* Floor 0 */
1247         tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
1248
1249         tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors, &binding->object);
1250
1251         if (!dcerpc_floor_pack_rhs_if_version_data(
1252                     tower->floors, &binding->object,
1253                     &tower->floors[0].rhs.uuid.unknown)) {
1254                 return NT_STATUS_NO_MEMORY;
1255         }
1256
1257         /* Floor 1 */
1258         tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
1259
1260         tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors, 
1261                                                                 &ndr_transfer_syntax_ndr);
1262
1263         tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(tower->floors, 2);
1264
1265         /* Floor 2 to num_protocols */
1266         for (i = 0; i < num_protocols; i++) {
1267                 tower->floors[2 + i].lhs.protocol = protseq[i];
1268                 tower->floors[2 + i].lhs.lhs_data = data_blob_null;
1269                 ZERO_STRUCT(tower->floors[2 + i].rhs);
1270                 status = dcerpc_floor_set_rhs_data(tower->floors,
1271                                                    &tower->floors[2 + i],
1272                                                    NULL);
1273                 if (!NT_STATUS_IS_OK(status)) {
1274                         return status;
1275                 }
1276         }
1277
1278         /* The 4th floor contains the endpoint */
1279         if (num_protocols >= 2 && binding->endpoint) {
1280                 status = dcerpc_floor_set_rhs_data(tower->floors,
1281                                                    &tower->floors[3],
1282                                                    binding->endpoint);
1283                 if (!NT_STATUS_IS_OK(status)) {
1284                         return status;
1285                 }
1286         }
1287
1288         /* The 5th contains the network address */
1289         if (num_protocols >= 3 && binding->host) {
1290                 status = dcerpc_floor_set_rhs_data(tower->floors,
1291                                                    &tower->floors[4],
1292                                                    binding->host);
1293                 if (!NT_STATUS_IS_OK(status)) {
1294                         return status;
1295                 }
1296         }
1297
1298         return NT_STATUS_OK;
1299 }