Coverage Report

Created: 2026-06-07 07:07

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