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" 26 RCSID("$OpenBSD: misc.c,v 1.25 2004/08/11 21:43:05 avsm Exp $"); 27 28 #include "misc.h" 29 #include "log.h" 30 #include "xmalloc.h" 31 32 /* remove newline at end of string */ 33 char * 34 chop(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 */ 49 int 50 set_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 73 int 74 unset_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 */ 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 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 */ 123 char * 124 strdelim(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 150 struct passwd * 151 pwcopy(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 */ 180 int 181 a2port(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 */ 223 long 224 convtime(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 char * 279 cleanhostname(char *host) 280 { 281 if (*host == '[' && host[strlen(host) - 1] == ']') { 282 host[strlen(host) - 1] = '\0'; 283 return (host + 1); 284 } else 285 return host; 286 } 287 288 char * 289 colon(char *cp) 290 { 291 int flag = 0; 292 293 if (*cp == ':') /* Leading colon is part of file name. */ 294 return (0); 295 if (*cp == '[') 296 flag = 1; 297 298 for (; *cp; ++cp) { 299 if (*cp == '@' && *(cp+1) == '[') 300 flag = 1; 301 if (*cp == ']' && *(cp+1) == ':' && flag) 302 return (cp+1); 303 if (*cp == ':' && !flag) 304 return (cp); 305 if (*cp == '/') 306 return (0); 307 } 308 return (0); 309 } 310 311 /* function to assist building execv() arguments */ 312 void 313 addargs(arglist *args, char *fmt, ...) 314 { 315 va_list ap; 316 char buf[1024]; 317 u_int nalloc; 318 319 va_start(ap, fmt); 320 vsnprintf(buf, sizeof(buf), fmt, ap); 321 va_end(ap); 322 323 nalloc = args->nalloc; 324 if (args->list == NULL) { 325 nalloc = 32; 326 args->num = 0; 327 } else if (args->num+2 >= nalloc) 328 nalloc *= 2; 329 330 args->list = xrealloc(args->list, nalloc * sizeof(char *)); 331 args->nalloc = nalloc; 332 args->list[args->num++] = xstrdup(buf); 333 args->list[args->num] = NULL; 334 } 335