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 freeargs(arglist *args) 367 { 368 u_int i; 369 370 if (args->list != NULL) { 371 for (i = 0; i < args->num; i++) 372 xfree(args->list[i]); 373 xfree(args->list); 374 args->nalloc = args->num = 0; 375 args->list = NULL; 376 } 377 } 378 379 char * 380 tohex(const void *vp, size_t l) 381 { 382 const u_char *p = (const u_char *)vp; 383 char b[3], *r; 384 size_t i, hl; 385 386 if (l > 65536) 387 return xstrdup("tohex: length > 65536"); 388 389 hl = l * 2 + 1; 390 r = xcalloc(1, hl); 391 for (i = 0; i < l; i++) { 392 snprintf(b, sizeof(b), "%02x", p[i]); 393 strlcat(r, b, hl); 394 } 395 return (r); 396 } 397 398 mysig_t 399 mysignal(int sig, mysig_t act) 400 { 401 #ifdef HAVE_SIGACTION 402 struct sigaction sa, osa; 403 404 if (sigaction(sig, NULL, &osa) == -1) 405 return (mysig_t) -1; 406 if (osa.sa_handler != act) { 407 memset(&sa, 0, sizeof(sa)); 408 sigemptyset(&sa.sa_mask); 409 sa.sa_flags = 0; 410 #if defined(SA_INTERRUPT) 411 if (sig == SIGALRM) 412 sa.sa_flags |= SA_INTERRUPT; 413 #endif 414 sa.sa_handler = act; 415 if (sigaction(sig, &sa, NULL) == -1) 416 return (mysig_t) -1; 417 } 418 return (osa.sa_handler); 419 #else 420 return (signal(sig, act)); 421 #endif 422 } 423 424 /* 425 * Return true if argument is one of "yes", "true", "no" or "false". If 426 * 'active' is 0 than we are in a non-matching Host section of the 427 * configuration file so we check the syntax but will not set the value of 428 * '*option'. Otherwise we set its value if not already set. 429 */ 430 int 431 get_yes_no_flag(int *option, const char *arg, const char *filename, int linenum, 432 int active) 433 { 434 int value = -1; 435 436 if (arg == NULL || *arg == '\0') 437 fatal("%.200s line %d: Missing argument.", filename, linenum); 438 if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) 439 value = 1; 440 else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) 441 value = 0; 442 443 if (active && *option == -1 && value != -1) 444 *option = value; 445 446 return (value != -1); 447 } 448