librpc/rpc: add dcerpc_binding_[g|s]et_flags()
[nivanova/samba-autobuild/.git] / librpc / rpc / binding.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    dcerpc utility functions
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Jelmer Vernooij 2004
8    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9    Copyright (C) Rafal Szczesniak 2006
10    Copyright (C) Stefan Metzmacher 2014
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "../../lib/util/util_net.h"
28 #include "librpc/gen_ndr/ndr_epmapper.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/rpc/dcerpc.h"
31 #include "rpc_common.h"
32
33 #undef strcasecmp
34 #undef strncasecmp
35
36 #define MAX_PROTSEQ             10
37
38 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_ void dcerpc_binding_get_auth_info(const struct dcerpc_binding *b,
432                                            enum dcerpc_AuthType *_auth_type,
433                                            enum dcerpc_AuthLevel *_auth_level)
434 {
435         enum dcerpc_AuthType auth_type;
436         enum dcerpc_AuthLevel auth_level;
437
438         if (b->flags & DCERPC_AUTH_SPNEGO) {
439                 auth_type = DCERPC_AUTH_TYPE_SPNEGO;
440         } else if (b->flags & DCERPC_AUTH_KRB5) {
441                 auth_type = DCERPC_AUTH_TYPE_KRB5;
442         } else if (b->flags & DCERPC_SCHANNEL) {
443                 auth_type = DCERPC_AUTH_TYPE_SCHANNEL;
444         } else if (b->flags & DCERPC_AUTH_NTLM) {
445                 auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
446         } else {
447                 auth_type = DCERPC_AUTH_TYPE_NONE;
448         }
449
450         if (b->flags & DCERPC_SEAL) {
451                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
452         } else if (b->flags & DCERPC_SIGN) {
453                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
454         } else if (b->flags & DCERPC_CONNECT) {
455                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
456         } else if (auth_type != DCERPC_AUTH_TYPE_NONE) {
457                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
458         } else {
459                 auth_level = DCERPC_AUTH_LEVEL_NONE;
460         }
461
462         if (_auth_type == NULL) {
463                 *_auth_type = auth_type;
464         }
465
466         if (_auth_level == NULL) {
467                 *_auth_level = auth_level;
468         }
469 }
470
471 _PUBLIC_ const char *dcerpc_binding_get_string_option(const struct dcerpc_binding *b,
472                                                       const char *name)
473 {
474         struct {
475                 const char *name;
476                 const char *value;
477 #define _SPECIAL(x) { .name = #x, .value = b->x, }
478         } specials[] = {
479                 { .name = "object", .value = b->object_string, },
480                 _SPECIAL(host),
481                 _SPECIAL(endpoint),
482                 _SPECIAL(target_hostname),
483                 _SPECIAL(target_principal),
484 #undef _SPECIAL
485         };
486         const struct ncacn_option *no = NULL;
487         size_t name_len = strlen(name);
488         size_t i;
489         int ret;
490
491         ret = strcmp(name, "transport");
492         if (ret == 0) {
493                 return derpc_transport_string_by_transport(b->transport);
494         }
495
496         for (i=0; i < ARRAY_SIZE(specials); i++) {
497                 ret = strcmp(specials[i].name, name);
498                 if (ret != 0) {
499                         continue;
500                 }
501
502                 return specials[i].value;
503         }
504
505         no = ncacn_option_by_name(name);
506         if (no != NULL) {
507                 if (b->flags & no->flag) {
508                         return no->name;
509                 }
510
511                 return NULL;
512         }
513
514         if (b->options == NULL) {
515                 return NULL;
516         }
517
518         for (i=0; b->options[i]; i++) {
519                 const char *o = b->options[i];
520                 const char *vs = NULL;
521
522                 ret = strncmp(name, o, name_len);
523                 if (ret != 0) {
524                         continue;
525                 }
526
527                 if (o[name_len] != '=') {
528                         continue;
529                 }
530
531                 vs = &o[name_len + 1];
532
533                 return vs;
534         }
535
536         return NULL;
537 }
538
539 _PUBLIC_ char *dcerpc_binding_copy_string_option(TALLOC_CTX *mem_ctx,
540                                                  const struct dcerpc_binding *b,
541                                                  const char *name)
542 {
543         const char *c = dcerpc_binding_get_string_option(b, name);
544         char *v;
545
546         if (c == NULL) {
547                 errno = ENOENT;
548                 return NULL;
549         }
550
551         v = talloc_strdup(mem_ctx, c);
552         if (v == NULL) {
553                 errno = ENOMEM;
554                 return NULL;
555         }
556
557         return v;
558 }
559
560 _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
561                                                    const char *name,
562                                                    const char *value)
563 {
564         struct {
565                 const char *name;
566                 const char **ptr;
567 #define _SPECIAL(x) { .name = #x, .ptr = &b->x, }
568         } specials[] = {
569                 _SPECIAL(host),
570                 _SPECIAL(endpoint),
571                 _SPECIAL(target_hostname),
572                 _SPECIAL(target_principal),
573 #undef _SPECIAL
574         };
575         const struct ncacn_option *no = NULL;
576         size_t name_len = strlen(name);
577         const char *opt = NULL;
578         char *tmp;
579         size_t i;
580         int ret;
581
582         /*
583          * Note: value == NULL, means delete it.
584          * value != NULL means add or reset.
585          */
586
587         ret = strcmp(name, "transport");
588         if (ret == 0) {
589                 enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
590
591                 if (t == NCA_UNKNOWN && value != NULL) {
592                         return NT_STATUS_INVALID_PARAMETER_MIX;
593                 }
594
595                 b->transport = t;
596                 return NT_STATUS_OK;
597         }
598
599         ret = strcmp(name, "object");
600         if (ret == 0) {
601                 DATA_BLOB blob;
602                 NTSTATUS status;
603                 struct GUID uuid;
604
605                 tmp = discard_const_p(char, b->object_string);
606
607                 if (value == NULL) {
608                         talloc_free(tmp);
609                         b->object_string = NULL;
610                         ZERO_STRUCT(b->object);
611                         return NT_STATUS_OK;
612                 }
613
614                 blob = data_blob_string_const(value);
615                 if (blob.length != 36) {
616                         return NT_STATUS_INVALID_PARAMETER_MIX;
617                 }
618
619                 status = GUID_from_data_blob(&blob, &uuid);
620                 if (!NT_STATUS_IS_OK(status)) {
621                         return status;
622                 }
623
624                 b->object_string = GUID_string(b, &uuid);
625                 if (b->object_string == NULL) {
626                         b->object_string = tmp;
627                         return NT_STATUS_NO_MEMORY;
628                 }
629                 talloc_free(tmp);
630
631                 ZERO_STRUCT(b->object);
632                 b->object.uuid = uuid;
633                 return NT_STATUS_OK;
634         }
635
636         for (i=0; i < ARRAY_SIZE(specials); i++) {
637                 ret = strcmp(specials[i].name, name);
638                 if (ret != 0) {
639                         continue;
640                 }
641
642                 tmp = discard_const_p(char, *specials[i].ptr);
643
644                 if (value == NULL) {
645                         talloc_free(tmp);
646                         *specials[i].ptr = NULL;
647                         return NT_STATUS_OK;
648                 }
649
650                 if (value[0] == '\0') {
651                         return NT_STATUS_INVALID_PARAMETER_MIX;
652                 }
653
654                 *specials[i].ptr = talloc_strdup(b, value);
655                 if (*specials[i].ptr == NULL) {
656                         *specials[i].ptr = tmp;
657                         return NT_STATUS_NO_MEMORY;
658                 }
659                 talloc_free(tmp);
660
661                 return NT_STATUS_OK;
662         }
663
664         no = ncacn_option_by_name(name);
665         if (no != NULL) {
666                 if (value == NULL) {
667                         b->flags &= ~no->flag;
668                         return NT_STATUS_OK;
669                 }
670
671                 ret = strcasecmp(no->name, value);
672                 if (ret != 0) {
673                         return NT_STATUS_INVALID_PARAMETER_MIX;
674                 }
675
676                 b->flags |= no->flag;
677                 return NT_STATUS_OK;
678         }
679
680         for (i=0; b->options && b->options[i]; i++) {
681                 const char *o = b->options[i];
682
683                 ret = strncmp(name, o, name_len);
684                 if (ret != 0) {
685                         continue;
686                 }
687
688                 if (o[name_len] != '=') {
689                         continue;
690                 }
691
692                 opt = o;
693                 break;
694         }
695
696         if (opt == NULL) {
697                 const char **n;
698
699                 if (value == NULL) {
700                         return NT_STATUS_OK;
701                 }
702
703                 n = talloc_realloc(b, b->options, const char *, i + 2);
704                 if (n == NULL) {
705                         return NT_STATUS_NO_MEMORY;
706                 }
707                 n[i] = NULL;
708                 n[i + 1] = NULL;
709                 b->options = n;
710         }
711
712         tmp = discard_const_p(char, opt);
713
714         if (value == NULL) {
715                 for (;b->options[i];i++) {
716                         b->options[i] = b->options[i+1];
717                 }
718                 talloc_free(tmp);
719                 return NT_STATUS_OK;
720         }
721
722         b->options[i] = talloc_asprintf(b->options, "%s=%s",
723                                         name, value);
724         if (b->options[i] == NULL) {
725                 b->options[i] = tmp;
726                 return NT_STATUS_NO_MEMORY;
727         }
728
729         return NT_STATUS_OK;
730 }
731
732 _PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
733 {
734         return b->flags;
735 }
736
737 _PUBLIC_ NTSTATUS dcerpc_binding_set_flags(struct dcerpc_binding *b,
738                                            uint32_t additional,
739                                            uint32_t clear)
740 {
741         /*
742          * TODO: in future we may want to reject invalid combinations
743          */
744         b->flags &= ~clear;
745         b->flags |= additional;
746
747         return NT_STATUS_OK;
748 }
749
750 _PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor,
751                                             struct ndr_syntax_id *syntax)
752 {
753         TALLOC_CTX *mem_ctx = talloc_init("floor_get_lhs_data");
754         struct ndr_pull *ndr;
755         enum ndr_err_code ndr_err;
756         uint16_t if_version=0;
757
758         ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
759         if (ndr == NULL) {
760                 talloc_free(mem_ctx);
761                 return NT_STATUS_NO_MEMORY;
762         }
763         ndr->flags |= LIBNDR_FLAG_NOALIGN;
764
765         ndr_err = ndr_pull_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
766         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
767                 talloc_free(mem_ctx);
768                 return ndr_map_error2ntstatus(ndr_err);
769         }
770
771         ndr_err = ndr_pull_uint16(ndr, NDR_SCALARS, &if_version);
772         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
773                 talloc_free(mem_ctx);
774                 return ndr_map_error2ntstatus(ndr_err);
775         }
776
777         syntax->if_version = if_version;
778
779         talloc_free(mem_ctx);
780
781         return NT_STATUS_OK;
782 }
783
784 static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
785 {
786         DATA_BLOB blob;
787         enum ndr_err_code ndr_err;
788         struct ndr_push *ndr;
789
790         ndr = ndr_push_init_ctx(mem_ctx);
791         if (ndr == NULL) {
792                 return data_blob_null;
793         }
794
795         ndr->flags |= LIBNDR_FLAG_NOALIGN;
796
797         ndr_err = ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
798         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
799                 return data_blob_null;
800         }
801         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
802         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
803                 return data_blob_null;
804         }
805
806         blob = ndr_push_blob(ndr);
807         talloc_steal(mem_ctx, blob.data);
808         talloc_free(ndr);
809         return blob;
810 }
811
812 static bool dcerpc_floor_pack_rhs_if_version_data(
813         TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax,
814         DATA_BLOB *pblob)
815 {
816         DATA_BLOB blob;
817         struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
818         enum ndr_err_code ndr_err;
819
820         if (ndr == NULL) {
821                 return false;
822         }
823
824         ndr->flags |= LIBNDR_FLAG_NOALIGN;
825
826         ndr_err = ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version >> 16);
827         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
828                 return false;
829         }
830
831         blob = ndr_push_blob(ndr);
832         talloc_steal(mem_ctx, blob.data);
833         talloc_free(ndr);
834         *pblob = blob;
835         return true;
836 }
837
838 char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
839 {
840         switch (epm_floor->lhs.protocol) {
841         case EPM_PROTOCOL_TCP:
842                 if (epm_floor->rhs.tcp.port == 0) return NULL;
843                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.tcp.port);
844
845         case EPM_PROTOCOL_UDP:
846                 if (epm_floor->rhs.udp.port == 0) return NULL;
847                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.udp.port);
848
849         case EPM_PROTOCOL_HTTP:
850                 if (epm_floor->rhs.http.port == 0) return NULL;
851                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.http.port);
852
853         case EPM_PROTOCOL_IP:
854                 return talloc_strdup(mem_ctx, epm_floor->rhs.ip.ipaddr);
855
856         case EPM_PROTOCOL_NCACN:
857                 return NULL;
858
859         case EPM_PROTOCOL_NCADG:
860                 return NULL;
861
862         case EPM_PROTOCOL_SMB:
863                 if (strlen(epm_floor->rhs.smb.unc) == 0) return NULL;
864                 return talloc_strdup(mem_ctx, epm_floor->rhs.smb.unc);
865
866         case EPM_PROTOCOL_NAMED_PIPE:
867                 if (strlen(epm_floor->rhs.named_pipe.path) == 0) return NULL;
868                 return talloc_strdup(mem_ctx, epm_floor->rhs.named_pipe.path);
869
870         case EPM_PROTOCOL_NETBIOS:
871                 if (strlen(epm_floor->rhs.netbios.name) == 0) return NULL;
872                 return talloc_strdup(mem_ctx, epm_floor->rhs.netbios.name);
873
874         case EPM_PROTOCOL_NCALRPC:
875                 return NULL;
876
877         case EPM_PROTOCOL_VINES_SPP:
878                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_spp.port);
879
880         case EPM_PROTOCOL_VINES_IPC:
881                 return talloc_asprintf(mem_ctx, "%d", epm_floor->rhs.vines_ipc.port);
882
883         case EPM_PROTOCOL_STREETTALK:
884                 return talloc_strdup(mem_ctx, epm_floor->rhs.streettalk.streettalk);
885
886         case EPM_PROTOCOL_UNIX_DS:
887                 if (strlen(epm_floor->rhs.unix_ds.path) == 0) return NULL;
888                 return talloc_strdup(mem_ctx, epm_floor->rhs.unix_ds.path);
889
890         case EPM_PROTOCOL_NULL:
891                 return NULL;
892
893         default:
894                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
895                 break;
896         }
897
898         return NULL;
899 }
900
901 static NTSTATUS dcerpc_floor_set_rhs_data(TALLOC_CTX *mem_ctx, 
902                                           struct epm_floor *epm_floor,  
903                                           const char *data)
904 {
905         if (data == NULL) {
906                 data = "";
907         }
908
909         switch (epm_floor->lhs.protocol) {
910         case EPM_PROTOCOL_TCP:
911                 epm_floor->rhs.tcp.port = atoi(data);
912                 return NT_STATUS_OK;
913
914         case EPM_PROTOCOL_UDP:
915                 epm_floor->rhs.udp.port = atoi(data);
916                 return NT_STATUS_OK;
917
918         case EPM_PROTOCOL_HTTP:
919                 epm_floor->rhs.http.port = atoi(data);
920                 return NT_STATUS_OK;
921
922         case EPM_PROTOCOL_IP:
923                 if (!is_ipaddress_v4(data)) {
924                         data = "0.0.0.0";
925                 }
926                 epm_floor->rhs.ip.ipaddr = talloc_strdup(mem_ctx, data);
927                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.ip.ipaddr);
928                 return NT_STATUS_OK;
929
930         case EPM_PROTOCOL_NCACN:
931                 epm_floor->rhs.ncacn.minor_version = 0;
932                 return NT_STATUS_OK;
933
934         case EPM_PROTOCOL_NCADG:
935                 epm_floor->rhs.ncadg.minor_version = 0;
936                 return NT_STATUS_OK;
937
938         case EPM_PROTOCOL_SMB:
939                 epm_floor->rhs.smb.unc = talloc_strdup(mem_ctx, data);
940                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.smb.unc);
941                 return NT_STATUS_OK;
942
943         case EPM_PROTOCOL_NAMED_PIPE:
944                 epm_floor->rhs.named_pipe.path = talloc_strdup(mem_ctx, data);
945                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.named_pipe.path);
946                 return NT_STATUS_OK;
947
948         case EPM_PROTOCOL_NETBIOS:
949                 epm_floor->rhs.netbios.name = talloc_strdup(mem_ctx, data);
950                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.netbios.name);
951                 return NT_STATUS_OK;
952
953         case EPM_PROTOCOL_NCALRPC:
954                 return NT_STATUS_OK;
955
956         case EPM_PROTOCOL_VINES_SPP:
957                 epm_floor->rhs.vines_spp.port = atoi(data);
958                 return NT_STATUS_OK;
959
960         case EPM_PROTOCOL_VINES_IPC:
961                 epm_floor->rhs.vines_ipc.port = atoi(data);
962                 return NT_STATUS_OK;
963
964         case EPM_PROTOCOL_STREETTALK:
965                 epm_floor->rhs.streettalk.streettalk = talloc_strdup(mem_ctx, data);
966                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.streettalk.streettalk);
967                 return NT_STATUS_OK;
968
969         case EPM_PROTOCOL_UNIX_DS:
970                 epm_floor->rhs.unix_ds.path = talloc_strdup(mem_ctx, data);
971                 NT_STATUS_HAVE_NO_MEMORY(epm_floor->rhs.unix_ds.path);
972                 return NT_STATUS_OK;
973
974         case EPM_PROTOCOL_NULL:
975                 return NT_STATUS_OK;
976
977         default:
978                 DEBUG(0,("Unsupported lhs protocol %d\n", epm_floor->lhs.protocol));
979                 break;
980         }
981
982         return NT_STATUS_NOT_SUPPORTED;
983 }
984
985 enum dcerpc_transport_t dcerpc_transport_by_endpoint_protocol(int prot)
986 {
987         int i;
988
989         /* Find a transport that has 'prot' as 4th protocol */
990         for (i=0;i<ARRAY_SIZE(transports);i++) {
991                 if (transports[i].num_protocols >= 2 && 
992                         transports[i].protseq[1] == prot) {
993                         return transports[i].transport;
994                 }
995         }
996
997         /* Unknown transport */
998         return (unsigned int)-1;
999 }
1000
1001 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_tower(const struct epm_tower *tower)
1002 {
1003         int i;
1004
1005         /* Find a transport that matches this tower */
1006         for (i=0;i<ARRAY_SIZE(transports);i++) {
1007                 int j;
1008                 if (transports[i].num_protocols != tower->num_floors - 2) {
1009                         continue; 
1010                 }
1011
1012                 for (j = 0; j < transports[i].num_protocols; j++) {
1013                         if (transports[i].protseq[j] != tower->floors[j+2].lhs.protocol) {
1014                                 break;
1015                         }
1016                 }
1017
1018                 if (j == transports[i].num_protocols) {
1019                         return transports[i].transport;
1020                 }
1021         }
1022
1023         /* Unknown transport */
1024         return (unsigned int)-1;
1025 }
1026
1027 _PUBLIC_ const char *derpc_transport_string_by_transport(enum dcerpc_transport_t t)
1028 {
1029         int i;
1030
1031         for (i=0; i<ARRAY_SIZE(transports); i++) {
1032                 if (t == transports[i].transport) {
1033                         return transports[i].name;
1034                 }
1035         }
1036         return NULL;
1037 }
1038
1039 _PUBLIC_ enum dcerpc_transport_t dcerpc_transport_by_name(const char *name)
1040 {
1041         size_t i;
1042
1043         if (name == NULL) {
1044                 return NCA_UNKNOWN;
1045         }
1046
1047         for (i=0; i<ARRAY_SIZE(transports);i++) {
1048                 if (strcasecmp(name, transports[i].name) == 0) {
1049                         return transports[i].transport;
1050                 }
1051         }
1052
1053         return NCA_UNKNOWN;
1054 }
1055
1056 _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
1057                                             struct epm_tower *tower,
1058                                             struct dcerpc_binding **b_out)
1059 {
1060         NTSTATUS status;
1061         struct dcerpc_binding *binding;
1062
1063         /*
1064          * A tower needs to have at least 4 floors to carry useful
1065          * information. Floor 3 is the transport identifier which defines
1066          * how many floors are required at least.
1067          */
1068         if (tower->num_floors < 4) {
1069                 return NT_STATUS_INVALID_PARAMETER;
1070         }
1071
1072         binding = talloc_zero(mem_ctx, struct dcerpc_binding);
1073         NT_STATUS_HAVE_NO_MEMORY(binding);
1074
1075         ZERO_STRUCT(binding->object);
1076         binding->options = NULL;
1077         binding->host = NULL;
1078         binding->target_hostname = NULL;
1079         binding->flags = 0;
1080         binding->assoc_group_id = 0;
1081
1082         binding->transport = dcerpc_transport_by_tower(tower);
1083
1084         if (binding->transport == (unsigned int)-1) {
1085                 talloc_free(binding);
1086                 return NT_STATUS_NOT_SUPPORTED;
1087         }
1088
1089         /* Set object uuid */
1090         status = dcerpc_floor_get_lhs_data(&tower->floors[0], &binding->object);
1091
1092         if (!NT_STATUS_IS_OK(status)) {
1093                 DEBUG(1, ("Error pulling object uuid and version: %s", nt_errstr(status)));
1094                 talloc_free(binding);
1095                 return status;
1096         }
1097
1098         /* Ignore floor 1, it contains the NDR version info */
1099
1100         binding->options = NULL;
1101
1102         /* Set endpoint */
1103         errno = 0;
1104         if (tower->num_floors >= 4) {
1105                 binding->endpoint = dcerpc_floor_get_rhs_data(binding, &tower->floors[3]);
1106         }
1107         if (errno != 0) {
1108                 int saved_errno = errno;
1109                 talloc_free(binding);
1110                 return map_nt_error_from_unix_common(saved_errno);
1111         }
1112
1113         /* Set network address */
1114         errno = 0;
1115         if (tower->num_floors >= 5) {
1116                 binding->host = dcerpc_floor_get_rhs_data(binding, &tower->floors[4]);
1117         }
1118         if (errno != 0) {
1119                 int saved_errno = errno;
1120                 talloc_free(binding);
1121                 return map_nt_error_from_unix_common(saved_errno);
1122         }
1123         binding->target_hostname = binding->host;
1124
1125         *b_out = binding;
1126         return NT_STATUS_OK;
1127 }
1128
1129 _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
1130                                                    const struct dcerpc_binding *b)
1131 {
1132         struct dcerpc_binding *n;
1133         uint32_t count;
1134
1135         n = talloc_zero(mem_ctx, struct dcerpc_binding);
1136         if (n == NULL) {
1137                 return NULL;
1138         }
1139
1140         n->transport = b->transport;
1141         n->object = b->object;
1142         n->flags = b->flags;
1143         n->assoc_group_id = b->assoc_group_id;
1144
1145         if (b->object_string != NULL) {
1146                 n->object_string = talloc_strdup(n, b->object_string);
1147                 if (n->object_string == NULL) {
1148                         talloc_free(n);
1149                         return NULL;
1150                 }
1151         }
1152         if (b->host != NULL) {
1153                 n->host = talloc_strdup(n, b->host);
1154                 if (n->host == NULL) {
1155                         talloc_free(n);
1156                         return NULL;
1157                 }
1158         }
1159
1160         if (b->target_hostname != NULL) {
1161                 n->target_hostname = talloc_strdup(n, b->target_hostname);
1162                 if (n->target_hostname == NULL) {
1163                         talloc_free(n);
1164                         return NULL;
1165                 }
1166         }
1167
1168         if (b->target_principal != NULL) {
1169                 n->target_principal = talloc_strdup(n, b->target_principal);
1170                 if (n->target_principal == NULL) {
1171                         talloc_free(n);
1172                         return NULL;
1173                 }
1174         }
1175
1176         if (b->endpoint != NULL) {
1177                 n->endpoint = talloc_strdup(n, b->endpoint);
1178                 if (n->endpoint == NULL) {
1179                         talloc_free(n);
1180                         return NULL;
1181                 }
1182         }
1183
1184         for (count = 0; b->options && b->options[count]; count++);
1185
1186         if (count > 0) {
1187                 uint32_t i;
1188
1189                 n->options = talloc_array(n, const char *, count + 1);
1190                 if (n->options == NULL) {
1191                         talloc_free(n);
1192                         return NULL;
1193                 }
1194
1195                 for (i = 0; i < count; i++) {
1196                         n->options[i] = talloc_strdup(n->options, b->options[i]);
1197                         if (n->options[i] == NULL) {
1198                                 talloc_free(n);
1199                                 return NULL;
1200                         }
1201                 }
1202                 n->options[count] = NULL;
1203         }
1204
1205         return n;
1206 }
1207
1208 _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
1209                                              const struct dcerpc_binding *binding,
1210                                              struct epm_tower *tower)
1211 {
1212         const enum epm_protocol *protseq = NULL;
1213         int num_protocols = -1, i;
1214         NTSTATUS status;
1215
1216         /* Find transport */
1217         for (i=0;i<ARRAY_SIZE(transports);i++) {
1218                 if (transports[i].transport == binding->transport) {
1219                         protseq = transports[i].protseq;
1220                         num_protocols = transports[i].num_protocols;
1221                         break;
1222                 }
1223         }
1224
1225         if (num_protocols == -1) {
1226                 DEBUG(0, ("Unable to find transport with id '%d'\n", binding->transport));
1227                 return NT_STATUS_UNSUCCESSFUL;
1228         }
1229
1230         tower->num_floors = 2 + num_protocols;
1231         tower->floors = talloc_array(mem_ctx, struct epm_floor, tower->num_floors);
1232
1233         /* Floor 0 */
1234         tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
1235
1236         tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors, &binding->object);
1237
1238         if (!dcerpc_floor_pack_rhs_if_version_data(
1239                     tower->floors, &binding->object,
1240                     &tower->floors[0].rhs.uuid.unknown)) {
1241                 return NT_STATUS_NO_MEMORY;
1242         }
1243
1244         /* Floor 1 */
1245         tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
1246
1247         tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors, 
1248                                                                 &ndr_transfer_syntax_ndr);
1249
1250         tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(tower->floors, 2);
1251
1252         /* Floor 2 to num_protocols */
1253         for (i = 0; i < num_protocols; i++) {
1254                 tower->floors[2 + i].lhs.protocol = protseq[i];
1255                 tower->floors[2 + i].lhs.lhs_data = data_blob_null;
1256                 ZERO_STRUCT(tower->floors[2 + i].rhs);
1257                 status = dcerpc_floor_set_rhs_data(tower->floors,
1258                                                    &tower->floors[2 + i],
1259                                                    NULL);
1260                 if (!NT_STATUS_IS_OK(status)) {
1261                         return status;
1262                 }
1263         }
1264
1265         /* The 4th floor contains the endpoint */
1266         if (num_protocols >= 2 && binding->endpoint) {
1267                 status = dcerpc_floor_set_rhs_data(tower->floors,
1268                                                    &tower->floors[3],
1269                                                    binding->endpoint);
1270                 if (!NT_STATUS_IS_OK(status)) {
1271                         return status;
1272                 }
1273         }
1274
1275         /* The 5th contains the network address */
1276         if (num_protocols >= 3 && binding->host) {
1277                 status = dcerpc_floor_set_rhs_data(tower->floors,
1278                                                    &tower->floors[4],
1279                                                    binding->host);
1280                 if (!NT_STATUS_IS_OK(status)) {
1281                         return status;
1282                 }
1283         }
1284
1285         return NT_STATUS_OK;
1286 }