1 /* $OpenBSD: util.c,v 1.127 2016/05/16 17:43:18 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2000,2001 Markus Friedl. All rights reserved. 5 * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> 6 * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> 7 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/types.h> 23 #include <sys/queue.h> 24 #include <sys/tree.h> 25 #include <sys/socket.h> 26 #include <sys/stat.h> 27 #include <sys/resource.h> 28 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 31 32 #include <ctype.h> 33 #include <errno.h> 34 #include <event.h> 35 #include <fcntl.h> 36 #include <fts.h> 37 #include <imsg.h> 38 #include <inttypes.h> 39 #include <libgen.h> 40 #include <netdb.h> 41 #include <pwd.h> 42 #include <limits.h> 43 #include <resolv.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <time.h> 49 #include <unistd.h> 50 51 #include "smtpd.h" 52 #include "log.h" 53 54 const char *log_in6addr(const struct in6_addr *); 55 const char *log_sockaddr(struct sockaddr *); 56 static int parse_mailname_file(char *, size_t); 57 58 void * 59 xmalloc(size_t size, const char *where) 60 { 61 void *r; 62 63 if ((r = malloc(size)) == NULL) { 64 log_warnx("%s: malloc(%zu)", where, size); 65 fatalx("exiting"); 66 } 67 68 return (r); 69 } 70 71 void * 72 xcalloc(size_t nmemb, size_t size, const char *where) 73 { 74 void *r; 75 76 if ((r = calloc(nmemb, size)) == NULL) { 77 log_warnx("%s: calloc(%zu, %zu)", where, nmemb, size); 78 fatalx("exiting"); 79 } 80 81 return (r); 82 } 83 84 char * 85 xstrdup(const char *str, const char *where) 86 { 87 char *r; 88 89 if ((r = strdup(str)) == NULL) { 90 log_warnx("%s: strdup(%p)", where, str); 91 fatalx("exiting"); 92 } 93 94 return (r); 95 } 96 97 void * 98 xmemdup(const void *ptr, size_t size, const char *where) 99 { 100 void *r; 101 102 if ((r = malloc(size)) == NULL) { 103 log_warnx("%s: malloc(%zu)", where, size); 104 fatalx("exiting"); 105 } 106 memmove(r, ptr, size); 107 108 return (r); 109 } 110 111 #if !defined(NO_IO) 112 void 113 iobuf_xinit(struct iobuf *io, size_t size, size_t max, const char *where) 114 { 115 if (iobuf_init(io, size, max) == -1) { 116 log_warnx("%s: iobuf_init(%p, %zu, %zu)", where, io, size, max); 117 fatalx("exiting"); 118 } 119 } 120 121 void 122 iobuf_xfqueue(struct iobuf *io, const char *where, const char *fmt, ...) 123 { 124 va_list ap; 125 int len; 126 127 va_start(ap, fmt); 128 len = iobuf_vfqueue(io, fmt, ap); 129 va_end(ap); 130 131 if (len == -1) { 132 log_warnx("%s: iobuf_xfqueue(%p, %s, ...)", where, io, fmt); 133 fatalx("exiting"); 134 } 135 } 136 #endif 137 138 char * 139 strip(char *s) 140 { 141 size_t l; 142 143 while (isspace((unsigned char)*s)) 144 s++; 145 146 for (l = strlen(s); l; l--) { 147 if (!isspace((unsigned char)s[l-1])) 148 break; 149 s[l-1] = '\0'; 150 } 151 152 return (s); 153 } 154 155 int 156 bsnprintf(char *str, size_t size, const char *format, ...) 157 { 158 int ret; 159 va_list ap; 160 161 va_start(ap, format); 162 ret = vsnprintf(str, size, format, ap); 163 va_end(ap); 164 if (ret == -1 || ret >= (int)size) 165 return 0; 166 167 return 1; 168 } 169 170 171 static int 172 mkdirs_component(char *path, mode_t mode) 173 { 174 struct stat sb; 175 176 if (stat(path, &sb) == -1) { 177 if (errno != ENOENT) 178 return 0; 179 if (mkdir(path, mode | S_IWUSR | S_IXUSR) == -1) 180 return 0; 181 } 182 else if (!S_ISDIR(sb.st_mode)) 183 return 0; 184 185 return 1; 186 } 187 188 int 189 mkdirs(char *path, mode_t mode) 190 { 191 char buf[PATH_MAX]; 192 int i = 0; 193 int done = 0; 194 char *p; 195 196 /* absolute path required */ 197 if (*path != '/') 198 return 0; 199 200 /* make sure we don't exceed PATH_MAX */ 201 if (strlen(path) >= sizeof buf) 202 return 0; 203 204 memset(buf, 0, sizeof buf); 205 for (p = path; *p; p++) { 206 if (*p == '/') { 207 if (buf[0] != '\0') 208 if (!mkdirs_component(buf, mode)) 209 return 0; 210 while (*p == '/') 211 p++; 212 buf[i++] = '/'; 213 buf[i++] = *p; 214 if (*p == '\0' && ++done) 215 break; 216 continue; 217 } 218 buf[i++] = *p; 219 } 220 if (!done) 221 if (!mkdirs_component(buf, mode)) 222 return 0; 223 224 if (chmod(path, mode) == -1) 225 return 0; 226 227 return 1; 228 } 229 230 int 231 ckdir(const char *path, mode_t mode, uid_t owner, gid_t group, int create) 232 { 233 char mode_str[12]; 234 int ret; 235 struct stat sb; 236 237 if (stat(path, &sb) == -1) { 238 if (errno != ENOENT || create == 0) { 239 log_warn("stat: %s", path); 240 return (0); 241 } 242 243 /* chmod is deferred to avoid umask effect */ 244 if (mkdir(path, 0) == -1) { 245 log_warn("mkdir: %s", path); 246 return (0); 247 } 248 249 if (chown(path, owner, group) == -1) { 250 log_warn("chown: %s", path); 251 return (0); 252 } 253 254 if (chmod(path, mode) == -1) { 255 log_warn("chmod: %s", path); 256 return (0); 257 } 258 259 if (stat(path, &sb) == -1) { 260 log_warn("stat: %s", path); 261 return (0); 262 } 263 } 264 265 ret = 1; 266 267 /* check if it's a directory */ 268 if (!S_ISDIR(sb.st_mode)) { 269 ret = 0; 270 log_warnx("%s is not a directory", path); 271 } 272 273 /* check that it is owned by owner/group */ 274 if (sb.st_uid != owner) { 275 ret = 0; 276 log_warnx("%s is not owned by uid %d", path, owner); 277 } 278 if (sb.st_gid != group) { 279 ret = 0; 280 log_warnx("%s is not owned by gid %d", path, group); 281 } 282 283 /* check permission */ 284 if ((sb.st_mode & 07777) != mode) { 285 ret = 0; 286 strmode(mode, mode_str); 287 mode_str[10] = '\0'; 288 log_warnx("%s must be %s (%o)", path, mode_str + 1, mode); 289 } 290 291 return ret; 292 } 293 294 int 295 rmtree(char *path, int keepdir) 296 { 297 char *path_argv[2]; 298 FTS *fts; 299 FTSENT *e; 300 int ret, depth; 301 302 path_argv[0] = path; 303 path_argv[1] = NULL; 304 ret = 0; 305 depth = 0; 306 307 fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL); 308 if (fts == NULL) { 309 log_warn("fts_open: %s", path); 310 return (-1); 311 } 312 313 while ((e = fts_read(fts)) != NULL) { 314 switch (e->fts_info) { 315 case FTS_D: 316 depth++; 317 break; 318 case FTS_DP: 319 case FTS_DNR: 320 depth--; 321 if (keepdir && depth == 0) 322 continue; 323 if (rmdir(e->fts_path) == -1) { 324 log_warn("rmdir: %s", e->fts_path); 325 ret = -1; 326 } 327 break; 328 329 case FTS_F: 330 if (unlink(e->fts_path) == -1) { 331 log_warn("unlink: %s", e->fts_path); 332 ret = -1; 333 } 334 } 335 } 336 337 fts_close(fts); 338 339 return (ret); 340 } 341 342 int 343 mvpurge(char *from, char *to) 344 { 345 size_t n; 346 int retry; 347 const char *sep; 348 char buf[PATH_MAX]; 349 350 if ((n = strlen(to)) == 0) 351 fatalx("to is empty"); 352 353 sep = (to[n - 1] == '/') ? "" : "/"; 354 retry = 0; 355 356 again: 357 (void)snprintf(buf, sizeof buf, "%s%s%u", to, sep, arc4random()); 358 if (rename(from, buf) == -1) { 359 /* ENOTDIR has actually 2 meanings, and incorrect input 360 * could lead to an infinite loop. Consider that after 361 * 20 tries something is hopelessly wrong. 362 */ 363 if (errno == ENOTEMPTY || errno == EISDIR || errno == ENOTDIR) { 364 if ((retry++) >= 20) 365 return (-1); 366 goto again; 367 } 368 return -1; 369 } 370 371 return 0; 372 } 373 374 375 int 376 mktmpfile(void) 377 { 378 char path[PATH_MAX]; 379 int fd; 380 381 if (!bsnprintf(path, sizeof(path), "%s/smtpd.XXXXXXXXXX", 382 PATH_TEMPORARY)) { 383 log_warn("snprintf"); 384 fatal("exiting"); 385 } 386 387 if ((fd = mkstemp(path)) == -1) { 388 log_warn("cannot create temporary file %s", path); 389 fatal("exiting"); 390 } 391 unlink(path); 392 return (fd); 393 } 394 395 396 /* Close file, signifying temporary error condition (if any) to the caller. */ 397 int 398 safe_fclose(FILE *fp) 399 { 400 if (ferror(fp)) { 401 fclose(fp); 402 return 0; 403 } 404 if (fflush(fp)) { 405 fclose(fp); 406 if (errno == ENOSPC) 407 return 0; 408 fatal("safe_fclose: fflush"); 409 } 410 if (fsync(fileno(fp))) 411 fatal("safe_fclose: fsync"); 412 if (fclose(fp)) 413 fatal("safe_fclose: fclose"); 414 415 return 1; 416 } 417 418 int 419 hostname_match(const char *hostname, const char *pattern) 420 { 421 while (*pattern != '\0' && *hostname != '\0') { 422 if (*pattern == '*') { 423 while (*pattern == '*') 424 pattern++; 425 while (*hostname != '\0' && 426 tolower((unsigned char)*hostname) != 427 tolower((unsigned char)*pattern)) 428 hostname++; 429 continue; 430 } 431 432 if (tolower((unsigned char)*pattern) != 433 tolower((unsigned char)*hostname)) 434 return 0; 435 pattern++; 436 hostname++; 437 } 438 439 return (*hostname == '\0' && *pattern == '\0'); 440 } 441 442 int 443 mailaddr_match(const struct mailaddr *maddr1, const struct mailaddr *maddr2) 444 { 445 struct mailaddr m1 = *maddr1; 446 struct mailaddr m2 = *maddr2; 447 char *p; 448 449 /* catchall */ 450 if (m2.user[0] == '\0' && m2.domain[0] == '\0') 451 return 1; 452 453 if (!hostname_match(m1.domain, m2.domain)) 454 return 0; 455 456 if (m2.user[0]) { 457 /* if address from table has a tag, we must respect it */ 458 if (strchr(m2.user, TAG_CHAR) == NULL) { 459 /* otherwise, strip tag from session address if any */ 460 p = strchr(m1.user, TAG_CHAR); 461 if (p) 462 *p = '\0'; 463 } 464 if (strcasecmp(m1.user, m2.user)) 465 return 0; 466 } 467 return 1; 468 } 469 470 int 471 valid_localpart(const char *s) 472 { 473 #define IS_ATEXT(c) (isalnum((unsigned char)(c)) || strchr(MAILADDR_ALLOWED, (c))) 474 nextatom: 475 if (!IS_ATEXT(*s) || *s == '\0') 476 return 0; 477 while (*(++s) != '\0') { 478 if (*s == '.') 479 break; 480 if (IS_ATEXT(*s)) 481 continue; 482 return 0; 483 } 484 if (*s == '.') { 485 s++; 486 goto nextatom; 487 } 488 return 1; 489 } 490 491 int 492 valid_domainpart(const char *s) 493 { 494 struct in_addr ina; 495 struct in6_addr ina6; 496 char *c, domain[SMTPD_MAXDOMAINPARTSIZE]; 497 const char *p; 498 499 if (*s == '[') { 500 if (strncasecmp("[IPv6:", s, 6) == 0) 501 p = s + 6; 502 else 503 p = s + 1; 504 505 if (strlcpy(domain, p, sizeof domain) >= sizeof domain) 506 return 0; 507 508 c = strchr(domain, (int)']'); 509 if (!c || c[1] != '\0') 510 return 0; 511 512 *c = '\0'; 513 514 if (inet_pton(AF_INET6, domain, &ina6) == 1) 515 return 1; 516 if (inet_pton(AF_INET, domain, &ina) == 1) 517 return 1; 518 519 return 0; 520 } 521 522 if (*s == '\0') 523 return 0; 524 525 return res_hnok(s); 526 } 527 528 int 529 secure_file(int fd, char *path, char *userdir, uid_t uid, int mayread) 530 { 531 char buf[PATH_MAX]; 532 char homedir[PATH_MAX]; 533 struct stat st; 534 char *cp; 535 536 if (realpath(path, buf) == NULL) 537 return 0; 538 539 if (realpath(userdir, homedir) == NULL) 540 homedir[0] = '\0'; 541 542 /* Check the open file to avoid races. */ 543 if (fstat(fd, &st) < 0 || 544 !S_ISREG(st.st_mode) || 545 st.st_uid != uid || 546 (st.st_mode & (mayread ? 022 : 066)) != 0) 547 return 0; 548 549 /* For each component of the canonical path, walking upwards. */ 550 for (;;) { 551 if ((cp = dirname(buf)) == NULL) 552 return 0; 553 (void)strlcpy(buf, cp, sizeof(buf)); 554 555 if (stat(buf, &st) < 0 || 556 (st.st_uid != 0 && st.st_uid != uid) || 557 (st.st_mode & 022) != 0) 558 return 0; 559 560 /* We can stop checking after reaching homedir level. */ 561 if (strcmp(homedir, buf) == 0) 562 break; 563 564 /* 565 * dirname should always complete with a "/" path, 566 * but we can be paranoid and check for "." too 567 */ 568 if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) 569 break; 570 } 571 572 return 1; 573 } 574 575 void 576 addargs(arglist *args, char *fmt, ...) 577 { 578 va_list ap; 579 char *cp; 580 uint nalloc; 581 int r; 582 char **tmp; 583 584 va_start(ap, fmt); 585 r = vasprintf(&cp, fmt, ap); 586 va_end(ap); 587 if (r == -1) 588 fatal("addargs: argument too long"); 589 590 nalloc = args->nalloc; 591 if (args->list == NULL) { 592 nalloc = 32; 593 args->num = 0; 594 } else if (args->num+2 >= nalloc) 595 nalloc *= 2; 596 597 tmp = reallocarray(args->list, nalloc, sizeof(char *)); 598 if (tmp == NULL) 599 fatal("addargs: reallocarray"); 600 args->list = tmp; 601 args->nalloc = nalloc; 602 args->list[args->num++] = cp; 603 args->list[args->num] = NULL; 604 } 605 606 int 607 lowercase(char *buf, const char *s, size_t len) 608 { 609 if (len == 0) 610 return 0; 611 612 if (strlcpy(buf, s, len) >= len) 613 return 0; 614 615 while (*buf != '\0') { 616 *buf = tolower((unsigned char)*buf); 617 buf++; 618 } 619 620 return 1; 621 } 622 623 int 624 uppercase(char *buf, const char *s, size_t len) 625 { 626 if (len == 0) 627 return 0; 628 629 if (strlcpy(buf, s, len) >= len) 630 return 0; 631 632 while (*buf != '\0') { 633 *buf = toupper((unsigned char)*buf); 634 buf++; 635 } 636 637 return 1; 638 } 639 640 void 641 xlowercase(char *buf, const char *s, size_t len) 642 { 643 if (len == 0) 644 fatalx("lowercase: len == 0"); 645 646 if (!lowercase(buf, s, len)) 647 fatalx("lowercase: truncation"); 648 } 649 650 uint64_t 651 generate_uid(void) 652 { 653 static uint32_t id; 654 static uint8_t inited; 655 uint64_t uid; 656 657 if (!inited) { 658 id = arc4random(); 659 inited = 1; 660 } 661 while ((uid = ((uint64_t)(id++) << 32 | arc4random())) == 0) 662 ; 663 664 return (uid); 665 } 666 667 int 668 session_socket_error(int fd) 669 { 670 int error; 671 socklen_t len; 672 673 len = sizeof(error); 674 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1) 675 fatal("session_socket_error: getsockopt"); 676 677 return (error); 678 } 679 680 const char * 681 parse_smtp_response(char *line, size_t len, char **msg, int *cont) 682 { 683 size_t i; 684 685 if (len >= LINE_MAX) 686 return "line too long"; 687 688 if (len > 3) { 689 if (msg) 690 *msg = line + 4; 691 if (cont) 692 *cont = (line[3] == '-'); 693 } else if (len == 3) { 694 if (msg) 695 *msg = line + 3; 696 if (cont) 697 *cont = 0; 698 } else 699 return "line too short"; 700 701 /* validate reply code */ 702 if (line[0] < '2' || line[0] > '5' || !isdigit((unsigned char)line[1]) || 703 !isdigit((unsigned char)line[2])) 704 return "reply code out of range"; 705 706 /* validate reply message */ 707 for (i = 0; i < len; i++) 708 if (!isprint((unsigned char)line[i])) 709 return "non-printable character in reply"; 710 711 return NULL; 712 } 713 714 static int 715 parse_mailname_file(char *hostname, size_t len) 716 { 717 FILE *fp; 718 char *buf = NULL; 719 size_t bufsz = 0; 720 ssize_t buflen; 721 722 if ((fp = fopen(MAILNAME_FILE, "r")) == NULL) 723 return 1; 724 725 if ((buflen = getline(&buf, &bufsz, fp)) == -1) 726 goto error; 727 728 if (buf[buflen - 1] == '\n') 729 buf[buflen - 1] = '\0'; 730 731 if (strlcpy(hostname, buf, len) >= len) { 732 fprintf(stderr, MAILNAME_FILE " entry too long"); 733 goto error; 734 } 735 736 return 0; 737 error: 738 fclose(fp); 739 free(buf); 740 return 1; 741 } 742 743 int 744 getmailname(char *hostname, size_t len) 745 { 746 struct addrinfo hints, *res = NULL; 747 int error; 748 749 /* Try MAILNAME_FILE first */ 750 if (parse_mailname_file(hostname, len) == 0) 751 return 0; 752 753 /* Next, gethostname(3) */ 754 if (gethostname(hostname, len) == -1) { 755 fprintf(stderr, "getmailname: gethostname() failed\n"); 756 return -1; 757 } 758 759 if (strchr(hostname, '.') != NULL) 760 return 0; 761 762 /* Canonicalize if domain part is missing */ 763 memset(&hints, 0, sizeof hints); 764 hints.ai_family = PF_UNSPEC; 765 hints.ai_flags = AI_CANONNAME; 766 error = getaddrinfo(hostname, NULL, &hints, &res); 767 if (error) 768 return 0; /* Continue with non-canon hostname */ 769 770 if (strlcpy(hostname, res->ai_canonname, len) >= len) { 771 fprintf(stderr, "hostname too long"); 772 return -1; 773 } 774 775 freeaddrinfo(res); 776 return 0; 777 } 778 779 int 780 base64_encode(unsigned char const *src, size_t srclen, 781 char *dest, size_t destsize) 782 { 783 return __b64_ntop(src, srclen, dest, destsize); 784 } 785 786 int 787 base64_decode(char const *src, unsigned char *dest, size_t destsize) 788 { 789 return __b64_pton(src, dest, destsize); 790 } 791