version 1.29.2.2, 2006/02/03 02:53:44 |
version 1.30, 2005/04/09 04:32:54 |
|
|
/* |
/* |
* Copyright (c) 2000 Markus Friedl. All rights reserved. |
* Copyright (c) 2000 Markus Friedl. All rights reserved. |
* Copyright (c) 2005 Damien Miller. All rights reserved. |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
|
|
#include "includes.h" |
#include "includes.h" |
RCSID("$OpenBSD$"); |
RCSID("$OpenBSD$"); |
|
|
#include <net/if.h> |
|
|
|
#include "misc.h" |
#include "misc.h" |
#include "log.h" |
#include "log.h" |
#include "xmalloc.h" |
#include "xmalloc.h" |
|
|
return port; |
return port; |
} |
} |
|
|
int |
|
a2tun(const char *s, int *remote) |
|
{ |
|
const char *errstr = NULL; |
|
char *sp, *ep; |
|
int tun; |
|
|
|
if (remote != NULL) { |
|
*remote = SSH_TUNID_ANY; |
|
sp = xstrdup(s); |
|
if ((ep = strchr(sp, ':')) == NULL) { |
|
xfree(sp); |
|
return (a2tun(s, NULL)); |
|
} |
|
ep[0] = '\0'; ep++; |
|
*remote = a2tun(ep, NULL); |
|
tun = a2tun(sp, NULL); |
|
xfree(sp); |
|
return (*remote == SSH_TUNID_ERR ? *remote : tun); |
|
} |
|
|
|
if (strcasecmp(s, "any") == 0) |
|
return (SSH_TUNID_ANY); |
|
|
|
tun = strtonum(s, 0, SSH_TUNID_MAX, &errstr); |
|
if (errstr != NULL) |
|
return (SSH_TUNID_ERR); |
|
|
|
return (tun); |
|
} |
|
|
|
#define SECONDS 1 |
#define SECONDS 1 |
#define MINUTES (SECONDS * 60) |
#define MINUTES (SECONDS * 60) |
#define HOURS (MINUTES * 60) |
#define HOURS (MINUTES * 60) |
|
|
addargs(arglist *args, char *fmt, ...) |
addargs(arglist *args, char *fmt, ...) |
{ |
{ |
va_list ap; |
va_list ap; |
char *cp; |
char buf[1024]; |
u_int nalloc; |
u_int nalloc; |
int r; |
|
|
|
va_start(ap, fmt); |
va_start(ap, fmt); |
r = vasprintf(&cp, fmt, ap); |
vsnprintf(buf, sizeof(buf), fmt, ap); |
va_end(ap); |
va_end(ap); |
if (r == -1) |
|
fatal("addargs: argument too long"); |
|
|
|
nalloc = args->nalloc; |
nalloc = args->nalloc; |
if (args->list == NULL) { |
if (args->list == NULL) { |
|
|
|
|
args->list = xrealloc(args->list, nalloc * sizeof(char *)); |
args->list = xrealloc(args->list, nalloc * sizeof(char *)); |
args->nalloc = nalloc; |
args->nalloc = nalloc; |
args->list[args->num++] = cp; |
args->list[args->num++] = xstrdup(buf); |
args->list[args->num] = NULL; |
args->list[args->num] = NULL; |
} |
} |
|
|
void |
|
replacearg(arglist *args, u_int which, char *fmt, ...) |
|
{ |
|
va_list ap; |
|
char *cp; |
|
int r; |
|
|
|
va_start(ap, fmt); |
|
r = vasprintf(&cp, fmt, ap); |
|
va_end(ap); |
|
if (r == -1) |
|
fatal("replacearg: argument too long"); |
|
|
|
if (which >= args->num) |
|
fatal("replacearg: tried to replace invalid arg %d >= %d", |
|
which, args->num); |
|
xfree(args->list[which]); |
|
args->list[which] = cp; |
|
} |
|
|
|
void |
|
freeargs(arglist *args) |
|
{ |
|
u_int i; |
|
|
|
if (args->list != NULL) { |
|
for (i = 0; i < args->num; i++) |
|
xfree(args->list[i]); |
|
xfree(args->list); |
|
args->nalloc = args->num = 0; |
|
args->list = NULL; |
|
} |
|
} |
|
|
|
/* |
/* |
* Expands tildes in the file name. Returns data allocated by xmalloc. |
* Expands tildes in the file name. Returns data allocated by xmalloc. |
* Warning: this calls getpw*. |
* Warning: this calls getpw*. |
|
|
const char *path; |
const char *path; |
char user[128], ret[MAXPATHLEN]; |
char user[128], ret[MAXPATHLEN]; |
struct passwd *pw; |
struct passwd *pw; |
u_int len, slash; |
int len; |
|
|
if (*filename != '~') |
if (*filename != '~') |
return (xstrdup(filename)); |
return (xstrdup(filename)); |
|
|
|
|
path = strchr(filename, '/'); |
path = strchr(filename, '/'); |
if (path != NULL && path > filename) { /* ~user/path */ |
if (path != NULL && path > filename) { /* ~user/path */ |
slash = path - filename; |
if (path - filename > sizeof(user) - 1) |
if (slash > sizeof(user) - 1) |
|
fatal("tilde_expand_filename: ~username too long"); |
fatal("tilde_expand_filename: ~username too long"); |
memcpy(user, filename, slash); |
memcpy(user, filename, path - filename); |
user[slash] = '\0'; |
user[path - filename] = '\0'; |
if ((pw = getpwnam(user)) == NULL) |
if ((pw = getpwnam(user)) == NULL) |
fatal("tilde_expand_filename: No such user %s", user); |
fatal("tilde_expand_filename: No such user %s", user); |
} else if ((pw = getpwuid(uid)) == NULL) /* ~/path */ |
} else if ((pw = getpwuid(uid)) == NULL) /* ~/path */ |
|
|
} |
} |
|
|
/* |
/* |
* Expand a string with a set of %[char] escapes. A number of escapes may be |
|
* specified as (char *escape_chars, char *replacement) pairs. The list must |
|
* be terminated by a NULL escape_char. Returns replaced string in memory |
|
* allocated by xmalloc. |
|
*/ |
|
char * |
|
percent_expand(const char *string, ...) |
|
{ |
|
#define EXPAND_MAX_KEYS 16 |
|
struct { |
|
const char *key; |
|
const char *repl; |
|
} keys[EXPAND_MAX_KEYS]; |
|
u_int num_keys, i, j; |
|
char buf[4096]; |
|
va_list ap; |
|
|
|
/* Gather keys */ |
|
va_start(ap, string); |
|
for (num_keys = 0; num_keys < EXPAND_MAX_KEYS; num_keys++) { |
|
keys[num_keys].key = va_arg(ap, char *); |
|
if (keys[num_keys].key == NULL) |
|
break; |
|
keys[num_keys].repl = va_arg(ap, char *); |
|
if (keys[num_keys].repl == NULL) |
|
fatal("percent_expand: NULL replacement"); |
|
} |
|
va_end(ap); |
|
|
|
if (num_keys >= EXPAND_MAX_KEYS) |
|
fatal("percent_expand: too many keys"); |
|
|
|
/* Expand string */ |
|
*buf = '\0'; |
|
for (i = 0; *string != '\0'; string++) { |
|
if (*string != '%') { |
|
append: |
|
buf[i++] = *string; |
|
if (i >= sizeof(buf)) |
|
fatal("percent_expand: string too long"); |
|
buf[i] = '\0'; |
|
continue; |
|
} |
|
string++; |
|
if (*string == '%') |
|
goto append; |
|
for (j = 0; j < num_keys; j++) { |
|
if (strchr(keys[j].key, *string) != NULL) { |
|
i = strlcat(buf, keys[j].repl, sizeof(buf)); |
|
if (i >= sizeof(buf)) |
|
fatal("percent_expand: string too long"); |
|
break; |
|
} |
|
} |
|
if (j >= num_keys) |
|
fatal("percent_expand: unknown key %%%c", *string); |
|
} |
|
return (xstrdup(buf)); |
|
#undef EXPAND_MAX_KEYS |
|
} |
|
|
|
/* |
|
* Read an entire line from a public key file into a static buffer, discarding |
* Read an entire line from a public key file into a static buffer, discarding |
* lines that exceed the buffer size. Returns 0 on success, -1 on failure. |
* lines that exceed the buffer size. Returns 0 on success, -1 on failure. |
*/ |
*/ |
|
|
} |
} |
return -1; |
return -1; |
} |
} |
|
|
int |
|
tun_open(int tun, int mode) |
|
{ |
|
struct ifreq ifr; |
|
char name[100]; |
|
int fd = -1, sock; |
|
|
|
/* Open the tunnel device */ |
|
if (tun <= SSH_TUNID_MAX) { |
|
snprintf(name, sizeof(name), "/dev/tun%d", tun); |
|
fd = open(name, O_RDWR); |
|
} else if (tun == SSH_TUNID_ANY) { |
|
for (tun = 100; tun >= 0; tun--) { |
|
snprintf(name, sizeof(name), "/dev/tun%d", tun); |
|
if ((fd = open(name, O_RDWR)) >= 0) |
|
break; |
|
} |
|
} else { |
|
debug("%s: invalid tunnel %u", __func__, tun); |
|
return (-1); |
|
} |
|
|
|
if (fd < 0) { |
|
debug("%s: %s open failed: %s", __func__, name, strerror(errno)); |
|
return (-1); |
|
} |
|
|
|
debug("%s: %s mode %d fd %d", __func__, name, mode, fd); |
|
|
|
/* Set the tunnel device operation mode */ |
|
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tun%d", tun); |
|
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) |
|
goto failed; |
|
|
|
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) |
|
goto failed; |
|
|
|
/* Set interface mode */ |
|
ifr.ifr_flags &= ~IFF_UP; |
|
if (mode == SSH_TUNMODE_ETHERNET) |
|
ifr.ifr_flags |= IFF_LINK0; |
|
else |
|
ifr.ifr_flags &= ~IFF_LINK0; |
|
if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) |
|
goto failed; |
|
|
|
/* Bring interface up */ |
|
ifr.ifr_flags |= IFF_UP; |
|
if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) |
|
goto failed; |
|
|
|
close(sock); |
|
return (fd); |
|
|
|
failed: |
|
if (fd >= 0) |
|
close(fd); |
|
if (sock >= 0) |
|
close(sock); |
|
debug("%s: failed to set %s mode %d: %s", __func__, name, |
|
mode, strerror(errno)); |
|
return (-1); |
|
} |
|
|
|
void |
|
sanitise_stdfd(void) |
|
{ |
|
int nullfd, dupfd; |
|
|
|
if ((nullfd = dupfd = open(_PATH_DEVNULL, O_RDWR)) == -1) { |
|
fprintf(stderr, "Couldn't open /dev/null: %s", strerror(errno)); |
|
exit(1); |
|
} |
|
while (++dupfd <= 2) { |
|
/* Only clobber closed fds */ |
|
if (fcntl(dupfd, F_GETFL, 0) >= 0) |
|
continue; |
|
if (dup2(nullfd, dupfd) == -1) { |
|
fprintf(stderr, "dup2: %s", strerror(errno)); |
|
exit(1); |
|
} |
|
} |
|
if (nullfd > 2) |
|
close(nullfd); |
|
} |
|
|
|
char * |
|
tohex(const u_char *d, u_int l) |
|
{ |
|
char b[3], *r; |
|
u_int i, hl; |
|
|
|
hl = l * 2 + 1; |
|
r = xmalloc(hl); |
|
*r = '\0'; |
|
for (i = 0; i < l; i++) { |
|
snprintf(b, sizeof(b), "%02x", d[i]); |
|
strlcat(r, b, hl); |
|
} |
|
return (r); |
|
} |
|
|
|