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.20 2002/12/13 10:03:15 markus 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 void 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; 58 } 59 if (val & O_NONBLOCK) { 60 debug2("fd %d is O_NONBLOCK", fd); 61 return; 62 } 63 debug("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", 67 fd, strerror(errno)); 68 } 69 70 void 71 unset_nonblock(int fd) 72 { 73 int val; 74 75 val = fcntl(fd, F_GETFL, 0); 76 if (val < 0) { 77 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); 78 return; 79 } 80 if (!(val & O_NONBLOCK)) { 81 debug2("fd %d is not O_NONBLOCK", fd); 82 return; 83 } 84 debug("fd %d clearing O_NONBLOCK", fd); 85 val &= ~O_NONBLOCK; 86 if (fcntl(fd, F_SETFL, val) == -1) 87 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", 88 fd, strerror(errno)); 89 } 90 91 /* disable nagle on socket */ 92 void 93 set_nodelay(int fd) 94 { 95 int opt; 96 socklen_t optlen; 97 98 optlen = sizeof opt; 99 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { 100 error("getsockopt TCP_NODELAY: %.100s", strerror(errno)); 101 return; 102 } 103 if (opt == 1) { 104 debug2("fd %d is TCP_NODELAY", fd); 105 return; 106 } 107 opt = 1; 108 debug2("fd %d setting TCP_NODELAY", fd); 109 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) 110 error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); 111 } 112 113 /* Characters considered whitespace in strsep calls. */ 114 #define WHITESPACE " \t\r\n" 115 116 /* return next token in configuration line */ 117 char * 118 strdelim(char **s) 119 { 120 char *old; 121 int wspace = 0; 122 123 if (*s == NULL) 124 return NULL; 125 126 old = *s; 127 128 *s = strpbrk(*s, WHITESPACE "="); 129 if (*s == NULL) 130 return (old); 131 132 /* Allow only one '=' to be skipped */ 133 if (*s[0] == '=') 134 wspace = 1; 135 *s[0] = '\0'; 136 137 *s += strspn(*s + 1, WHITESPACE) + 1; 138 if (*s[0] == '=' && !wspace) 139 *s += strspn(*s + 1, WHITESPACE) + 1; 140 141 return (old); 142 } 143 144 struct passwd * 145 pwcopy(struct passwd *pw) 146 { 147 struct passwd *copy = xmalloc(sizeof(*copy)); 148 149 memset(copy, 0, sizeof(*copy)); 150 copy->pw_name = xstrdup(pw->pw_name); 151 copy->pw_passwd = xstrdup(pw->pw_passwd); 152 copy->pw_gecos = xstrdup(pw->pw_gecos); 153 copy->pw_uid = pw->pw_uid; 154 copy->pw_gid = pw->pw_gid; 155 #ifdef HAVE_PW_EXPIRE_IN_PASSWD 156 copy->pw_expire = pw->pw_expire; 157 #endif 158 #ifdef HAVE_PW_CHANGE_IN_PASSWD 159 copy->pw_change = pw->pw_change; 160 #endif 161 #ifdef HAVE_PW_CLASS_IN_PASSWD 162 copy->pw_class = xstrdup(pw->pw_class); 163 #endif 164 copy->pw_dir = xstrdup(pw->pw_dir); 165 copy->pw_shell = xstrdup(pw->pw_shell); 166 return copy; 167 } 168 169 /* 170 * Convert ASCII string to TCP/IP port number. 171 * Port must be >0 and <=65535. 172 * Return 0 if invalid. 173 */ 174 int 175 a2port(const char *s) 176 { 177 long port; 178 char *endp; 179 180 errno = 0; 181 port = strtol(s, &endp, 0); 182 if (s == endp || *endp != '\0' || 183 (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || 184 port <= 0 || port > 65535) 185 return 0; 186 187 return port; 188 } 189 190 #define SECONDS 1 191 #define MINUTES (SECONDS * 60) 192 #define HOURS (MINUTES * 60) 193 #define DAYS (HOURS * 24) 194 #define WEEKS (DAYS * 7) 195 196 /* 197 * Convert a time string into seconds; format is 198 * a sequence of: 199 * time[qualifier] 200 * 201 * Valid time qualifiers are: 202 * <none> seconds 203 * s|S seconds 204 * m|M minutes 205 * h|H hours 206 * d|D days 207 * w|W weeks 208 * 209 * Examples: 210 * 90m 90 minutes 211 * 1h30m 90 minutes 212 * 2d 2 days 213 * 1w 1 week 214 * 215 * Return -1 if time string is invalid. 216 */ 217 long 218 convtime(const char *s) 219 { 220 long total, secs; 221 const char *p; 222 char *endp; 223 224 errno = 0; 225 total = 0; 226 p = s; 227 228 if (p == NULL || *p == '\0') 229 return -1; 230 231 while (*p) { 232 secs = strtol(p, &endp, 10); 233 if (p == endp || 234 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || 235 secs < 0) 236 return -1; 237 238 switch (*endp++) { 239 case '\0': 240 endp--; 241 case 's': 242 case 'S': 243 break; 244 case 'm': 245 case 'M': 246 secs *= MINUTES; 247 break; 248 case 'h': 249 case 'H': 250 secs *= HOURS; 251 break; 252 case 'd': 253 case 'D': 254 secs *= DAYS; 255 break; 256 case 'w': 257 case 'W': 258 secs *= WEEKS; 259 break; 260 default: 261 return -1; 262 } 263 total += secs; 264 if (total < 0) 265 return -1; 266 p = endp; 267 } 268 269 return total; 270 } 271 272 char * 273 cleanhostname(char *host) 274 { 275 if (*host == '[' && host[strlen(host) - 1] == ']') { 276 host[strlen(host) - 1] = '\0'; 277 return (host + 1); 278 } else 279 return host; 280 } 281 282 char * 283 colon(char *cp) 284 { 285 int flag = 0; 286 287 if (*cp == ':') /* Leading colon is part of file name. */ 288 return (0); 289 if (*cp == '[') 290 flag = 1; 291 292 for (; *cp; ++cp) { 293 if (*cp == '@' && *(cp+1) == '[') 294 flag = 1; 295 if (*cp == ']' && *(cp+1) == ':' && flag) 296 return (cp+1); 297 if (*cp == ':' && !flag) 298 return (cp); 299 if (*cp == '/') 300 return (0); 301 } 302 return (0); 303 } 304 305 /* function to assist building execv() arguments */ 306 void 307 addargs(arglist *args, char *fmt, ...) 308 { 309 va_list ap; 310 char buf[1024]; 311 int nalloc; 312 313 va_start(ap, fmt); 314 vsnprintf(buf, sizeof(buf), fmt, ap); 315 va_end(ap); 316 317 nalloc = args->nalloc; 318 if (args->list == NULL) { 319 nalloc = 32; 320 args->num = 0; 321 } else if (args->num+2 >= nalloc) 322 nalloc *= 2; 323 324 args->list = xrealloc(args->list, nalloc * sizeof(char *)); 325 args->nalloc = nalloc; 326 args->list[args->num++] = xstrdup(buf); 327 args->list[args->num] = NULL; 328 } 329 330 mysig_t 331 mysignal(int sig, mysig_t act) 332 { 333 #ifdef HAVE_SIGACTION 334 struct sigaction sa, osa; 335 336 if (sigaction(sig, NULL, &osa) == -1) 337 return (mysig_t) -1; 338 if (osa.sa_handler != act) { 339 memset(&sa, 0, sizeof(sa)); 340 sigemptyset(&sa.sa_mask); 341 sa.sa_flags = 0; 342 #if defined(SA_INTERRUPT) 343 if (sig == SIGALRM) 344 sa.sa_flags |= SA_INTERRUPT; 345 #endif 346 sa.sa_handler = act; 347 if (sigaction(sig, &sa, NULL) == -1) 348 return (mysig_t) -1; 349 } 350 return (osa.sa_handler); 351 #else 352 return (signal(sig, act)); 353 #endif 354 } 355