1 /* $OpenBSD: table.c,v 1.48 2019/01/10 07:40:52 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> 5 * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/tree.h> 23 #include <sys/socket.h> 24 #include <sys/stat.h> 25 26 #include <netinet/in.h> 27 #include <arpa/inet.h> 28 #include <net/if.h> 29 30 #include <errno.h> 31 #include <event.h> 32 #include <imsg.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <regex.h> 36 #include <limits.h> 37 #include <string.h> 38 #include <unistd.h> 39 40 #include "smtpd.h" 41 #include "log.h" 42 43 struct table_backend *table_backend_lookup(const char *); 44 45 extern struct table_backend table_backend_static; 46 extern struct table_backend table_backend_db; 47 extern struct table_backend table_backend_getpwnam; 48 extern struct table_backend table_backend_proc; 49 50 static const char * table_service_name(enum table_service); 51 static int table_parse_lookup(enum table_service, const char *, const char *, 52 union lookup *); 53 static int parse_sockaddr(struct sockaddr *, int, const char *); 54 55 static unsigned int last_table_id = 0; 56 57 static struct table_backend *backends[] = { 58 &table_backend_static, 59 &table_backend_db, 60 &table_backend_getpwnam, 61 &table_backend_proc, 62 NULL 63 }; 64 65 struct table_backend * 66 table_backend_lookup(const char *backend) 67 { 68 int i; 69 70 if (!strcmp(backend, "file")) 71 backend = "static"; 72 73 for (i = 0; backends[i]; i++) 74 if (!strcmp(backends[i]->name, backend)) 75 return (backends[i]); 76 77 return NULL; 78 } 79 80 static const char * 81 table_service_name(enum table_service s) 82 { 83 switch (s) { 84 case K_NONE: return "NONE"; 85 case K_ALIAS: return "ALIAS"; 86 case K_DOMAIN: return "DOMAIN"; 87 case K_CREDENTIALS: return "CREDENTIALS"; 88 case K_NETADDR: return "NETADDR"; 89 case K_USERINFO: return "USERINFO"; 90 case K_SOURCE: return "SOURCE"; 91 case K_MAILADDR: return "MAILADDR"; 92 case K_ADDRNAME: return "ADDRNAME"; 93 case K_MAILADDRMAP: return "MAILADDRMAP"; 94 case K_RELAYHOST: return "RELAYHOST"; 95 case K_STRING: return "STRING"; 96 case K_REGEX: return "REGEX"; 97 } 98 return "???"; 99 } 100 101 struct table * 102 table_find(struct smtpd *conf, const char *name) 103 { 104 return dict_get(conf->sc_tables_dict, name); 105 } 106 107 int 108 table_match(struct table *table, enum table_service kind, const char *key) 109 { 110 return table_lookup(table, kind, key, NULL); 111 } 112 113 int 114 table_lookup(struct table *table, enum table_service kind, const char *key, 115 union lookup *lk) 116 { 117 char lkey[1024], *buf = NULL; 118 int r; 119 120 r = -1; 121 if (table->t_backend->lookup == NULL) 122 errno = ENOTSUP; 123 else if (!lowercase(lkey, key, sizeof lkey)) { 124 log_warnx("warn: lookup key too long: %s", key); 125 errno = EINVAL; 126 } 127 else 128 r = table->t_backend->lookup(table, kind, lkey, lk ? &buf : NULL); 129 130 if (r == 1) { 131 log_trace(TRACE_LOOKUP, "lookup: %s \"%s\" as %s in table %s:%s -> %s%s%s", 132 lk ? "lookup" : "match", 133 key, 134 table_service_name(kind), 135 table->t_backend->name, 136 table->t_name, 137 lk ? "\"" : "", 138 lk ? buf : "true", 139 lk ? "\"" : ""); 140 if (buf) 141 r = table_parse_lookup(kind, lkey, buf, lk); 142 } 143 else 144 log_trace(TRACE_LOOKUP, "lookup: %s \"%s\" as %s in table %s:%s -> %s%s", 145 lk ? "lookup" : "match", 146 key, 147 table_service_name(kind), 148 table->t_backend->name, 149 table->t_name, 150 (r == -1) ? "error: " : (lk ? "none" : "false"), 151 (r == -1) ? strerror(errno) : ""); 152 153 free(buf); 154 155 return (r); 156 } 157 158 int 159 table_fetch(struct table *table, enum table_service kind, union lookup *lk) 160 { 161 char *buf = NULL; 162 int r; 163 164 r = -1; 165 if (table->t_backend->fetch == NULL) 166 errno = ENOTSUP; 167 else 168 r = table->t_backend->fetch(table, kind, &buf); 169 170 if (r == 1) { 171 log_trace(TRACE_LOOKUP, "lookup: fetch %s from table %s:%s -> \"%s\"", 172 table_service_name(kind), 173 table->t_backend->name, 174 table->t_name, 175 buf); 176 r = table_parse_lookup(kind, NULL, buf, lk); 177 } 178 else 179 log_trace(TRACE_LOOKUP, "lookup: fetch %s from table %s:%s -> %s%s", 180 table_service_name(kind), 181 table->t_backend->name, 182 table->t_name, 183 (r == -1) ? "error: " : "none", 184 (r == -1) ? strerror(errno) : ""); 185 186 free(buf); 187 188 return (r); 189 } 190 191 struct table * 192 table_create(struct smtpd *conf, const char *backend, const char *name, 193 const char *config) 194 { 195 struct table *t; 196 struct table_backend *tb; 197 char path[LINE_MAX]; 198 size_t n; 199 struct stat sb; 200 201 if (name && table_find(conf, name)) 202 fatalx("table_create: table \"%s\" already defined", name); 203 204 if ((tb = table_backend_lookup(backend)) == NULL) { 205 if ((size_t)snprintf(path, sizeof(path), PATH_LIBEXEC"/table-%s", 206 backend) >= sizeof(path)) { 207 fatalx("table_create: path too long \"" 208 PATH_LIBEXEC"/table-%s\"", backend); 209 } 210 if (stat(path, &sb) == 0) { 211 tb = table_backend_lookup("proc"); 212 (void)strlcpy(path, backend, sizeof(path)); 213 if (config) { 214 (void)strlcat(path, ":", sizeof(path)); 215 if (strlcat(path, config, sizeof(path)) 216 >= sizeof(path)) 217 fatalx("table_create: config file path too long"); 218 } 219 config = path; 220 } 221 } 222 223 if (tb == NULL) 224 fatalx("table_create: backend \"%s\" does not exist", backend); 225 226 t = xcalloc(1, sizeof(*t)); 227 t->t_backend = tb; 228 229 if (config) { 230 if (strlcpy(t->t_config, config, sizeof t->t_config) 231 >= sizeof t->t_config) 232 fatalx("table_create: table config \"%s\" too large", 233 t->t_config); 234 } 235 236 if (strcmp(tb->name, "static") != 0) 237 t->t_type = T_DYNAMIC; 238 239 if (name == NULL) 240 (void)snprintf(t->t_name, sizeof(t->t_name), "<dynamic:%u>", 241 last_table_id++); 242 else { 243 n = strlcpy(t->t_name, name, sizeof(t->t_name)); 244 if (n >= sizeof(t->t_name)) 245 fatalx("table_create: table name too long"); 246 } 247 248 dict_set(conf->sc_tables_dict, t->t_name, t); 249 250 return (t); 251 } 252 253 void 254 table_destroy(struct smtpd *conf, struct table *t) 255 { 256 dict_xpop(conf->sc_tables_dict, t->t_name); 257 free(t); 258 } 259 260 int 261 table_config(struct table *t) 262 { 263 if (t->t_backend->config == NULL) 264 return (1); 265 return (t->t_backend->config(t)); 266 } 267 268 void 269 table_add(struct table *t, const char *key, const char *val) 270 { 271 if (t->t_backend->add == NULL) 272 fatalx("table_add: cannot add to table"); 273 274 if (t->t_backend->add(t, key, val) == 0) 275 log_warnx("warn: failed to add \"%s\" in table \"%s\"", key, t->t_name); 276 } 277 278 void 279 table_dump(struct table *t) 280 { 281 const char *type; 282 char buf[LINE_MAX]; 283 284 switch(t->t_type) { 285 case T_NONE: 286 type = "NONE"; 287 break; 288 case T_DYNAMIC: 289 type = "DYNAMIC"; 290 break; 291 case T_LIST: 292 type = "LIST"; 293 break; 294 case T_HASH: 295 type = "HASH"; 296 break; 297 default: 298 type = "???"; 299 break; 300 } 301 302 if (t->t_config[0]) 303 snprintf(buf, sizeof(buf), " config=\"%s\"", t->t_config); 304 else 305 buf[0] = '\0'; 306 307 log_debug("TABLE \"%s\" backend=%s type=%s%s", t->t_name, 308 t->t_backend->name, type, buf); 309 310 if (t->t_backend->dump) 311 t->t_backend->dump(t); 312 } 313 314 int 315 table_check_type(struct table *t, uint32_t mask) 316 { 317 return t->t_type & mask; 318 } 319 320 int 321 table_check_service(struct table *t, uint32_t mask) 322 { 323 return t->t_backend->services & mask; 324 } 325 326 int 327 table_check_use(struct table *t, uint32_t tmask, uint32_t smask) 328 { 329 return table_check_type(t, tmask) && table_check_service(t, smask); 330 } 331 332 int 333 table_open(struct table *t) 334 { 335 if (t->t_backend->open == NULL) 336 return (1); 337 return (t->t_backend->open(t)); 338 } 339 340 void 341 table_close(struct table *t) 342 { 343 if (t->t_backend->close) 344 t->t_backend->close(t); 345 } 346 347 int 348 table_update(struct table *t) 349 { 350 if (t->t_backend->update == NULL) 351 return (1); 352 return (t->t_backend->update(t)); 353 } 354 355 356 /* 357 * quick reminder: 358 * in *_match() s1 comes from session, s2 comes from table 359 */ 360 361 int 362 table_domain_match(const char *s1, const char *s2) 363 { 364 return hostname_match(s1, s2); 365 } 366 367 int 368 table_mailaddr_match(const char *s1, const char *s2) 369 { 370 struct mailaddr m1; 371 struct mailaddr m2; 372 373 if (!text_to_mailaddr(&m1, s1)) 374 return 0; 375 if (!text_to_mailaddr(&m2, s2)) 376 return 0; 377 return mailaddr_match(&m1, &m2); 378 } 379 380 static int table_match_mask(struct sockaddr_storage *, struct netaddr *); 381 static int table_inet4_match(struct sockaddr_in *, struct netaddr *); 382 static int table_inet6_match(struct sockaddr_in6 *, struct netaddr *); 383 384 int 385 table_netaddr_match(const char *s1, const char *s2) 386 { 387 struct netaddr n1; 388 struct netaddr n2; 389 390 if (strcasecmp(s1, s2) == 0) 391 return 1; 392 if (!text_to_netaddr(&n1, s1)) 393 return 0; 394 if (!text_to_netaddr(&n2, s2)) 395 return 0; 396 if (n1.ss.ss_family != n2.ss.ss_family) 397 return 0; 398 if (n1.ss.ss_len != n2.ss.ss_len) 399 return 0; 400 return table_match_mask(&n1.ss, &n2); 401 } 402 403 static int 404 table_match_mask(struct sockaddr_storage *ss, struct netaddr *ssmask) 405 { 406 if (ss->ss_family == AF_INET) 407 return table_inet4_match((struct sockaddr_in *)ss, ssmask); 408 409 if (ss->ss_family == AF_INET6) 410 return table_inet6_match((struct sockaddr_in6 *)ss, ssmask); 411 412 return (0); 413 } 414 415 static int 416 table_inet4_match(struct sockaddr_in *ss, struct netaddr *ssmask) 417 { 418 in_addr_t mask; 419 int i; 420 421 /* a.b.c.d/8 -> htonl(0xff000000) */ 422 mask = 0; 423 for (i = 0; i < ssmask->bits; ++i) 424 mask = (mask >> 1) | 0x80000000; 425 mask = htonl(mask); 426 427 /* (addr & mask) == (net & mask) */ 428 if ((ss->sin_addr.s_addr & mask) == 429 (((struct sockaddr_in *)ssmask)->sin_addr.s_addr & mask)) 430 return 1; 431 432 return 0; 433 } 434 435 static int 436 table_inet6_match(struct sockaddr_in6 *ss, struct netaddr *ssmask) 437 { 438 struct in6_addr *in; 439 struct in6_addr *inmask; 440 struct in6_addr mask; 441 int i; 442 443 memset(&mask, 0, sizeof(mask)); 444 for (i = 0; i < ssmask->bits / 8; i++) 445 mask.s6_addr[i] = 0xff; 446 i = ssmask->bits % 8; 447 if (i) 448 mask.s6_addr[ssmask->bits / 8] = 0xff00 >> i; 449 450 in = &ss->sin6_addr; 451 inmask = &((struct sockaddr_in6 *)&ssmask->ss)->sin6_addr; 452 453 for (i = 0; i < 16; i++) { 454 if ((in->s6_addr[i] & mask.s6_addr[i]) != 455 (inmask->s6_addr[i] & mask.s6_addr[i])) 456 return (0); 457 } 458 459 return (1); 460 } 461 462 int 463 table_regex_match(const char *string, const char *pattern) 464 { 465 regex_t preg; 466 int cflags = REG_EXTENDED|REG_NOSUB; 467 468 if (strncmp(pattern, "(?i)", 4) == 0) { 469 cflags |= REG_ICASE; 470 pattern += 4; 471 } 472 473 if (regcomp(&preg, pattern, cflags) != 0) 474 return (0); 475 476 if (regexec(&preg, string, 0, NULL, 0) != 0) 477 return (0); 478 479 return (1); 480 } 481 482 void 483 table_dump_all(struct smtpd *conf) 484 { 485 struct table *t; 486 void *iter; 487 488 iter = NULL; 489 while (dict_iter(conf->sc_tables_dict, &iter, NULL, (void **)&t)) 490 table_dump(t); 491 } 492 493 void 494 table_open_all(struct smtpd *conf) 495 { 496 struct table *t; 497 void *iter; 498 499 iter = NULL; 500 while (dict_iter(conf->sc_tables_dict, &iter, NULL, (void **)&t)) 501 if (!table_open(t)) 502 fatalx("failed to open table %s", t->t_name); 503 } 504 505 void 506 table_close_all(struct smtpd *conf) 507 { 508 struct table *t; 509 void *iter; 510 511 iter = NULL; 512 while (dict_iter(conf->sc_tables_dict, &iter, NULL, (void **)&t)) 513 table_close(t); 514 } 515 516 static int 517 table_parse_lookup(enum table_service service, const char *key, 518 const char *line, union lookup *lk) 519 { 520 char buffer[LINE_MAX], *p; 521 size_t len; 522 523 len = strlen(line); 524 525 switch (service) { 526 case K_ALIAS: 527 lk->expand = calloc(1, sizeof(*lk->expand)); 528 if (lk->expand == NULL) 529 return (-1); 530 if (!expand_line(lk->expand, line, 1)) { 531 expand_free(lk->expand); 532 return (-1); 533 } 534 return (1); 535 536 case K_DOMAIN: 537 if (strlcpy(lk->domain.name, line, sizeof(lk->domain.name)) 538 >= sizeof(lk->domain.name)) 539 return (-1); 540 return (1); 541 542 case K_CREDENTIALS: 543 544 /* credentials are stored as user:password */ 545 if (len < 3) 546 return (-1); 547 548 /* too big to fit in a smtp session line */ 549 if (len >= LINE_MAX) 550 return (-1); 551 552 p = strchr(line, ':'); 553 if (p == NULL) { 554 if (strlcpy(lk->creds.username, key, sizeof (lk->creds.username)) 555 >= sizeof (lk->creds.username)) 556 return (-1); 557 if (strlcpy(lk->creds.password, line, sizeof(lk->creds.password)) 558 >= sizeof(lk->creds.password)) 559 return (-1); 560 return (1); 561 } 562 563 if (p == line || p == line + len - 1) 564 return (-1); 565 566 memmove(lk->creds.username, line, p - line); 567 lk->creds.username[p - line] = '\0'; 568 569 if (strlcpy(lk->creds.password, p+1, sizeof(lk->creds.password)) 570 >= sizeof(lk->creds.password)) 571 return (-1); 572 573 return (1); 574 575 case K_NETADDR: 576 if (!text_to_netaddr(&lk->netaddr, line)) 577 return (-1); 578 return (1); 579 580 case K_USERINFO: 581 if (!bsnprintf(buffer, sizeof(buffer), "%s:%s", key, line)) 582 return (-1); 583 if (!text_to_userinfo(&lk->userinfo, buffer)) 584 return (-1); 585 return (1); 586 587 case K_SOURCE: 588 if (parse_sockaddr((struct sockaddr *)&lk->source.addr, 589 PF_UNSPEC, line) == -1) 590 return (-1); 591 return (1); 592 593 case K_MAILADDR: 594 if (!text_to_mailaddr(&lk->mailaddr, line)) 595 return (-1); 596 return (1); 597 598 case K_MAILADDRMAP: 599 lk->maddrmap = calloc(1, sizeof(*lk->maddrmap)); 600 if (lk->maddrmap == NULL) 601 return (-1); 602 maddrmap_init(lk->maddrmap); 603 if (!mailaddr_line(lk->maddrmap, line)) { 604 maddrmap_free(lk->maddrmap); 605 return (-1); 606 } 607 return (1); 608 609 case K_ADDRNAME: 610 if (parse_sockaddr((struct sockaddr *)&lk->addrname.addr, 611 PF_UNSPEC, key) == -1) 612 return (-1); 613 if (strlcpy(lk->addrname.name, line, sizeof(lk->addrname.name)) 614 >= sizeof(lk->addrname.name)) 615 return (-1); 616 return (1); 617 618 case K_RELAYHOST: 619 if (strlcpy(lk->relayhost, line, sizeof(lk->relayhost)) 620 >= sizeof(lk->relayhost)) 621 return (-1); 622 return (1); 623 624 default: 625 return (-1); 626 } 627 } 628 629 static int 630 parse_sockaddr(struct sockaddr *sa, int family, const char *str) 631 { 632 struct in_addr ina; 633 struct in6_addr in6a; 634 struct sockaddr_in *sin; 635 struct sockaddr_in6 *sin6; 636 char *cp, *str2; 637 const char *errstr; 638 639 switch (family) { 640 case PF_UNSPEC: 641 if (parse_sockaddr(sa, PF_INET, str) == 0) 642 return (0); 643 return parse_sockaddr(sa, PF_INET6, str); 644 645 case PF_INET: 646 if (inet_pton(PF_INET, str, &ina) != 1) 647 return (-1); 648 649 sin = (struct sockaddr_in *)sa; 650 memset(sin, 0, sizeof *sin); 651 sin->sin_len = sizeof(struct sockaddr_in); 652 sin->sin_family = PF_INET; 653 sin->sin_addr.s_addr = ina.s_addr; 654 return (0); 655 656 case PF_INET6: 657 if (strncasecmp("ipv6:", str, 5) == 0) 658 str += 5; 659 cp = strchr(str, SCOPE_DELIMITER); 660 if (cp) { 661 str2 = strdup(str); 662 if (str2 == NULL) 663 return (-1); 664 str2[cp - str] = '\0'; 665 if (inet_pton(PF_INET6, str2, &in6a) != 1) { 666 free(str2); 667 return (-1); 668 } 669 cp++; 670 free(str2); 671 } else if (inet_pton(PF_INET6, str, &in6a) != 1) 672 return (-1); 673 674 sin6 = (struct sockaddr_in6 *)sa; 675 memset(sin6, 0, sizeof *sin6); 676 sin6->sin6_len = sizeof(struct sockaddr_in6); 677 sin6->sin6_family = PF_INET6; 678 sin6->sin6_addr = in6a; 679 680 if (cp == NULL) 681 return (0); 682 683 if (IN6_IS_ADDR_LINKLOCAL(&in6a) || 684 IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || 685 IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) 686 if ((sin6->sin6_scope_id = if_nametoindex(cp))) 687 return (0); 688 689 sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr); 690 if (errstr) 691 return (-1); 692 return (0); 693 694 default: 695 break; 696 } 697 698 return (-1); 699 } 700