]> andersk Git - gssapi-openssh.git/blame - openssh/misc.c
merged OpenSSH 4.2p1 to trunk
[gssapi-openssh.git] / openssh / misc.c
CommitLineData
3c0ef626 1/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
2ce0bfe4 3 * Copyright (c) 2005 Damien Miller. All rights reserved.
3c0ef626 4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
2ce0bfe4 27RCSID("$OpenBSD: misc.c,v 1.34 2005/07/08 09:26:18 dtucker Exp $");
3c0ef626 28
29#include "misc.h"
30#include "log.h"
31#include "xmalloc.h"
32
33/* remove newline at end of string */
34char *
35chop(char *s)
36{
37 char *t = s;
38 while (*t) {
75be3237 39 if (*t == '\n' || *t == '\r') {
3c0ef626 40 *t = '\0';
41 return s;
42 }
43 t++;
44 }
45 return s;
46
47}
48
49/* set/unset filedescriptor to non-blocking */
7e82606e 50int
3c0ef626 51set_nonblock(int fd)
52{
53 int val;
54
55 val = fcntl(fd, F_GETFL, 0);
56 if (val < 0) {
57 error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno));
7e82606e 58 return (-1);
3c0ef626 59 }
60 if (val & O_NONBLOCK) {
7e82606e 61 debug3("fd %d is O_NONBLOCK", fd);
62 return (0);
3c0ef626 63 }
7cac2b65 64 debug2("fd %d setting O_NONBLOCK", fd);
3c0ef626 65 val |= O_NONBLOCK;
7e82606e 66 if (fcntl(fd, F_SETFL, val) == -1) {
67 debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd,
68 strerror(errno));
69 return (-1);
70 }
71 return (0);
3c0ef626 72}
73
7e82606e 74int
3c0ef626 75unset_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));
7e82606e 82 return (-1);
3c0ef626 83 }
84 if (!(val & O_NONBLOCK)) {
7e82606e 85 debug3("fd %d is not O_NONBLOCK", fd);
86 return (0);
3c0ef626 87 }
88 debug("fd %d clearing O_NONBLOCK", fd);
89 val &= ~O_NONBLOCK;
7e82606e 90 if (fcntl(fd, F_SETFL, val) == -1) {
91 debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s",
75be3237 92 fd, strerror(errno));
7e82606e 93 return (-1);
94 }
95 return (0);
75be3237 96}
97
98/* disable nagle on socket */
99void
100set_nodelay(int fd)
101{
102 int opt;
103 socklen_t optlen;
104
105 optlen = sizeof opt;
106 if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) {
540d72c3 107 debug("getsockopt TCP_NODELAY: %.100s", strerror(errno));
75be3237 108 return;
109 }
110 if (opt == 1) {
111 debug2("fd %d is TCP_NODELAY", fd);
112 return;
113 }
114 opt = 1;
115 debug2("fd %d setting TCP_NODELAY", fd);
116 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1)
117 error("setsockopt TCP_NODELAY: %.100s", strerror(errno));
3c0ef626 118}
119
120/* Characters considered whitespace in strsep calls. */
121#define WHITESPACE " \t\r\n"
122
75be3237 123/* Characters considered as quotations. */
124#define QUOTES "'\""
125
3c0ef626 126/* return next token in configuration line */
127char *
128strdelim(char **s)
129{
75be3237 130 char *old, *p, *q;
3c0ef626 131 int wspace = 0;
132
133 if (*s == NULL)
134 return NULL;
135
136 old = *s;
137
75be3237 138 if ((q=strchr(QUOTES, (int) *old)) && *q)
139 {
140 /* find next quote character, point old to start of quoted
141 * string */
142 for (p = ++old;*p && *p!=*q; p++)
143 ;
144
145 /* find start of next token */
146 *s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL;
147
148 /* terminate 'old' token */
149 *p = '\0';
150 return (old);
151 }
152
153 *s = strpbrk(*s, WHITESPACE "=");
3c0ef626 154 if (*s == NULL)
155 return (old);
156
157 /* Allow only one '=' to be skipped */
158 if (*s[0] == '=')
159 wspace = 1;
160 *s[0] = '\0';
161
162 *s += strspn(*s + 1, WHITESPACE) + 1;
163 if (*s[0] == '=' && !wspace)
164 *s += strspn(*s + 1, WHITESPACE) + 1;
165
166 return (old);
167}
168
169struct passwd *
170pwcopy(struct passwd *pw)
171{
172 struct passwd *copy = xmalloc(sizeof(*copy));
173
174 memset(copy, 0, sizeof(*copy));
175 copy->pw_name = xstrdup(pw->pw_name);
176 copy->pw_passwd = xstrdup(pw->pw_passwd);
177 copy->pw_gecos = xstrdup(pw->pw_gecos);
178 copy->pw_uid = pw->pw_uid;
179 copy->pw_gid = pw->pw_gid;
180#ifdef HAVE_PW_EXPIRE_IN_PASSWD
181 copy->pw_expire = pw->pw_expire;
182#endif
183#ifdef HAVE_PW_CHANGE_IN_PASSWD
184 copy->pw_change = pw->pw_change;
185#endif
186#ifdef HAVE_PW_CLASS_IN_PASSWD
187 copy->pw_class = xstrdup(pw->pw_class);
188#endif
189 copy->pw_dir = xstrdup(pw->pw_dir);
190 copy->pw_shell = xstrdup(pw->pw_shell);
191 return copy;
192}
193
194/*
195 * Convert ASCII string to TCP/IP port number.
196 * Port must be >0 and <=65535.
197 * Return 0 if invalid.
198 */
199int
200a2port(const char *s)
201{
202 long port;
203 char *endp;
204
205 errno = 0;
206 port = strtol(s, &endp, 0);
207 if (s == endp || *endp != '\0' ||
208 (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) ||
209 port <= 0 || port > 65535)
210 return 0;
211
212 return port;
213}
214
215#define SECONDS 1
216#define MINUTES (SECONDS * 60)
217#define HOURS (MINUTES * 60)
218#define DAYS (HOURS * 24)
219#define WEEKS (DAYS * 7)
220
221/*
222 * Convert a time string into seconds; format is
223 * a sequence of:
224 * time[qualifier]
225 *
226 * Valid time qualifiers are:
227 * <none> seconds
228 * s|S seconds
229 * m|M minutes
230 * h|H hours
231 * d|D days
232 * w|W weeks
233 *
234 * Examples:
235 * 90m 90 minutes
236 * 1h30m 90 minutes
237 * 2d 2 days
238 * 1w 1 week
239 *
240 * Return -1 if time string is invalid.
241 */
242long
243convtime(const char *s)
244{
245 long total, secs;
246 const char *p;
247 char *endp;
248
249 errno = 0;
250 total = 0;
251 p = s;
252
253 if (p == NULL || *p == '\0')
254 return -1;
255
256 while (*p) {
257 secs = strtol(p, &endp, 10);
258 if (p == endp ||
259 (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) ||
260 secs < 0)
261 return -1;
262
263 switch (*endp++) {
264 case '\0':
265 endp--;
266 case 's':
267 case 'S':
268 break;
269 case 'm':
270 case 'M':
271 secs *= MINUTES;
272 break;
273 case 'h':
274 case 'H':
275 secs *= HOURS;
276 break;
277 case 'd':
278 case 'D':
279 secs *= DAYS;
280 break;
281 case 'w':
282 case 'W':
283 secs *= WEEKS;
284 break;
285 default:
286 return -1;
287 }
288 total += secs;
289 if (total < 0)
290 return -1;
291 p = endp;
292 }
293
294 return total;
295}
296
dfddba3d 297/*
298 * Search for next delimiter between hostnames/addresses and ports.
299 * Argument may be modified (for termination).
300 * Returns *cp if parsing succeeds.
301 * *cp is set to the start of the next delimiter, if one was found.
302 * If this is the last field, *cp is set to NULL.
303 */
304char *
305hpdelim(char **cp)
306{
307 char *s, *old;
308
309 if (cp == NULL || *cp == NULL)
310 return NULL;
311
312 old = s = *cp;
313 if (*s == '[') {
314 if ((s = strchr(s, ']')) == NULL)
315 return NULL;
316 else
317 s++;
318 } else if ((s = strpbrk(s, ":/")) == NULL)
319 s = *cp + strlen(*cp); /* skip to end (see first case below) */
320
321 switch (*s) {
322 case '\0':
323 *cp = NULL; /* no more fields*/
324 break;
8b32eddc 325
dfddba3d 326 case ':':
327 case '/':
328 *s = '\0'; /* terminate */
329 *cp = s + 1;
330 break;
8b32eddc 331
dfddba3d 332 default:
333 return NULL;
334 }
335
336 return old;
337}
338
3c0ef626 339char *
340cleanhostname(char *host)
341{
342 if (*host == '[' && host[strlen(host) - 1] == ']') {
343 host[strlen(host) - 1] = '\0';
344 return (host + 1);
345 } else
346 return host;
347}
348
349char *
350colon(char *cp)
351{
352 int flag = 0;
353
354 if (*cp == ':') /* Leading colon is part of file name. */
355 return (0);
356 if (*cp == '[')
357 flag = 1;
358
359 for (; *cp; ++cp) {
360 if (*cp == '@' && *(cp+1) == '[')
361 flag = 1;
362 if (*cp == ']' && *(cp+1) == ':' && flag)
363 return (cp+1);
364 if (*cp == ':' && !flag)
365 return (cp);
366 if (*cp == '/')
367 return (0);
368 }
369 return (0);
370}
371
372/* function to assist building execv() arguments */
373void
374addargs(arglist *args, char *fmt, ...)
375{
376 va_list ap;
377 char buf[1024];
7e82606e 378 u_int nalloc;
3c0ef626 379
380 va_start(ap, fmt);
381 vsnprintf(buf, sizeof(buf), fmt, ap);
382 va_end(ap);
383
29d88157 384 nalloc = args->nalloc;
3c0ef626 385 if (args->list == NULL) {
29d88157 386 nalloc = 32;
3c0ef626 387 args->num = 0;
29d88157 388 } else if (args->num+2 >= nalloc)
389 nalloc *= 2;
3c0ef626 390
29d88157 391 args->list = xrealloc(args->list, nalloc * sizeof(char *));
392 args->nalloc = nalloc;
3c0ef626 393 args->list[args->num++] = xstrdup(buf);
394 args->list[args->num] = NULL;
395}
dfddba3d 396
2ce0bfe4 397/*
398 * Expands tildes in the file name. Returns data allocated by xmalloc.
399 * Warning: this calls getpw*.
400 */
401char *
402tilde_expand_filename(const char *filename, uid_t uid)
403{
404 const char *path;
405 char user[128], ret[MAXPATHLEN];
406 struct passwd *pw;
407 u_int len, slash;
408
409 if (*filename != '~')
410 return (xstrdup(filename));
411 filename++;
412
413 path = strchr(filename, '/');
414 if (path != NULL && path > filename) { /* ~user/path */
415 slash = path - filename;
416 if (slash > sizeof(user) - 1)
417 fatal("tilde_expand_filename: ~username too long");
418 memcpy(user, filename, slash);
419 user[slash] = '\0';
420 if ((pw = getpwnam(user)) == NULL)
421 fatal("tilde_expand_filename: No such user %s", user);
422 } else if ((pw = getpwuid(uid)) == NULL) /* ~/path */
423 fatal("tilde_expand_filename: No such uid %d", uid);
424
425 if (strlcpy(ret, pw->pw_dir, sizeof(ret)) >= sizeof(ret))
426 fatal("tilde_expand_filename: Path too long");
427
428 /* Make sure directory has a trailing '/' */
429 len = strlen(pw->pw_dir);
430 if ((len == 0 || pw->pw_dir[len - 1] != '/') &&
431 strlcat(ret, "/", sizeof(ret)) >= sizeof(ret))
432 fatal("tilde_expand_filename: Path too long");
433
434 /* Skip leading '/' from specified path */
435 if (path != NULL)
436 filename = path + 1;
437 if (strlcat(ret, filename, sizeof(ret)) >= sizeof(ret))
438 fatal("tilde_expand_filename: Path too long");
439
440 return (xstrdup(ret));
441}
442
443/*
444 * Expand a string with a set of %[char] escapes. A number of escapes may be
445 * specified as (char *escape_chars, char *replacement) pairs. The list must
446 * be terminated by a NULL escape_char. Returns replaced string in memory
447 * allocated by xmalloc.
448 */
449char *
450percent_expand(const char *string, ...)
451{
452#define EXPAND_MAX_KEYS 16
453 struct {
454 const char *key;
455 const char *repl;
456 } keys[EXPAND_MAX_KEYS];
457 u_int num_keys, i, j;
458 char buf[4096];
459 va_list ap;
460
461 /* Gather keys */
462 va_start(ap, string);
463 for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) {
464 keys[num_keys].key = va_arg(ap, char *);
465 if (keys[num_keys].key == NULL)
466 break;
467 keys[num_keys].repl = va_arg(ap, char *);
468 if (keys[num_keys].repl == NULL)
469 fatal("percent_expand: NULL replacement");
470 }
471 va_end(ap);
472
473 if (num_keys >= EXPAND_MAX_KEYS)
474 fatal("percent_expand: too many keys");
475
476 /* Expand string */
477 *buf = '\0';
478 for (i = 0; *string != '\0'; string++) {
479 if (*string != '%') {
480 append:
481 buf[i++] = *string;
482 if (i >= sizeof(buf))
483 fatal("percent_expand: string too long");
484 buf[i] = '\0';
485 continue;
486 }
487 string++;
488 if (*string == '%')
489 goto append;
490 for (j = 0; j < num_keys; j++) {
491 if (strchr(keys[j].key, *string) != NULL) {
492 i = strlcat(buf, keys[j].repl, sizeof(buf));
493 if (i >= sizeof(buf))
494 fatal("percent_expand: string too long");
495 break;
496 }
497 }
498 if (j >= num_keys)
499 fatal("percent_expand: unknown key %%%c", *string);
500 }
501 return (xstrdup(buf));
502#undef EXPAND_MAX_KEYS
503}
504
dfddba3d 505/*
506 * Read an entire line from a public key file into a static buffer, discarding
507 * lines that exceed the buffer size. Returns 0 on success, -1 on failure.
508 */
509int
510read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
511 u_long *lineno)
512{
513 while (fgets(buf, bufsz, f) != NULL) {
514 (*lineno)++;
515 if (buf[strlen(buf) - 1] == '\n' || feof(f)) {
516 return 0;
517 } else {
518 debug("%s: %s line %lu exceeds size limit", __func__,
519 filename, *lineno);
520 /* discard remainder of line */
8b32eddc 521 while (fgetc(f) != '\n' && !feof(f))
dfddba3d 522 ; /* nothing */
523 }
524 }
525 return -1;
526}
2ce0bfe4 527
528char *
529tohex(const u_char *d, u_int l)
530{
531 char b[3], *r;
532 u_int i, hl;
533
534 hl = l * 2 + 1;
535 r = xmalloc(hl);
536 *r = '\0';
537 for (i = 0; i < l; i++) {
538 snprintf(b, sizeof(b), "%02x", d[i]);
539 strlcat(r, b, hl);
540 }
541 return (r);
542}
543
This page took 0.362846 seconds and 5 git commands to generate.