misc.c revision 146998
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#include "includes.h" 26RCSID("$OpenBSD: misc.c,v 1.28 2005/03/01 10:09:52 djm Exp $"); 27 28#include "misc.h" 29#include "log.h" 30#include "xmalloc.h" 31 32/* remove newline at end of string */ 33char * 34chop(char *s) 35{ 36 char *t = s; 37 while (*t) { 38 if (*t == '\n' || *t == '\r') { 39 *t = '\0'; 40 return s; 41 } 42 t++; 43 } 44 return s; 45 46} 47 48/* set/unset filedescriptor to non-blocking */ 49int 50set_nonblock(int fd) 51{ 52 int val; 53 54 val = fcntl(fd, F_GETFL, 0); 55 if (val < 0) { 56 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 57 return (-1); 58 } 59 if (val & O_NONBLOCK) { 60 debug3("fd %d is O_NONBLOCK", fd); 61 return (0); 62 } 63 debug2("fd %d setting O_NONBLOCK", fd); 64 val |= O_NONBLOCK; 65 if (fcntl(fd, F_SETFL, val) == -1) { 66 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, 67 strerror(errno)); 68 return (-1); 69 } 70 return (0); 71} 72 73int 74unset_nonblock(int fd) 75{ 76 int val; 77 78 val = fcntl(fd, F_GETFL, 0); 79 if (val < 0) { 80 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 81 return (-1); 82 } 83 if (!(val & O_NONBLOCK)) { 84 debug3("fd %d is not O_NONBLOCK", fd); 85 return (0); 86 } 87 debug("fd %d clearing O_NONBLOCK", fd); 88 val &= ~O_NONBLOCK; 89 if (fcntl(fd, F_SETFL, val) == -1) { 90 debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s", 91 fd, strerror(errno)); 92 return (-1); 93 } 94 return (0); 95} 96 97/* disable nagle on socket */ 98void 99set_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 debug("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 debug2("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/* return next token in configuration line */ 123char * 124strdelim(char **s) 125{ 126 char *old; 127 int wspace = 0; 128 129 if (*s == NULL) 130 return NULL; 131 132 old = *s; 133 134 *s = strpbrk(*s, WHITESPACE "="); 135 if (*s == NULL) 136 return (old); 137 138 /* Allow only one '=' to be skipped */ 139 if (*s[0] == '=') 140 wspace = 1; 141 *s[0] = '\0'; 142 143 *s += strspn(*s + 1, WHITESPACE) + 1; 144 if (*s[0] == '=' && !wspace) 145 *s += strspn(*s + 1, WHITESPACE) + 1; 146 147 return (old); 148} 149 150struct passwd * 151pwcopy(struct passwd *pw) 152{ 153 struct passwd *copy = xmalloc(sizeof(*copy)); 154 155 memset(copy, 0, sizeof(*copy)); 156 copy->pw_name = xstrdup(pw->pw_name); 157 copy->pw_passwd = xstrdup(pw->pw_passwd); 158 copy->pw_gecos = xstrdup(pw->pw_gecos); 159 copy->pw_uid = pw->pw_uid; 160 copy->pw_gid = pw->pw_gid; 161#ifdef HAVE_PW_EXPIRE_IN_PASSWD 162 copy->pw_expire = pw->pw_expire; 163#endif 164#ifdef HAVE_PW_CHANGE_IN_PASSWD 165 copy->pw_change = pw->pw_change; 166#endif 167#ifdef HAVE_PW_CLASS_IN_PASSWD 168 copy->pw_class = xstrdup(pw->pw_class); 169#endif 170 copy->pw_dir = xstrdup(pw->pw_dir); 171 copy->pw_shell = xstrdup(pw->pw_shell); 172 return copy; 173} 174 175/* 176 * Convert ASCII string to TCP/IP port number. 177 * Port must be >0 and <=65535. 178 * Return 0 if invalid. 179 */ 180int 181a2port(const char *s) 182{ 183 long port; 184 char *endp; 185 186 errno = 0; 187 port = strtol(s, &endp, 0); 188 if (s == endp || *endp != '\0' || 189 (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || 190 port <= 0 || port > 65535) 191 return 0; 192 193 return port; 194} 195 196#define SECONDS 1 197#define MINUTES (SECONDS * 60) 198#define HOURS (MINUTES * 60) 199#define DAYS (HOURS * 24) 200#define WEEKS (DAYS * 7) 201 202/* 203 * Convert a time string into seconds; format is 204 * a sequence of: 205 * time[qualifier] 206 * 207 * Valid time qualifiers are: 208 * <none> seconds 209 * s|S seconds 210 * m|M minutes 211 * h|H hours 212 * d|D days 213 * w|W weeks 214 * 215 * Examples: 216 * 90m 90 minutes 217 * 1h30m 90 minutes 218 * 2d 2 days 219 * 1w 1 week 220 * 221 * Return -1 if time string is invalid. 222 */ 223long 224convtime(const char *s) 225{ 226 long total, secs; 227 const char *p; 228 char *endp; 229 230 errno = 0; 231 total = 0; 232 p = s; 233 234 if (p == NULL || *p == '\0') 235 return -1; 236 237 while (*p) { 238 secs = strtol(p, &endp, 10); 239 if (p == endp || 240 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 241 secs < 0) 242 return -1; 243 244 switch (*endp++) { 245 case '\0': 246 endp--; 247 case 's': 248 case 'S': 249 break; 250 case 'm': 251 case 'M': 252 secs *= MINUTES; 253 break; 254 case 'h': 255 case 'H': 256 secs *= HOURS; 257 break; 258 case 'd': 259 case 'D': 260 secs *= DAYS; 261 break; 262 case 'w': 263 case 'W': 264 secs *= WEEKS; 265 break; 266 default: 267 return -1; 268 } 269 total += secs; 270 if (total < 0) 271 return -1; 272 p = endp; 273 } 274 275 return total; 276} 277 278/* 279 * Search for next delimiter between hostnames/addresses and ports. 280 * Argument may be modified (for termination). 281 * Returns *cp if parsing succeeds. 282 * *cp is set to the start of the next delimiter, if one was found. 283 * If this is the last field, *cp is set to NULL. 284 */ 285char * 286hpdelim(char **cp) 287{ 288 char *s, *old; 289 290 if (cp == NULL || *cp == NULL) 291 return NULL; 292 293 old = s = *cp; 294 if (*s == '[') { 295 if ((s = strchr(s, ']')) == NULL) 296 return NULL; 297 else 298 s++; 299 } else if ((s = strpbrk(s, ":/")) == NULL) 300 s = *cp + strlen(*cp); /* skip to end (see first case below) */ 301 302 switch (*s) { 303 case '\0': 304 *cp = NULL; /* no more fields*/ 305 break; 306 307 case ':': 308 case '/': 309 *s = '\0'; /* terminate */ 310 *cp = s + 1; 311 break; 312 313 default: 314 return NULL; 315 } 316 317 return old; 318} 319 320char * 321cleanhostname(char *host) 322{ 323 if (*host == '[' && host[strlen(host) - 1] == ']') { 324 host[strlen(host) - 1] = '\0'; 325 return (host + 1); 326 } else 327 return host; 328} 329 330char * 331colon(char *cp) 332{ 333 int flag = 0; 334 335 if (*cp == ':') /* Leading colon is part of file name. */ 336 return (0); 337 if (*cp == '[') 338 flag = 1; 339 340 for (; *cp; ++cp) { 341 if (*cp == '@' && *(cp+1) == '[') 342 flag = 1; 343 if (*cp == ']' && *(cp+1) == ':' && flag) 344 return (cp+1); 345 if (*cp == ':' && !flag) 346 return (cp); 347 if (*cp == '/') 348 return (0); 349 } 350 return (0); 351} 352 353/* function to assist building execv() arguments */ 354void 355addargs(arglist *args, char *fmt, ...) 356{ 357 va_list ap; 358 char buf[1024]; 359 u_int nalloc; 360 361 va_start(ap, fmt); 362 vsnprintf(buf, sizeof(buf), fmt, ap); 363 va_end(ap); 364 365 nalloc = args->nalloc; 366 if (args->list == NULL) { 367 nalloc = 32; 368 args->num = 0; 369 } else if (args->num+2 >= nalloc) 370 nalloc *= 2; 371 372 args->list = xrealloc(args->list, nalloc * sizeof(char *)); 373 args->nalloc = nalloc; 374 args->list[args->num++] = xstrdup(buf); 375 args->list[args->num] = NULL; 376} 377 378/* 379 * Read an entire line from a public key file into a static buffer, discarding 380 * lines that exceed the buffer size. Returns 0 on success, -1 on failure. 381 */ 382int 383read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, 384 u_long *lineno) 385{ 386 while (fgets(buf, bufsz, f) != NULL) { 387 (*lineno)++; 388 if (buf[strlen(buf) - 1] == '\n' || feof(f)) { 389 return 0; 390 } else { 391 debug("%s: %s line %lu exceeds size limit", __func__, 392 filename, *lineno); 393 /* discard remainder of line */ 394 while(fgetc(f) != '\n' && !feof(f)) 395 ; /* nothing */ 396 } 397 } 398 return -1; 399} 400