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 char * 310 cleanhostname(char *host) 311 { 312 if (*host == '[' && host[strlen(host) - 1] == ']') { 313 host[strlen(host) - 1] = '\0'; 314 return (host + 1); 315 } else 316 return host; 317 } 318 319 char * 320 colon(char *cp) 321 { 322 int flag = 0; 323 324 if (*cp == ':') /* Leading colon is part of file name. */ 325 return (0); 326 if (*cp == '[') 327 flag = 1; 328 329 for (; *cp; ++cp) { 330 if (*cp == '@' && *(cp+1) == '[') 331 flag = 1; 332 if (*cp == ']' && *(cp+1) == ':' && flag) 333 return (cp+1); 334 if (*cp == ':' && !flag) 335 return (cp); 336 if (*cp == '/') 337 return (0); 338 } 339 return (0); 340 } 341 342 /* function to assist building execv() arguments */ 343 /* PRINTFLIKE2 */ 344 void 345 addargs(arglist *args, char *fmt, ...) 346 { 347 va_list ap; 348 char buf[1024]; 349 350 va_start(ap, fmt); 351 vsnprintf(buf, sizeof(buf), fmt, ap); 352 va_end(ap); 353 354 if (args->list == NULL) { 355 args->nalloc = 32; 356 args->num = 0; 357 } else if (args->num+2 >= args->nalloc) 358 args->nalloc *= 2; 359 360 args->list = xrealloc(args->list, args->nalloc * sizeof(char *)); 361 args->list[args->num++] = xstrdup(buf); 362 args->list[args->num] = NULL; 363 } 364 365 void 366 replacearg(arglist *args, u_int which, char *fmt, ...) 367 { 368 va_list ap; 369 char *cp; 370 int r; 371 372 va_start(ap, fmt); 373 r = vasprintf(&cp, fmt, ap); 374 va_end(ap); 375 if (r == -1) 376 fatal("replacearg: argument too long"); 377 378 if (which >= args->num) 379 fatal("replacearg: tried to replace invalid arg %d >= %d", 380 which, args->num); 381 xfree(args->list[which]); 382 args->list[which] = cp; 383 } 384 385 void 386 freeargs(arglist *args) 387 { 388 u_int i; 389 390 if (args->list != NULL) { 391 for (i = 0; i < args->num; i++) 392 xfree(args->list[i]); 393 xfree(args->list); 394 args->nalloc = args->num = 0; 395 args->list = NULL; 396 } 397 } 398 399 /* 400 * Ensure that file descriptors 0, 1 and 2 are open or directed to /dev/null, 401 * do not touch those that are already open. 402 */ 403 void 404 sanitise_stdfd(void) 405 { 406 int nullfd, dupfd; 407 408 if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 409 fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno)); 410 exit(1); 411 } 412 while (++dupfd <= 2) { 413 /* Only clobber closed fds */ 414 if (fcntl(dupfd, F_GETFL, 0) >= 0) 415 continue; 416 if (dup2(nullfd, dupfd) == -1) { 417 fprintf(stderr, "dup2: %s", strerror(errno)); 418 exit(1); 419 } 420 } 421 if (nullfd > 2) 422 close(nullfd); 423 } 424 425 char * 426 tohex(const void *vp, size_t l) 427 { 428 const u_char *p = (const u_char *)vp; 429 char b[3], *r; 430 size_t i, hl; 431 432 if (l > 65536) 433 return xstrdup("tohex: length > 65536"); 434 435 hl = l * 2 + 1; 436 r = xcalloc(1, hl); 437 for (i = 0; i < l; i++) { 438 snprintf(b, sizeof(b), "%02x", p[i]); 439 strlcat(r, b, hl); 440 } 441 return (r); 442 } 443 444 u_int64_t 445 get_u64(const void *vp) 446 { 447 const u_char *p = (const u_char *)vp; 448 u_int64_t v; 449 450 v = (u_int64_t)p[0] << 56; 451 v |= (u_int64_t)p[1] << 48; 452 v |= (u_int64_t)p[2] << 40; 453 v |= (u_int64_t)p[3] << 32; 454 v |= (u_int64_t)p[4] << 24; 455 v |= (u_int64_t)p[5] << 16; 456 v |= (u_int64_t)p[6] << 8; 457 v |= (u_int64_t)p[7]; 458 459 return (v); 460 } 461 462 u_int32_t 463 get_u32(const void *vp) 464 { 465 const u_char *p = (const u_char *)vp; 466 u_int32_t v; 467 468 v = (u_int32_t)p[0] << 24; 469 v |= (u_int32_t)p[1] << 16; 470 v |= (u_int32_t)p[2] << 8; 471 v |= (u_int32_t)p[3]; 472 473 return (v); 474 } 475 476 u_int16_t 477 get_u16(const void *vp) 478 { 479 const u_char *p = (const u_char *)vp; 480 u_int16_t v; 481 482 v = (u_int16_t)p[0] << 8; 483 v |= (u_int16_t)p[1]; 484 485 return (v); 486 } 487 488 void 489 put_u64(void *vp, u_int64_t v) 490 { 491 u_char *p = (u_char *)vp; 492 493 p[0] = (u_char)(v >> 56) & 0xff; 494 p[1] = (u_char)(v >> 48) & 0xff; 495 p[2] = (u_char)(v >> 40) & 0xff; 496 p[3] = (u_char)(v >> 32) & 0xff; 497 p[4] = (u_char)(v >> 24) & 0xff; 498 p[5] = (u_char)(v >> 16) & 0xff; 499 p[6] = (u_char)(v >> 8) & 0xff; 500 p[7] = (u_char)v & 0xff; 501 } 502 503 void 504 put_u32(void *vp, u_int32_t v) 505 { 506 u_char *p = (u_char *)vp; 507 508 p[0] = (u_char)(v >> 24) & 0xff; 509 p[1] = (u_char)(v >> 16) & 0xff; 510 p[2] = (u_char)(v >> 8) & 0xff; 511 p[3] = (u_char)v & 0xff; 512 } 513 514 515 void 516 put_u16(void *vp, u_int16_t v) 517 { 518 u_char *p = (u_char *)vp; 519 520 p[0] = (u_char)(v >> 8) & 0xff; 521 p[1] = (u_char)v & 0xff; 522 } 523 524 mysig_t 525 mysignal(int sig, mysig_t act) 526 { 527 #ifdef HAVE_SIGACTION 528 struct sigaction sa, osa; 529 530 if (sigaction(sig, NULL, &osa) == -1) 531 return (mysig_t) -1; 532 if (osa.sa_handler != act) { 533 memset(&sa, 0, sizeof(sa)); 534 sigemptyset(&sa.sa_mask); 535 sa.sa_flags = 0; 536 #if defined(SA_INTERRUPT) 537 if (sig == SIGALRM) 538 sa.sa_flags |= SA_INTERRUPT; 539 #endif 540 sa.sa_handler = act; 541 if (sigaction(sig, &sa, NULL) == -1) 542 return (mysig_t) -1; 543 } 544 return (osa.sa_handler); 545 #else 546 return (signal(sig, act)); 547 #endif 548 } 549 550 /* 551 * Return true if argument is one of "yes", "true", "no" or "false". If 552 * 'active' is 0 than we are in a non-matching Host section of the 553 * configuration file so we check the syntax but will not set the value of 554 * '*option'. Otherwise we set its value if not already set. 555 */ 556 int 557 get_yes_no_flag(int *option, const char *arg, const char *filename, int linenum, 558 int active) 559 { 560 int value = -1; 561 562 if (arg == NULL || *arg == '\0') 563 fatal("%.200s line %d: Missing argument.", filename, linenum); 564 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 565 value = 1; 566 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 567 value = 0; 568 569 if (active && *option == -1 && value != -1) 570 *option = value; 571 572 return (value != -1); 573 } 574 575 /* 576 * Convert a string to lowercase. The string returned is an internally allocated 577 * one so the consumer of this function is not expected to change it or free it. 578 */ 579 char * 580 tolowercase(const char *s) 581 { 582 int i, len; 583 static int lenret = 0; 584 static char *ret = NULL; 585 586 /* allocate a new string if the old one it not long enough to store s */ 587 len = strlen(s) + 1; 588 if (len > lenret) { 589 if (ret != NULL) 590 xfree(ret); 591 ret = xmalloc(len); 592 lenret = len; 593 } 594 595 /* process the string including the ending '\0' */ 596 for (i = 0; i < len; ++i) 597 ret[i] = tolower(s[i]); 598 599 return (ret); 600 } 601