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