Coverage Report

Created: 2025-07-18 07:02

/src/bind9/lib/dns/ssu.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <stdbool.h>
17
18
#include <isc/magic.h>
19
#include <isc/mem.h>
20
#include <isc/netaddr.h>
21
#include <isc/refcount.h>
22
#include <isc/result.h>
23
#include <isc/string.h>
24
#include <isc/util.h>
25
26
#include <dns/dlz.h>
27
#include <dns/fixedname.h>
28
#include <dns/name.h>
29
#include <dns/ssu.h>
30
31
#include <dst/dst.h>
32
#include <dst/gssapi.h>
33
34
0
#define SSUTABLEMAGIC       ISC_MAGIC('S', 'S', 'U', 'T')
35
#define VALID_SSUTABLE(table) ISC_MAGIC_VALID(table, SSUTABLEMAGIC)
36
37
0
#define SSURULEMAGIC       ISC_MAGIC('S', 'S', 'U', 'R')
38
#define VALID_SSURULE(table) ISC_MAGIC_VALID(table, SSURULEMAGIC)
39
40
struct dns_ssurule {
41
  unsigned int magic;
42
  bool grant;         /*%< is this a grant or a deny? */
43
  dns_ssumatchtype_t matchtype; /*%< which type of pattern match? */
44
  dns_name_t *identity;       /*%< the identity to match */
45
  dns_name_t *name;       /*%< the name being updated */
46
  unsigned int ntypes;        /*%< number of data types covered */
47
  dns_ssuruletype_t *types;     /*%< the data types.  Can include */
48
              /*   ANY. if NULL, defaults to all */
49
              /*   types except SIG, SOA, and NS */
50
  char *debug;          /*%< text version for debugging */
51
  ISC_LINK(dns_ssurule_t) link;
52
};
53
54
struct dns_ssutable {
55
  unsigned int magic;
56
  isc_mem_t *mctx;
57
  isc_refcount_t references;
58
  dns_dlzdb_t *dlzdatabase;
59
  ISC_LIST(dns_ssurule_t) rules;
60
};
61
62
void
63
0
dns_ssutable_create(isc_mem_t *mctx, dns_ssutable_t **tablep) {
64
0
  dns_ssutable_t *table;
65
66
0
  REQUIRE(tablep != NULL && *tablep == NULL);
67
0
  REQUIRE(mctx != NULL);
68
69
0
  table = isc_mem_get(mctx, sizeof(*table));
70
0
  isc_refcount_init(&table->references, 1);
71
0
  table->mctx = NULL;
72
0
  isc_mem_attach(mctx, &table->mctx);
73
0
  ISC_LIST_INIT(table->rules);
74
0
  table->magic = SSUTABLEMAGIC;
75
0
  *tablep = table;
76
0
}
77
78
static void
79
0
destroy(dns_ssutable_t *table) {
80
0
  isc_mem_t *mctx;
81
82
0
  REQUIRE(VALID_SSUTABLE(table));
83
84
0
  mctx = table->mctx;
85
0
  ISC_LIST_FOREACH (table->rules, rule, link) {
86
0
    if (rule->identity != NULL) {
87
0
      dns_name_free(rule->identity, mctx);
88
0
      isc_mem_put(mctx, rule->identity,
89
0
            sizeof(*rule->identity));
90
0
    }
91
0
    if (rule->name != NULL) {
92
0
      dns_name_free(rule->name, mctx);
93
0
      isc_mem_put(mctx, rule->name, sizeof(*rule->name));
94
0
    }
95
0
    if (rule->types != NULL) {
96
0
      isc_mem_cput(mctx, rule->types, rule->ntypes,
97
0
             sizeof(*rule->types));
98
0
    }
99
0
    if (rule->debug != NULL) {
100
0
      isc_mem_free(mctx, rule->debug);
101
0
    }
102
0
    ISC_LIST_UNLINK(table->rules, rule, link);
103
0
    rule->magic = 0;
104
0
    isc_mem_put(mctx, rule, sizeof(dns_ssurule_t));
105
0
  }
106
0
  isc_refcount_destroy(&table->references);
107
0
  table->magic = 0;
108
0
  isc_mem_putanddetach(&table->mctx, table, sizeof(dns_ssutable_t));
109
0
}
110
111
void
112
0
dns_ssutable_attach(dns_ssutable_t *source, dns_ssutable_t **targetp) {
113
0
  REQUIRE(VALID_SSUTABLE(source));
114
0
  REQUIRE(targetp != NULL && *targetp == NULL);
115
116
0
  isc_refcount_increment(&source->references);
117
118
0
  *targetp = source;
119
0
}
120
121
void
122
0
dns_ssutable_detach(dns_ssutable_t **tablep) {
123
0
  dns_ssutable_t *table;
124
125
0
  REQUIRE(tablep != NULL);
126
0
  table = *tablep;
127
0
  *tablep = NULL;
128
0
  REQUIRE(VALID_SSUTABLE(table));
129
130
0
  if (isc_refcount_decrement(&table->references) == 1) {
131
0
    destroy(table);
132
0
  }
133
0
}
134
135
static const char *
136
0
mtypetostring(dns_ssumatchtype_t matchtype) {
137
0
  switch (matchtype) {
138
0
  case dns_ssumatchtype_name:
139
0
    return "name";
140
0
  case dns_ssumatchtype_wildcard:
141
0
    return "wildcard";
142
0
  case dns_ssumatchtype_self:
143
0
    return "self";
144
0
  case dns_ssumatchtype_selfsub:
145
0
    return "selfsub";
146
0
  case dns_ssumatchtype_selfwild:
147
0
    return "selfwild";
148
0
  case dns_ssumatchtype_selfms:
149
0
    return "ms-self";
150
0
  case dns_ssumatchtype_selfsubms:
151
0
    return "ms-selfsub";
152
0
  case dns_ssumatchtype_selfkrb5:
153
0
    return "krb5-self";
154
0
  case dns_ssumatchtype_selfsubkrb5:
155
0
    return "krb5-selfsub";
156
0
  case dns_ssumatchtype_subdomainms:
157
0
    return "ms-subdomain";
158
0
  case dns_ssumatchtype_subdomainselfmsrhs:
159
0
    return "ms-subdomain-self-rhs";
160
0
  case dns_ssumatchtype_subdomainkrb5:
161
0
    return "krb5-subdomain";
162
0
  case dns_ssumatchtype_subdomainselfkrb5rhs:
163
0
    return "krb5-subdomain-self-rhs";
164
0
  case dns_ssumatchtype_tcpself:
165
0
    return "tcp-self";
166
0
  case dns_ssumatchtype_6to4self:
167
0
    return "6to4-self";
168
0
  case dns_ssumatchtype_subdomain:
169
0
    return "subdomain";
170
0
  case dns_ssumatchtype_external:
171
0
    return "external";
172
0
  case dns_ssumatchtype_local:
173
0
    return "local";
174
0
  case dns_ssumatchtype_dlz:
175
0
    return "dlz";
176
0
  }
177
0
  return "UnknownMatchType";
178
0
}
179
180
void
181
dns_ssutable_addrule(dns_ssutable_t *table, bool grant,
182
         const dns_name_t *identity, dns_ssumatchtype_t matchtype,
183
         const dns_name_t *name, unsigned int ntypes,
184
0
         dns_ssuruletype_t *types, const char *debug) {
185
0
  dns_ssurule_t *rule;
186
0
  isc_mem_t *mctx;
187
188
0
  REQUIRE(VALID_SSUTABLE(table));
189
0
  REQUIRE(dns_name_isabsolute(identity));
190
0
  REQUIRE(dns_name_isabsolute(name));
191
0
  REQUIRE(matchtype <= dns_ssumatchtype_max);
192
0
  if (matchtype == dns_ssumatchtype_wildcard) {
193
0
    REQUIRE(dns_name_iswildcard(name));
194
0
  }
195
0
  if (ntypes > 0) {
196
0
    REQUIRE(types != NULL);
197
0
  }
198
0
  REQUIRE(debug != NULL);
199
200
0
  mctx = table->mctx;
201
0
  rule = isc_mem_get(mctx, sizeof(*rule));
202
0
  *rule = (dns_ssurule_t){
203
0
    .grant = grant,
204
0
    .matchtype = matchtype,
205
0
    .identity = isc_mem_get(mctx, sizeof(*rule->identity)),
206
0
    .name = isc_mem_get(mctx, sizeof(*rule->name)),
207
0
    .ntypes = ntypes,
208
0
    .types = ntypes == 0 ? NULL
209
0
             : isc_mem_cget(mctx, ntypes,
210
0
                sizeof(*rule->types)),
211
0
    .link = ISC_LINK_INITIALIZER,
212
0
    .magic = SSURULEMAGIC,
213
0
  };
214
215
0
  dns_name_init(rule->identity);
216
0
  dns_name_dup(identity, mctx, rule->identity);
217
0
  dns_name_init(rule->name);
218
0
  dns_name_dup(name, mctx, rule->name);
219
220
0
  if (ntypes > 0) {
221
0
    memmove(rule->types, types, ntypes * sizeof(*rule->types));
222
0
  }
223
224
0
  rule->debug = isc_mem_strdup(mctx, debug);
225
226
0
  ISC_LIST_INITANDAPPEND(table->rules, rule, link);
227
0
}
228
229
static bool
230
0
isusertype(dns_rdatatype_t type) {
231
0
  return type != dns_rdatatype_ns && type != dns_rdatatype_soa &&
232
0
         type != dns_rdatatype_rrsig;
233
0
}
234
235
static void
236
0
reverse_from_address(dns_name_t *tcpself, const isc_netaddr_t *tcpaddr) {
237
0
  char buf[16 * 4 + sizeof("IP6.ARPA.")];
238
0
  isc_result_t result;
239
0
  const unsigned char *ap;
240
0
  isc_buffer_t b;
241
0
  unsigned long l;
242
243
0
  switch (tcpaddr->family) {
244
0
  case AF_INET:
245
0
    l = ntohl(tcpaddr->type.in.s_addr);
246
0
    result = snprintf(buf, sizeof(buf),
247
0
          "%lu.%lu.%lu.%lu.IN-ADDR.ARPA.",
248
0
          (l >> 0) & 0xff, (l >> 8) & 0xff,
249
0
          (l >> 16) & 0xff, (l >> 24) & 0xff);
250
0
    RUNTIME_CHECK(result < sizeof(buf));
251
0
    break;
252
0
  case AF_INET6:
253
0
    ap = tcpaddr->type.in6.s6_addr;
254
0
    result = snprintf(
255
0
      buf, sizeof(buf),
256
0
      "%x.%x.%x.%x.%x.%x.%x.%x."
257
0
      "%x.%x.%x.%x.%x.%x.%x.%x."
258
0
      "%x.%x.%x.%x.%x.%x.%x.%x."
259
0
      "%x.%x.%x.%x.%x.%x.%x.%x."
260
0
      "IP6.ARPA.",
261
0
      ap[15] & 0x0f, (ap[15] >> 4) & 0x0f, ap[14] & 0x0f,
262
0
      (ap[14] >> 4) & 0x0f, ap[13] & 0x0f,
263
0
      (ap[13] >> 4) & 0x0f, ap[12] & 0x0f,
264
0
      (ap[12] >> 4) & 0x0f, ap[11] & 0x0f,
265
0
      (ap[11] >> 4) & 0x0f, ap[10] & 0x0f,
266
0
      (ap[10] >> 4) & 0x0f, ap[9] & 0x0f, (ap[9] >> 4) & 0x0f,
267
0
      ap[8] & 0x0f, (ap[8] >> 4) & 0x0f, ap[7] & 0x0f,
268
0
      (ap[7] >> 4) & 0x0f, ap[6] & 0x0f, (ap[6] >> 4) & 0x0f,
269
0
      ap[5] & 0x0f, (ap[5] >> 4) & 0x0f, ap[4] & 0x0f,
270
0
      (ap[4] >> 4) & 0x0f, ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
271
0
      ap[2] & 0x0f, (ap[2] >> 4) & 0x0f, ap[1] & 0x0f,
272
0
      (ap[1] >> 4) & 0x0f, ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
273
0
    RUNTIME_CHECK(result < sizeof(buf));
274
0
    break;
275
0
  default:
276
0
    UNREACHABLE();
277
0
  }
278
0
  isc_buffer_init(&b, buf, strlen(buf));
279
0
  isc_buffer_add(&b, strlen(buf));
280
0
  result = dns_name_fromtext(tcpself, &b, dns_rootname, 0);
281
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
282
0
}
283
284
static void
285
0
stf_from_address(dns_name_t *stfself, const isc_netaddr_t *tcpaddr) {
286
0
  char buf[sizeof("X.X.X.X.Y.Y.Y.Y.2.0.0.2.IP6.ARPA.")];
287
0
  isc_result_t result;
288
0
  const unsigned char *ap;
289
0
  isc_buffer_t b;
290
0
  unsigned long l;
291
292
0
  switch (tcpaddr->family) {
293
0
  case AF_INET:
294
0
    l = ntohl(tcpaddr->type.in.s_addr);
295
0
    result = snprintf(
296
0
      buf, sizeof(buf),
297
0
      "%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.2.0.0.2.IP6.ARPA.",
298
0
      l & 0xf, (l >> 4) & 0xf, (l >> 8) & 0xf,
299
0
      (l >> 12) & 0xf, (l >> 16) & 0xf, (l >> 20) & 0xf,
300
0
      (l >> 24) & 0xf, (l >> 28) & 0xf);
301
0
    RUNTIME_CHECK(result < sizeof(buf));
302
0
    break;
303
0
  case AF_INET6:
304
0
    ap = tcpaddr->type.in6.s6_addr;
305
0
    result = snprintf(
306
0
      buf, sizeof(buf),
307
0
      "%x.%x.%x.%x.%x.%x.%x.%x."
308
0
      "%x.%x.%x.%x.IP6.ARPA.",
309
0
      ap[5] & 0x0f, (ap[5] >> 4) & 0x0f, ap[4] & 0x0f,
310
0
      (ap[4] >> 4) & 0x0f, ap[3] & 0x0f, (ap[3] >> 4) & 0x0f,
311
0
      ap[2] & 0x0f, (ap[2] >> 4) & 0x0f, ap[1] & 0x0f,
312
0
      (ap[1] >> 4) & 0x0f, ap[0] & 0x0f, (ap[0] >> 4) & 0x0f);
313
0
    RUNTIME_CHECK(result < sizeof(buf));
314
0
    break;
315
0
  default:
316
0
    UNREACHABLE();
317
0
  }
318
0
  isc_buffer_init(&b, buf, strlen(buf));
319
0
  isc_buffer_add(&b, strlen(buf));
320
0
  result = dns_name_fromtext(stfself, &b, dns_rootname, 0);
321
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
322
0
}
323
324
bool
325
dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer,
326
      const dns_name_t *name, const isc_netaddr_t *addr,
327
      bool tcp, dns_aclenv_t *env, dns_rdatatype_t type,
328
      const dns_name_t *target, const dst_key_t *key,
329
0
      const dns_ssurule_t **rulep) {
330
0
  dns_fixedname_t fixed;
331
0
  dns_name_t *stfself;
332
0
  dns_name_t *tcpself;
333
0
  dns_name_t *wildcard;
334
0
  const dns_name_t *tname;
335
0
  int match;
336
0
  isc_result_t result;
337
0
  unsigned int i;
338
0
  bool logit = isc_log_wouldlog(99);
339
340
0
  REQUIRE(VALID_SSUTABLE(table));
341
0
  REQUIRE(signer == NULL || dns_name_isabsolute(signer));
342
0
  REQUIRE(dns_name_isabsolute(name));
343
0
  REQUIRE(addr == NULL || env != NULL);
344
345
0
  if (logit) {
346
0
    char signerbuf[DNS_NAME_FORMATSIZE] = { 0 };
347
0
    char namebuf[DNS_NAME_FORMATSIZE] = { 0 };
348
0
    char targetbuf[DNS_NAME_FORMATSIZE] = { 0 };
349
0
    char addrbuf[ISC_NETADDR_FORMATSIZE] = { 0 };
350
0
    char typebuf[DNS_RDATATYPE_FORMATSIZE] = { 0 };
351
352
0
    if (signer != NULL) {
353
0
      dns_name_format(signer, signerbuf, sizeof(signerbuf));
354
0
    }
355
0
    dns_name_format(name, namebuf, sizeof(namebuf));
356
0
    if (target != NULL) {
357
0
      dns_name_format(target, targetbuf, sizeof(targetbuf));
358
0
    }
359
0
    dns_rdatatype_format(type, typebuf, sizeof(typebuf));
360
0
    if (addr != NULL) {
361
0
      isc_netaddr_format(addr, addrbuf, sizeof(addrbuf));
362
0
    }
363
364
0
    isc_log_write(DNS_LOGCATEGORY_UPDATE_POLICY, DNS_LOGMODULE_SSU,
365
0
            ISC_LOG_DEBUG(99),
366
0
            "update-policy: using: signer=%s name=%s addr=%s "
367
0
            "tcp=%u type=%s target=%s",
368
0
            signerbuf, namebuf, addrbuf, tcp, typebuf,
369
0
            targetbuf);
370
0
  }
371
372
0
  if (signer == NULL && addr == NULL) {
373
0
    return false;
374
0
  }
375
376
0
  ISC_LIST_FOREACH (table->rules, rule, link) {
377
0
    if (logit) {
378
0
      isc_log_write(DNS_LOGCATEGORY_UPDATE_POLICY,
379
0
              DNS_LOGMODULE_SSU, ISC_LOG_DEBUG(99),
380
0
              "update-policy: trying: %s",
381
0
              rule->debug != NULL ? rule->debug
382
0
                : "not available");
383
384
0
      if (tcp && addr != NULL) {
385
0
        char namebuf[DNS_NAME_FORMATSIZE] = { 0 };
386
0
        switch (rule->matchtype) {
387
0
        case dns_ssumatchtype_tcpself:
388
0
          tcpself =
389
0
            dns_fixedname_initname(&fixed);
390
0
          reverse_from_address(tcpself, addr);
391
0
          dns_name_format(tcpself, namebuf,
392
0
              sizeof(namebuf));
393
0
          isc_log_write(
394
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
395
0
            DNS_LOGMODULE_SSU,
396
0
            ISC_LOG_DEBUG(99),
397
0
            "update-policy: %s=%s",
398
0
            mtypetostring(rule->matchtype),
399
0
            namebuf);
400
0
          break;
401
0
        case dns_ssumatchtype_6to4self:
402
0
          stfself =
403
0
            dns_fixedname_initname(&fixed);
404
0
          stf_from_address(stfself, addr);
405
0
          dns_name_format(stfself, namebuf,
406
0
              sizeof(namebuf));
407
0
          isc_log_write(
408
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
409
0
            DNS_LOGMODULE_SSU,
410
0
            ISC_LOG_DEBUG(99),
411
0
            "update-policy: %s=%s",
412
0
            mtypetostring(rule->matchtype),
413
0
            namebuf);
414
0
          break;
415
0
        default:
416
0
          break;
417
0
        }
418
0
      }
419
0
    }
420
0
    switch (rule->matchtype) {
421
0
    case dns_ssumatchtype_local:
422
0
    case dns_ssumatchtype_name:
423
0
    case dns_ssumatchtype_self:
424
0
    case dns_ssumatchtype_selfsub:
425
0
    case dns_ssumatchtype_selfwild:
426
0
    case dns_ssumatchtype_subdomain:
427
0
    case dns_ssumatchtype_wildcard:
428
0
      if (signer == NULL) {
429
0
        if (logit) {
430
0
          isc_log_write(
431
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
432
0
            DNS_LOGMODULE_SSU,
433
0
            ISC_LOG_DEBUG(99),
434
0
            "update-policy: next "
435
0
            "rule: no signer");
436
0
        }
437
0
        continue;
438
0
      }
439
0
      if (dns_name_iswildcard(rule->identity)) {
440
0
        if (!dns_name_matcheswildcard(signer,
441
0
                    rule->identity))
442
0
        {
443
0
          if (logit) {
444
0
            isc_log_write(
445
0
              DNS_LOGCATEGORY_UPDATE_POLICY,
446
0
              DNS_LOGMODULE_SSU,
447
0
              ISC_LOG_DEBUG(99),
448
0
              "update-policy: next "
449
0
              "rule: signer does not "
450
0
              "match wildcard "
451
0
              "identity");
452
0
          }
453
0
          continue;
454
0
        }
455
0
      } else {
456
0
        if (!dns_name_equal(signer, rule->identity)) {
457
0
          if (logit) {
458
0
            isc_log_write(
459
0
              DNS_LOGCATEGORY_UPDATE_POLICY,
460
0
              DNS_LOGMODULE_SSU,
461
0
              ISC_LOG_DEBUG(99),
462
0
              "update-policy: next "
463
0
              "rule: signer does not "
464
0
              "match identity");
465
0
          }
466
0
          continue;
467
0
        }
468
0
      }
469
0
      break;
470
0
    case dns_ssumatchtype_selfkrb5:
471
0
    case dns_ssumatchtype_selfms:
472
0
    case dns_ssumatchtype_selfsubkrb5:
473
0
    case dns_ssumatchtype_selfsubms:
474
0
    case dns_ssumatchtype_subdomainkrb5:
475
0
    case dns_ssumatchtype_subdomainms:
476
0
    case dns_ssumatchtype_subdomainselfkrb5rhs:
477
0
    case dns_ssumatchtype_subdomainselfmsrhs:
478
0
      if (signer == NULL) {
479
0
        if (logit) {
480
0
          isc_log_write(
481
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
482
0
            DNS_LOGMODULE_SSU,
483
0
            ISC_LOG_DEBUG(99),
484
0
            "update-policy: next "
485
0
            "rule: no signer");
486
0
        }
487
0
        continue;
488
0
      }
489
0
      break;
490
0
    case dns_ssumatchtype_tcpself:
491
0
    case dns_ssumatchtype_6to4self:
492
0
      if (!tcp || addr == NULL) {
493
0
        if (logit) {
494
0
          isc_log_write(
495
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
496
0
            DNS_LOGMODULE_SSU,
497
0
            ISC_LOG_DEBUG(99),
498
0
            "update-policy: next rule: %s",
499
0
            tcp ? "no address" : "not TCP");
500
0
        }
501
0
        continue;
502
0
      }
503
0
      break;
504
0
    case dns_ssumatchtype_external:
505
0
    case dns_ssumatchtype_dlz:
506
0
      break;
507
0
    }
508
509
0
    switch (rule->matchtype) {
510
0
    case dns_ssumatchtype_name:
511
0
      if (!dns_name_equal(name, rule->name)) {
512
0
        if (logit) {
513
0
          isc_log_write(
514
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
515
0
            DNS_LOGMODULE_SSU,
516
0
            ISC_LOG_DEBUG(99),
517
0
            "update-policy: next "
518
0
            "rule: name mismatch");
519
0
        }
520
0
        continue;
521
0
      }
522
0
      break;
523
0
    case dns_ssumatchtype_subdomain:
524
0
      if (!dns_name_issubdomain(name, rule->name)) {
525
0
        if (logit) {
526
0
          isc_log_write(
527
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
528
0
            DNS_LOGMODULE_SSU,
529
0
            ISC_LOG_DEBUG(99),
530
0
            "update-policy: next rule: "
531
0
            "name/subdomain mismatch");
532
0
        }
533
0
        continue;
534
0
      }
535
0
      break;
536
0
    case dns_ssumatchtype_local:
537
0
      if (addr == NULL) {
538
0
        if (logit) {
539
0
          isc_log_write(
540
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
541
0
            DNS_LOGMODULE_SSU,
542
0
            ISC_LOG_DEBUG(99),
543
0
            "update-policy: next "
544
0
            "rule: no address");
545
0
        }
546
0
        continue;
547
0
      }
548
0
      if (!dns_name_issubdomain(name, rule->name)) {
549
0
        if (logit) {
550
0
          isc_log_write(
551
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
552
0
            DNS_LOGMODULE_SSU,
553
0
            ISC_LOG_DEBUG(99),
554
0
            "update-policy: next rule: "
555
0
            "name/subdomain mismatch");
556
0
        }
557
0
        continue;
558
0
      }
559
0
      rcu_read_lock();
560
0
      dns_acl_t *localhost = rcu_dereference(env->localhost);
561
0
      dns_acl_match(addr, NULL, localhost, NULL, &match,
562
0
              NULL);
563
0
      rcu_read_unlock();
564
0
      if (match == 0) {
565
0
        if (signer != NULL) {
566
0
          isc_log_write(DNS_LOGCATEGORY_GENERAL,
567
0
                  DNS_LOGMODULE_SSU,
568
0
                  ISC_LOG_WARNING,
569
0
                  "update-policy local: "
570
0
                  "match on session "
571
0
                  "key not from "
572
0
                  "localhost");
573
0
        }
574
0
        if (logit) {
575
0
          isc_log_write(
576
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
577
0
            DNS_LOGMODULE_SSU,
578
0
            ISC_LOG_DEBUG(99),
579
0
            "update-policy: next rule: "
580
0
            "address not local");
581
0
        }
582
0
        continue;
583
0
      }
584
0
      break;
585
0
    case dns_ssumatchtype_wildcard:
586
0
      if (!dns_name_matcheswildcard(name, rule->name)) {
587
0
        if (logit) {
588
0
          isc_log_write(
589
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
590
0
            DNS_LOGMODULE_SSU,
591
0
            ISC_LOG_DEBUG(99),
592
0
            "update-policy: next "
593
0
            "rule: record name does "
594
0
            "not match wilcard name");
595
0
        }
596
0
        continue;
597
0
      }
598
0
      break;
599
0
    case dns_ssumatchtype_self:
600
0
      if (!dns_name_equal(signer, name)) {
601
0
        if (logit) {
602
0
          isc_log_write(
603
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
604
0
            DNS_LOGMODULE_SSU,
605
0
            ISC_LOG_DEBUG(99),
606
0
            "update-policy: next "
607
0
            "rule: record named not "
608
0
            "equal signer");
609
0
        }
610
0
        continue;
611
0
      }
612
0
      break;
613
0
    case dns_ssumatchtype_selfsub:
614
0
      if (!dns_name_issubdomain(name, signer)) {
615
0
        if (logit) {
616
0
          isc_log_write(
617
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
618
0
            DNS_LOGMODULE_SSU,
619
0
            ISC_LOG_DEBUG(99),
620
0
            "update-policy: next "
621
0
            "rule: record name not "
622
0
            "subdomain of signer");
623
0
        }
624
0
        continue;
625
0
      }
626
0
      break;
627
0
    case dns_ssumatchtype_selfwild:
628
0
      wildcard = dns_fixedname_initname(&fixed);
629
0
      result = dns_name_concatenate(dns_wildcardname, signer,
630
0
                  wildcard);
631
0
      if (result != ISC_R_SUCCESS) {
632
0
        if (logit) {
633
0
          isc_log_write(
634
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
635
0
            DNS_LOGMODULE_SSU,
636
0
            ISC_LOG_DEBUG(99),
637
0
            "update-policy: next "
638
0
            "rule: wilcard, signer "
639
0
            "concatenation failed");
640
0
        }
641
0
        continue;
642
0
      }
643
0
      if (!dns_name_matcheswildcard(name, wildcard)) {
644
0
        if (logit) {
645
0
          isc_log_write(
646
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
647
0
            DNS_LOGMODULE_SSU,
648
0
            ISC_LOG_DEBUG(99),
649
0
            "update-policy: next rule: "
650
0
            "record name does not match "
651
0
            "wildcarded signer");
652
0
        }
653
0
        continue;
654
0
      }
655
0
      break;
656
0
    case dns_ssumatchtype_selfkrb5:
657
0
      if (dst_gssapi_identitymatchesrealmkrb5(
658
0
            signer, name, rule->identity, false))
659
0
      {
660
0
        break;
661
0
      }
662
0
      if (logit) {
663
0
        isc_log_write(
664
0
          DNS_LOGCATEGORY_UPDATE_POLICY,
665
0
          DNS_LOGMODULE_SSU, ISC_LOG_DEBUG(99),
666
0
          "update-policy: next rule: krb5 signer "
667
0
          "doesn't map to record name");
668
0
      }
669
0
      continue;
670
0
    case dns_ssumatchtype_selfms:
671
0
      if (dst_gssapi_identitymatchesrealmms(
672
0
            signer, name, rule->identity, false))
673
0
      {
674
0
        break;
675
0
      }
676
0
      if (logit) {
677
0
        isc_log_write(
678
0
          DNS_LOGCATEGORY_UPDATE_POLICY,
679
0
          DNS_LOGMODULE_SSU, ISC_LOG_DEBUG(99),
680
0
          "update-policy: next rule: MS Windows "
681
0
          "signer doesn't map to record name");
682
0
      }
683
0
      continue;
684
0
    case dns_ssumatchtype_selfsubkrb5:
685
0
      if (dst_gssapi_identitymatchesrealmkrb5(
686
0
            signer, name, rule->identity, true))
687
0
      {
688
0
        break;
689
0
      }
690
0
      if (logit) {
691
0
        isc_log_write(DNS_LOGCATEGORY_UPDATE_POLICY,
692
0
                DNS_LOGMODULE_SSU,
693
0
                ISC_LOG_DEBUG(99),
694
0
                "update-policy: next rule: "
695
0
                "record name not a subdomain of "
696
0
                "krb5 signer mapped name");
697
0
      }
698
0
      continue;
699
0
    case dns_ssumatchtype_selfsubms:
700
0
      if (dst_gssapi_identitymatchesrealmms(
701
0
            signer, name, rule->identity, true))
702
0
      {
703
0
        break;
704
0
      }
705
0
      if (logit) {
706
0
        isc_log_write(DNS_LOGCATEGORY_UPDATE_POLICY,
707
0
                DNS_LOGMODULE_SSU,
708
0
                ISC_LOG_DEBUG(99),
709
0
                "update-policy: next rule: "
710
0
                "record name not a subdomain of "
711
0
                "MS Windows signer mapped name");
712
0
      }
713
0
      continue;
714
0
    case dns_ssumatchtype_subdomainkrb5:
715
0
    case dns_ssumatchtype_subdomainselfkrb5rhs:
716
0
      if (!dns_name_issubdomain(name, rule->name)) {
717
0
        if (logit) {
718
0
          isc_log_write(
719
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
720
0
            DNS_LOGMODULE_SSU,
721
0
            ISC_LOG_DEBUG(99),
722
0
            "update-policy: next "
723
0
            "rule: record name not a "
724
0
            "subdomain of rule name");
725
0
        }
726
0
        continue;
727
0
      }
728
0
      tname = NULL;
729
0
      switch (rule->matchtype) {
730
0
      case dns_ssumatchtype_subdomainselfkrb5rhs:
731
0
        if (type == dns_rdatatype_ptr) {
732
0
          tname = target;
733
0
        }
734
0
        if (type == dns_rdatatype_srv) {
735
0
          tname = target;
736
0
        }
737
0
        break;
738
0
      default:
739
0
        break;
740
0
      }
741
0
      if (dst_gssapi_identitymatchesrealmkrb5(
742
0
            signer, tname, rule->identity, false))
743
0
      {
744
0
        break;
745
0
      }
746
0
      if (logit) {
747
0
        isc_log_write(DNS_LOGCATEGORY_UPDATE_POLICY,
748
0
                DNS_LOGMODULE_SSU,
749
0
                ISC_LOG_DEBUG(99),
750
0
                "update-policy: next rule: rdata "
751
0
                "name does not match krb5 signer "
752
0
                "mapped name");
753
0
      }
754
0
      continue;
755
0
    case dns_ssumatchtype_subdomainms:
756
0
    case dns_ssumatchtype_subdomainselfmsrhs:
757
0
      if (!dns_name_issubdomain(name, rule->name)) {
758
0
        if (logit) {
759
0
          isc_log_write(
760
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
761
0
            DNS_LOGMODULE_SSU,
762
0
            ISC_LOG_DEBUG(99),
763
0
            "update-policy: next "
764
0
            "rule: record name not a "
765
0
            "subdomain of rule name");
766
0
        }
767
0
        continue;
768
0
      }
769
0
      tname = NULL;
770
0
      switch (rule->matchtype) {
771
0
      case dns_ssumatchtype_subdomainselfmsrhs:
772
0
        if (type == dns_rdatatype_ptr) {
773
0
          tname = target;
774
0
        }
775
0
        if (type == dns_rdatatype_srv) {
776
0
          tname = target;
777
0
        }
778
0
        break;
779
0
      default:
780
0
        break;
781
0
      }
782
0
      if (dst_gssapi_identitymatchesrealmms(
783
0
            signer, tname, rule->identity, false))
784
0
      {
785
0
        break;
786
0
      }
787
0
      if (logit) {
788
0
        isc_log_write(DNS_LOGCATEGORY_UPDATE_POLICY,
789
0
                DNS_LOGMODULE_SSU,
790
0
                ISC_LOG_DEBUG(99),
791
0
                "update-policy: next rule: rdata "
792
0
                "name does not match MS Windows "
793
0
                "signer mapped name");
794
0
      }
795
0
      continue;
796
0
    case dns_ssumatchtype_tcpself:
797
0
      tcpself = dns_fixedname_initname(&fixed);
798
0
      reverse_from_address(tcpself, addr);
799
0
      if (dns_name_iswildcard(rule->identity)) {
800
0
        if (!dns_name_matcheswildcard(tcpself,
801
0
                    rule->identity))
802
0
        {
803
0
          if (logit) {
804
0
            isc_log_write(
805
0
              DNS_LOGCATEGORY_UPDATE_POLICY,
806
0
              DNS_LOGMODULE_SSU,
807
0
              ISC_LOG_DEBUG(99),
808
0
              "update-policy: next "
809
0
              "rule: tcp-self name "
810
0
              "does not match "
811
0
              "wildcard identity");
812
0
          }
813
0
          continue;
814
0
        }
815
0
      } else {
816
0
        if (!dns_name_equal(tcpself, rule->identity)) {
817
0
          if (logit) {
818
0
            isc_log_write(
819
0
              DNS_LOGCATEGORY_UPDATE_POLICY,
820
0
              DNS_LOGMODULE_SSU,
821
0
              ISC_LOG_DEBUG(99),
822
0
              "update-policy: next "
823
0
              "rule: tcp-self name "
824
0
              "does not match "
825
0
              "identity");
826
0
          }
827
0
          continue;
828
0
        }
829
0
      }
830
0
      if (!dns_name_equal(tcpself, name)) {
831
0
        if (logit) {
832
0
          isc_log_write(
833
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
834
0
            DNS_LOGMODULE_SSU,
835
0
            ISC_LOG_DEBUG(99),
836
0
            "update-policy: next rule: "
837
0
            "tcp-self name does not match "
838
0
            "record name");
839
0
        }
840
0
        continue;
841
0
      }
842
0
      break;
843
0
    case dns_ssumatchtype_6to4self:
844
0
      stfself = dns_fixedname_initname(&fixed);
845
0
      stf_from_address(stfself, addr);
846
0
      if (dns_name_iswildcard(rule->identity)) {
847
0
        if (!dns_name_matcheswildcard(stfself,
848
0
                    rule->identity))
849
0
        {
850
0
          if (logit) {
851
0
            isc_log_write(
852
0
              DNS_LOGCATEGORY_UPDATE_POLICY,
853
0
              DNS_LOGMODULE_SSU,
854
0
              ISC_LOG_DEBUG(99),
855
0
              "update-policy: next "
856
0
              "rule: %s name "
857
0
              "does not match "
858
0
              "wildcard identity",
859
0
              mtypetostring(
860
0
                rule->matchtype));
861
0
          }
862
0
          continue;
863
0
        }
864
0
      } else {
865
0
        if (!dns_name_equal(stfself, rule->identity)) {
866
0
          if (logit) {
867
0
            isc_log_write(
868
0
              DNS_LOGCATEGORY_UPDATE_POLICY,
869
0
              DNS_LOGMODULE_SSU,
870
0
              ISC_LOG_DEBUG(99),
871
0
              "update-policy: next "
872
0
              "rule: %s name does "
873
0
              "not match identity",
874
0
              mtypetostring(
875
0
                rule->matchtype));
876
0
          }
877
0
          continue;
878
0
        }
879
0
      }
880
0
      if (!dns_name_equal(stfself, name)) {
881
0
        if (logit) {
882
0
          isc_log_write(
883
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
884
0
            DNS_LOGMODULE_SSU,
885
0
            ISC_LOG_DEBUG(99),
886
0
            "update-policy: next "
887
0
            "rule: %s name does not "
888
0
            "match record name",
889
0
            mtypetostring(rule->matchtype));
890
0
        }
891
0
        continue;
892
0
      }
893
0
      break;
894
0
    case dns_ssumatchtype_external:
895
0
      if (!dns_ssu_external_match(rule->identity, signer,
896
0
                name, addr, type, key,
897
0
                table->mctx))
898
0
      {
899
0
        if (logit) {
900
0
          isc_log_write(
901
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
902
0
            DNS_LOGMODULE_SSU,
903
0
            ISC_LOG_DEBUG(99),
904
0
            "update-policy: next rule: "
905
0
            "external match failed");
906
0
        }
907
0
        continue;
908
0
      }
909
0
      break;
910
0
    case dns_ssumatchtype_dlz:
911
0
      if (!dns_dlz_ssumatch(table->dlzdatabase, signer, name,
912
0
                addr, type, key))
913
0
      {
914
0
        if (logit) {
915
0
          isc_log_write(
916
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
917
0
            DNS_LOGMODULE_SSU,
918
0
            ISC_LOG_DEBUG(99),
919
0
            "update-policy: next "
920
0
            "rule: dlz match failed");
921
0
        }
922
0
        continue;
923
0
      }
924
0
      break;
925
0
    }
926
927
0
    if (rule->ntypes == 0) {
928
      /*
929
       * If this is a DLZ rule, then the DLZ ssu
930
       * checks will have already checked the type.
931
       */
932
0
      if (rule->matchtype != dns_ssumatchtype_dlz &&
933
0
          !isusertype(type))
934
0
      {
935
0
        if (logit) {
936
0
          isc_log_write(
937
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
938
0
            DNS_LOGMODULE_SSU,
939
0
            ISC_LOG_DEBUG(99),
940
0
            "update-policy: next "
941
0
            "rule: not user type");
942
0
        }
943
0
        continue;
944
0
      }
945
0
    } else {
946
0
      for (i = 0; i < rule->ntypes; i++) {
947
0
        if (rule->types[i].type == dns_rdatatype_any ||
948
0
            rule->types[i].type == type)
949
0
        {
950
0
          break;
951
0
        }
952
0
      }
953
0
      if (i == rule->ntypes) {
954
0
        if (logit) {
955
0
          isc_log_write(
956
0
            DNS_LOGCATEGORY_UPDATE_POLICY,
957
0
            DNS_LOGMODULE_SSU,
958
0
            ISC_LOG_DEBUG(99),
959
0
            "update-policy: next rule: "
960
0
            "type not in type list");
961
0
        }
962
0
        continue;
963
0
      }
964
0
    }
965
0
    if (rule->grant && rulep != NULL) {
966
0
      *rulep = rule;
967
0
    }
968
0
    if (logit) {
969
0
      isc_log_write(DNS_LOGCATEGORY_UPDATE_POLICY,
970
0
              DNS_LOGMODULE_SSU, ISC_LOG_DEBUG(99),
971
0
              "update-policy: matched: %s",
972
0
              rule->debug != NULL ? rule->debug
973
0
                : "not available");
974
0
    }
975
0
    return rule->grant;
976
0
  }
977
0
  if (logit) {
978
0
    isc_log_write(DNS_LOGCATEGORY_UPDATE_POLICY, DNS_LOGMODULE_SSU,
979
0
            ISC_LOG_DEBUG(99),
980
0
            "update-policy: no match found");
981
0
  }
982
983
0
  return false;
984
0
}
985
986
bool
987
0
dns_ssurule_isgrant(const dns_ssurule_t *rule) {
988
0
  REQUIRE(VALID_SSURULE(rule));
989
0
  return rule->grant;
990
0
}
991
992
dns_name_t *
993
0
dns_ssurule_identity(const dns_ssurule_t *rule) {
994
0
  REQUIRE(VALID_SSURULE(rule));
995
0
  return rule->identity;
996
0
}
997
998
unsigned int
999
0
dns_ssurule_matchtype(const dns_ssurule_t *rule) {
1000
0
  REQUIRE(VALID_SSURULE(rule));
1001
0
  return rule->matchtype;
1002
0
}
1003
1004
dns_name_t *
1005
0
dns_ssurule_name(const dns_ssurule_t *rule) {
1006
0
  REQUIRE(VALID_SSURULE(rule));
1007
0
  return rule->name;
1008
0
}
1009
1010
unsigned int
1011
0
dns_ssurule_types(const dns_ssurule_t *rule, dns_ssuruletype_t **types) {
1012
0
  REQUIRE(VALID_SSURULE(rule));
1013
0
  REQUIRE(types != NULL && *types != NULL);
1014
0
  *types = rule->types;
1015
0
  return rule->ntypes;
1016
0
}
1017
1018
unsigned int
1019
0
dns_ssurule_max(const dns_ssurule_t *rule, dns_rdatatype_t type) {
1020
0
  unsigned int i;
1021
0
  unsigned int max = 0;
1022
1023
0
  REQUIRE(VALID_SSURULE(rule));
1024
1025
0
  for (i = 0; i < rule->ntypes; i++) {
1026
0
    if (rule->types[i].type == dns_rdatatype_any) {
1027
0
      max = rule->types[i].max;
1028
0
    }
1029
0
    if (rule->types[i].type == type) {
1030
0
      return rule->types[i].max;
1031
0
    }
1032
0
  }
1033
0
  return max;
1034
0
}
1035
1036
isc_result_t
1037
0
dns_ssutable_firstrule(const dns_ssutable_t *table, dns_ssurule_t **rule) {
1038
0
  REQUIRE(VALID_SSUTABLE(table));
1039
0
  REQUIRE(rule != NULL && *rule == NULL);
1040
0
  *rule = ISC_LIST_HEAD(table->rules);
1041
0
  return *rule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE;
1042
0
}
1043
1044
isc_result_t
1045
0
dns_ssutable_nextrule(dns_ssurule_t *rule, dns_ssurule_t **nextrule) {
1046
0
  REQUIRE(VALID_SSURULE(rule));
1047
0
  REQUIRE(nextrule != NULL && *nextrule == NULL);
1048
0
  *nextrule = ISC_LIST_NEXT(rule, link);
1049
0
  return *nextrule != NULL ? ISC_R_SUCCESS : ISC_R_NOMORE;
1050
0
}
1051
1052
/*
1053
 * Create a specialised SSU table that points at an external DLZ database
1054
 */
1055
void
1056
dns_ssutable_createdlz(isc_mem_t *mctx, dns_ssutable_t **tablep,
1057
0
           dns_dlzdb_t *dlzdatabase) {
1058
0
  dns_ssurule_t *rule;
1059
0
  dns_ssutable_t *table = NULL;
1060
1061
0
  REQUIRE(tablep != NULL && *tablep == NULL);
1062
1063
0
  dns_ssutable_create(mctx, &table);
1064
1065
0
  table->dlzdatabase = dlzdatabase;
1066
1067
0
  rule = isc_mem_get(table->mctx, sizeof(dns_ssurule_t));
1068
1069
0
  *rule = (dns_ssurule_t){
1070
0
    .grant = true,
1071
0
    .matchtype = dns_ssumatchtype_dlz,
1072
0
    .magic = SSURULEMAGIC,
1073
0
  };
1074
1075
0
  rule->debug = isc_mem_strdup(mctx, "grant dlz");
1076
1077
0
  ISC_LIST_INITANDAPPEND(table->rules, rule, link);
1078
0
  *tablep = table;
1079
0
}
1080
1081
isc_result_t
1082
0
dns_ssu_mtypefromstring(const char *str, dns_ssumatchtype_t *mtype) {
1083
0
  REQUIRE(str != NULL);
1084
0
  REQUIRE(mtype != NULL);
1085
1086
0
  if (strcasecmp(str, "name") == 0) {
1087
0
    *mtype = dns_ssumatchtype_name;
1088
0
  } else if (strcasecmp(str, "subdomain") == 0) {
1089
0
    *mtype = dns_ssumatchtype_subdomain;
1090
0
  } else if (strcasecmp(str, "wildcard") == 0) {
1091
0
    *mtype = dns_ssumatchtype_wildcard;
1092
0
  } else if (strcasecmp(str, "self") == 0) {
1093
0
    *mtype = dns_ssumatchtype_self;
1094
0
  } else if (strcasecmp(str, "selfsub") == 0) {
1095
0
    *mtype = dns_ssumatchtype_selfsub;
1096
0
  } else if (strcasecmp(str, "selfwild") == 0) {
1097
0
    *mtype = dns_ssumatchtype_selfwild;
1098
0
  } else if (strcasecmp(str, "ms-self") == 0) {
1099
0
    *mtype = dns_ssumatchtype_selfms;
1100
0
  } else if (strcasecmp(str, "ms-selfsub") == 0) {
1101
0
    *mtype = dns_ssumatchtype_selfsubms;
1102
0
  } else if (strcasecmp(str, "krb5-self") == 0) {
1103
0
    *mtype = dns_ssumatchtype_selfkrb5;
1104
0
  } else if (strcasecmp(str, "krb5-selfsub") == 0) {
1105
0
    *mtype = dns_ssumatchtype_selfsubkrb5;
1106
0
  } else if (strcasecmp(str, "ms-subdomain") == 0) {
1107
0
    *mtype = dns_ssumatchtype_subdomainms;
1108
0
  } else if (strcasecmp(str, "ms-subdomain-self-rhs") == 0) {
1109
0
    *mtype = dns_ssumatchtype_subdomainselfmsrhs;
1110
0
  } else if (strcasecmp(str, "krb5-subdomain") == 0) {
1111
0
    *mtype = dns_ssumatchtype_subdomainkrb5;
1112
0
  } else if (strcasecmp(str, "krb5-subdomain-self-rhs") == 0) {
1113
0
    *mtype = dns_ssumatchtype_subdomainselfkrb5rhs;
1114
0
  } else if (strcasecmp(str, "tcp-self") == 0) {
1115
0
    *mtype = dns_ssumatchtype_tcpself;
1116
0
  } else if (strcasecmp(str, "6to4-self") == 0) {
1117
0
    *mtype = dns_ssumatchtype_6to4self;
1118
0
  } else if (strcasecmp(str, "zonesub") == 0) {
1119
0
    *mtype = dns_ssumatchtype_subdomain;
1120
0
  } else if (strcasecmp(str, "external") == 0) {
1121
0
    *mtype = dns_ssumatchtype_external;
1122
0
  } else {
1123
0
    return ISC_R_NOTFOUND;
1124
0
  }
1125
0
  return ISC_R_SUCCESS;
1126
0
}