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 }