1 /* 2 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 /* 25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #include "includes.h" 30 RCSID("$OpenBSD: misc.c,v 1.19 2002/03/04 17:27:39 stevesk Exp $"); 31 32 #include "misc.h" 33 #include "log.h" 34 #include "xmalloc.h" 35 36 /* remove newline at end of string */ 37 char * 38 chop(char *s) 39 { 40 char *t = s; 41 while (*t) { 42 if (*t == '\n' || *t == '\r') { 43 *t = '\0'; 44 return s; 45 } 46 t++; 47 } 48 return s; 49 50 } 51 52 /* set/unset filedescriptor to non-blocking */ 53 void 54 set_nonblock(int fd) 55 { 56 int val; 57 58 val = fcntl(fd, F_GETFL, 0); 59 if (val < 0) { 60 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 61 return; 62 } 63 if (val & O_NONBLOCK) { 64 debug2("fd %d is O_NONBLOCK", fd); 65 return; 66 } 67 debug("fd %d setting O_NONBLOCK", fd); 68 val |= O_NONBLOCK; 69 if (fcntl(fd, F_SETFL, val) == -1) 70 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", 71 fd, strerror(errno)); 72 } 73 74 void 75 unset_nonblock(int fd) 76 { 77 int val; 78 79 val = fcntl(fd, F_GETFL, 0); 80 if (val < 0) { 81 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 82 return; 83 } 84 if (!(val & O_NONBLOCK)) { 85 debug2("fd %d is not O_NONBLOCK", fd); 86 return; 87 } 88 debug("fd %d clearing O_NONBLOCK", fd); 89 val &= ~O_NONBLOCK; 90 if (fcntl(fd, F_SETFL, val) == -1) 91 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", 92 fd, strerror(errno)); 93 } 94 95 /* disable nagle on socket */ 96 void 97 set_nodelay(int fd) 98 { 99 int opt; 100 socklen_t optlen; 101 102 optlen = sizeof opt; 103 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 104 error("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 105 return; 106 } 107 if (opt == 1) { 108 debug2("fd %d is TCP_NODELAY", fd); 109 return; 110 } 111 opt = 1; 112 debug("fd %d setting TCP_NODELAY", fd); 113 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 114 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 115 } 116 117 /* Characters considered whitespace in strsep calls. */ 118 #define WHITESPACE " \t\r\n" 119 120 /* 121 * Function returns a pointer to the 1st token on the line. Such a token can 122 * be an empty string in the case of '*s' equal to " value". It changes the 123 * first whitespace token or '=' character after the 1st token to '\0'. Upon 124 * return it changes '*s' to point to the first character of the next token. 125 * That token may be an empty string if the 1st token was followed only by 126 * whitespace or it could be a NULL pointer if the line contained one token 127 * only. 128 */ 129 char * 130 strdelim(char **s) 131 { 132 char *old; 133 int wspace = 0; 134 135 if (*s == NULL) 136 return NULL; 137 138 old = *s; 139 140 *s = strpbrk(*s, WHITESPACE "="); 141 if (*s == NULL) 142 return (old); 143 144 /* Allow only one '=' to be skipped */ 145 if (*s[0] == '=') 146 wspace = 1; 147 *s[0] = '\0'; 148 149 *s += strspn(*s + 1, WHITESPACE) + 1; 150 if (*s[0] == '=' && !wspace) 151 *s += strspn(*s + 1, WHITESPACE) + 1; 152 153 return (old); 154 } 155 156 struct passwd * 157 pwcopy(struct passwd *pw) 158 { 159 struct passwd *copy = xmalloc(sizeof(*copy)); 160 161 memset(copy, 0, sizeof(*copy)); 162 copy->pw_name = xstrdup(pw->pw_name); 163 copy->pw_passwd = xstrdup(pw->pw_passwd); 164 copy->pw_gecos = xstrdup(pw->pw_gecos); 165 copy->pw_uid = pw->pw_uid; 166 copy->pw_gid = pw->pw_gid; 167 #ifdef HAVE_PW_EXPIRE_IN_PASSWD 168 copy->pw_expire = pw->pw_expire; 169 #endif 170 #ifdef HAVE_PW_CHANGE_IN_PASSWD 171 copy->pw_change = pw->pw_change; 172 #endif 173 #ifdef HAVE_PW_CLASS_IN_PASSWD 174 copy->pw_class = xstrdup(pw->pw_class); 175 #endif 176 copy->pw_dir = xstrdup(pw->pw_dir); 177 copy->pw_shell = xstrdup(pw->pw_shell); 178 return copy; 179 } 180 181 void 182 pwfree(struct passwd **pw) 183 { 184 struct passwd *p; 185 186 if (pw == NULL || *pw == NULL) 187 return; 188 189 p = *pw; 190 *pw = NULL; 191 192 xfree(p->pw_name); 193 xfree(p->pw_passwd); 194 xfree(p->pw_gecos); 195 #ifdef HAVE_PW_CLASS_IN_PASSWD 196 xfree(p->pw_class); 197 #endif 198 xfree(p->pw_dir); 199 xfree(p->pw_shell); 200 xfree(p); 201 } 202 203 /* 204 * Convert ASCII string to TCP/IP port number. 205 * Port must be >0 and <=65535. 206 * Return 0 if invalid. 207 */ 208 int 209 a2port(const char *s) 210 { 211 long port; 212 char *endp; 213 214 errno = 0; 215 port = strtol(s, &endp, 0); 216 if (s == endp || *endp != '\0' || 217 (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || 218 port <= 0 || port > 65535) 219 return 0; 220 221 return port; 222 } 223 224 #define SECONDS 1 225 #define MINUTES (SECONDS * 60) 226 #define HOURS (MINUTES * 60) 227 #define DAYS (HOURS * 24) 228 #define WEEKS (DAYS * 7) 229 230 /* 231 * Convert a time string into seconds; format is 232 * a sequence of: 233 * time[qualifier] 234 * 235 * Valid time qualifiers are: 236 * <none> seconds 237 * s|S seconds 238 * m|M minutes 239 * h|H hours 240 * d|D days 241 * w|W weeks 242 * 243 * Examples: 244 * 90m 90 minutes 245 * 1h30m 90 minutes 246 * 2d 2 days 247 * 1w 1 week 248 * 249 * Return -1 if time string is invalid. 250 */ 251 long 252 convtime(const char *s) 253 { 254 long total, secs; 255 const char *p; 256 char *endp; 257 258 errno = 0; 259 total = 0; 260 p = s; 261 262 if (p == NULL || *p == '\0') 263 return -1; 264 265 while (*p) { 266 secs = strtol(p, &endp, 10); 267 if (p == endp || 268 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 269 secs < 0) 270 return -1; 271 272 switch (*endp++) { 273 case '\0': 274 endp--; 275 break; 276 case 's': 277 case 'S': 278 break; 279 case 'm': 280 case 'M': 281 secs *= MINUTES; 282 break; 283 case 'h': 284 case 'H': 285 secs *= HOURS; 286 break; 287 case 'd': 288 case 'D': 289 secs *= DAYS; 290 break; 291 case 'w': 292 case 'W': 293 secs *= WEEKS; 294 break; 295 default: 296 return -1; 297 } 298 total += secs; 299 if (total < 0) 300 return -1; 301 p = endp; 302 } 303 304 return total; 305 } 306 307 /* 308 * Search for next delimiter between hostnames/addresses and ports. 309 * Argument may be modified (for termination). 310 * Returns *cp if parsing succeeds. 311 * *cp is set to the start of the next delimiter, if one was found. 312 * If this is the last field, *cp is set to NULL. 313 */ 314 char * 315 hpdelim(char **cp) 316 { 317 char *s, *old; 318 319 if (cp == NULL || *cp == NULL) 320 return NULL; 321 322 old = s = *cp; 323 if (*s == '[') { 324 if ((s = strchr(s, ']')) == NULL) 325 return NULL; 326 else 327 s++; 328 } else if ((s = strpbrk(s, ":/")) == NULL) 329 s = *cp + strlen(*cp); /* skip to end (see first case below) */ 330 331 switch (*s) { 332 case '\0': 333 *cp = NULL; /* no more fields*/ 334 break; 335 336 case ':': 337 case '/': 338 *s = '\0'; /* terminate */ 339 *cp = s + 1; 340 break; 341 342 default: 343 return NULL; 344 } 345 346 return old; 347 } 348 349 char * 350 cleanhostname(char *host) 351 { 352 if (*host == '[' && host[strlen(host) - 1] == ']') { 353 host[strlen(host) - 1] = '\0'; 354 return (host + 1); 355 } else 356 return host; 357 } 358 359 char * 360 colon(char *cp) 361 { 362 int flag = 0; 363 364 if (*cp == ':') /* Leading colon is part of file name. */ 365 return (0); 366 if (*cp == '[') 367 flag = 1; 368 369 for (; *cp; ++cp) { 370 if (*cp == '@' && *(cp+1) == '[') 371 flag = 1; 372 if (*cp == ']' && *(cp+1) == ':' && flag) 373 return (cp+1); 374 if (*cp == ':' && !flag) 375 return (cp); 376 if (*cp == '/') 377 return (0); 378 } 379 return (0); 380 } 381 382 /* function to assist building execv() arguments */ 383 /* PRINTFLIKE2 */ 384 void 385 addargs(arglist *args, char *fmt, ...) 386 { 387 va_list ap; 388 char buf[1024]; 389 390 va_start(ap, fmt); 391 vsnprintf(buf, sizeof(buf), fmt, ap); 392 va_end(ap); 393 394 if (args->list == NULL) { 395 args->nalloc = 32; 396 args->num = 0; 397 } else if (args->num+2 >= args->nalloc) 398 args->nalloc *= 2; 399 400 args->list = xrealloc(args->list, args->nalloc * sizeof(char *)); 401 args->list[args->num++] = xstrdup(buf); 402 args->list[args->num] = NULL; 403 } 404 405 void 406 replacearg(arglist *args, u_int which, char *fmt, ...) 407 { 408 va_list ap; 409 char *cp; 410 int r; 411 412 va_start(ap, fmt); 413 r = vasprintf(&cp, fmt, ap); 414 va_end(ap); 415 if (r == -1) 416 fatal("replacearg: argument too long"); 417 418 if (which >= args->num) 419 fatal("replacearg: tried to replace invalid arg %d >= %d", 420 which, args->num); 421 xfree(args->list[which]); 422 args->list[which] = cp; 423 } 424 425 void 426 freeargs(arglist *args) 427 { 428 u_int i; 429 430 if (args->list != NULL) { 431 for (i = 0; i < args->num; i++) 432 xfree(args->list[i]); 433 xfree(args->list); 434 args->nalloc = args->num = 0; 435 args->list = NULL; 436 } 437 } 438 439 /* 440 * Expand a string with a set of %[char] escapes. A number of escapes may be 441 * specified as (char *escape_chars, char *replacement) pairs. The list must 442 * be terminated by a NULL escape_char. Returns replaced string in memory 443 * allocated by xmalloc. 444 */ 445 char * 446 percent_expand(const char *string, ...) 447 { 448 #define EXPAND_MAX_KEYS 16 449 struct { 450 const char *key; 451 const char *repl; 452 } keys[EXPAND_MAX_KEYS]; 453 u_int num_keys, i, j; 454 char buf[4096]; 455 va_list ap; 456 457 /* Gather keys */ 458 va_start(ap, string); 459 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { 460 keys[num_keys].key = va_arg(ap, char *); 461 if (keys[num_keys].key == NULL) 462 break; 463 keys[num_keys].repl = va_arg(ap, char *); 464 if (keys[num_keys].repl == NULL) 465 fatal("percent_expand: NULL replacement"); 466 } 467 va_end(ap); 468 469 if (num_keys >= EXPAND_MAX_KEYS) 470 fatal("percent_expand: too many keys"); 471 472 /* Expand string */ 473 *buf = '\0'; 474 for (i = 0; *string != '\0'; string++) { 475 if (*string != '%') { 476 append: 477 buf[i++] = *string; 478 if (i >= sizeof(buf)) 479 fatal("percent_expand: string too long"); 480 buf[i] = '\0'; 481 continue; 482 } 483 string++; 484 if (*string == '%') 485 goto append; 486 for (j = 0; j < num_keys; j++) { 487 if (strchr(keys[j].key, *string) != NULL) { 488 i = strlcat(buf, keys[j].repl, sizeof(buf)); 489 if (i >= sizeof(buf)) 490 fatal("percent_expand: string too long"); 491 break; 492 } 493 } 494 if (j >= num_keys) 495 fatal("percent_expand: unknown key %%%c", *string); 496 } 497 return (xstrdup(buf)); 498 #undef EXPAND_MAX_KEYS 499 } 500 501 /* 502 * Ensure that file descriptors 0, 1 and 2 are open or directed to /dev/null, 503 * do not touch those that are already open. 504 */ 505 void 506 sanitise_stdfd(void) 507 { 508 int nullfd, dupfd; 509 510 if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 511 fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno)); 512 exit(1); 513 } 514 while (++dupfd <= 2) { 515 /* Only clobber closed fds */ 516 if (fcntl(dupfd, F_GETFL, 0) >= 0) 517 continue; 518 if (dup2(nullfd, dupfd) == -1) { 519 fprintf(stderr, "dup2: %s", strerror(errno)); 520 exit(1); 521 } 522 } 523 if (nullfd > 2) 524 close(nullfd); 525 } 526 527 char * 528 tohex(const void *vp, size_t l) 529 { 530 const u_char *p = (const u_char *)vp; 531 char b[3], *r; 532 size_t i, hl; 533 534 if (l > 65536) 535 return xstrdup("tohex: length > 65536"); 536 537 hl = l * 2 + 1; 538 r = xcalloc(1, hl); 539 for (i = 0; i < l; i++) { 540 snprintf(b, sizeof(b), "%02x", p[i]); 541 strlcat(r, b, hl); 542 } 543 return (r); 544 } 545 546 u_int64_t 547 get_u64(const void *vp) 548 { 549 const u_char *p = (const u_char *)vp; 550 u_int64_t v; 551 552 v = (u_int64_t)p[0] << 56; 553 v |= (u_int64_t)p[1] << 48; 554 v |= (u_int64_t)p[2] << 40; 555 v |= (u_int64_t)p[3] << 32; 556 v |= (u_int64_t)p[4] << 24; 557 v |= (u_int64_t)p[5] << 16; 558 v |= (u_int64_t)p[6] << 8; 559 v |= (u_int64_t)p[7]; 560 561 return (v); 562 } 563 564 u_int32_t 565 get_u32(const void *vp) 566 { 567 const u_char *p = (const u_char *)vp; 568 u_int32_t v; 569 570 v = (u_int32_t)p[0] << 24; 571 v |= (u_int32_t)p[1] << 16; 572 v |= (u_int32_t)p[2] << 8; 573 v |= (u_int32_t)p[3]; 574 575 return (v); 576 } 577 578 u_int16_t 579 get_u16(const void *vp) 580 { 581 const u_char *p = (const u_char *)vp; 582 u_int16_t v; 583 584 v = (u_int16_t)p[0] << 8; 585 v |= (u_int16_t)p[1]; 586 587 return (v); 588 } 589 590 void 591 put_u64(void *vp, u_int64_t v) 592 { 593 u_char *p = (u_char *)vp; 594 595 p[0] = (u_char)(v >> 56) & 0xff; 596 p[1] = (u_char)(v >> 48) & 0xff; 597 p[2] = (u_char)(v >> 40) & 0xff; 598 p[3] = (u_char)(v >> 32) & 0xff; 599 p[4] = (u_char)(v >> 24) & 0xff; 600 p[5] = (u_char)(v >> 16) & 0xff; 601 p[6] = (u_char)(v >> 8) & 0xff; 602 p[7] = (u_char)v & 0xff; 603 } 604 605 void 606 put_u32(void *vp, u_int32_t v) 607 { 608 u_char *p = (u_char *)vp; 609 610 p[0] = (u_char)(v >> 24) & 0xff; 611 p[1] = (u_char)(v >> 16) & 0xff; 612 p[2] = (u_char)(v >> 8) & 0xff; 613 p[3] = (u_char)v & 0xff; 614 } 615 616 617 void 618 put_u16(void *vp, u_int16_t v) 619 { 620 u_char *p = (u_char *)vp; 621 622 p[0] = (u_char)(v >> 8) & 0xff; 623 p[1] = (u_char)v & 0xff; 624 } 625 626 mysig_t 627 mysignal(int sig, mysig_t act) 628 { 629 #ifdef HAVE_SIGACTION 630 struct sigaction sa, osa; 631 632 if (sigaction(sig, NULL, &osa) == -1) 633 return (mysig_t) -1; 634 if (osa.sa_handler != act) { 635 memset(&sa, 0, sizeof(sa)); 636 sigemptyset(&sa.sa_mask); 637 sa.sa_flags = 0; 638 #if defined(SA_INTERRUPT) 639 if (sig == SIGALRM) 640 sa.sa_flags |= SA_INTERRUPT; 641 #endif 642 sa.sa_handler = act; 643 if (sigaction(sig, &sa, NULL) == -1) 644 return (mysig_t) -1; 645 } 646 return (osa.sa_handler); 647 #else 648 return (signal(sig, act)); 649 #endif 650 } 651 652 /* 653 * Return true if argument is one of "yes", "true", "no" or "false". If 654 * 'active' is 0 than we are in a non-matching Host section of the 655 * configuration file so we check the syntax but will not set the value of 656 * '*option'. Otherwise we set its value if not already set. 657 */ 658 int 659 get_yes_no_flag(int *option, const char *arg, const char *filename, int linenum, 660 int active) 661 { 662 int value = -1; 663 664 if (arg == NULL || *arg == '\0') 665 fatal("%.200s line %d: Missing argument.", filename, linenum); 666 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 667 value = 1; 668 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 669 value = 0; 670 671 if (active && *option == -1 && value != -1) 672 *option = value; 673 674 return (value != -1); 675 } 676 677 /* 678 * Convert a string to lowercase. The string returned is an internally allocated 679 * one so the consumer of this function is not expected to change it or free it. 680 */ 681 char * 682 tolowercase(const char *s) 683 { 684 int i, len; 685 static int lenret = 0; 686 static char *ret = NULL; 687 688 /* allocate a new string if the old one it not long enough to store s */ 689 len = strlen(s) + 1; 690 if (len > lenret) { 691 if (ret != NULL) 692 xfree(ret); 693 ret = xmalloc(len); 694 lenret = len; 695 } 696 697 /* process the string including the ending '\0' */ 698 for (i = 0; i < len; ++i) 699 ret[i] = tolower(s[i]); 700 701 return (ret); 702 }