version 1.154, 2020/10/03 09:22:26 |
version 1.155, 2020/10/18 11:32:01 |
|
|
size_t len; |
size_t len; |
|
|
if ((buf = sshbuf_new()) == NULL) |
if ((buf = sshbuf_new()) == NULL) |
fatal("%s: sshbuf_new failed", __func__); |
fatal_f("sshbuf_new failed"); |
if (parseerror == NULL) |
if (parseerror == NULL) |
fatal("%s: null parseerror arg", __func__); |
fatal_f("null parseerror arg"); |
*parseerror = 1; |
*parseerror = 1; |
|
|
/* Gather keys if we're doing percent expansion. */ |
/* Gather keys if we're doing percent expansion. */ |
|
|
if (keys[num_keys].key == NULL) |
if (keys[num_keys].key == NULL) |
break; |
break; |
keys[num_keys].repl = va_arg(ap, char *); |
keys[num_keys].repl = va_arg(ap, char *); |
if (keys[num_keys].repl == NULL) |
if (keys[num_keys].repl == NULL) { |
fatal("%s: NULL replacement for token %s", __func__, keys[num_keys].key); |
fatal_f("NULL replacement for token %s", |
|
keys[num_keys].key); |
|
} |
} |
} |
if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) |
if (num_keys == EXPAND_MAX_KEYS && va_arg(ap, char *) != NULL) |
fatal("%s: too many keys", __func__); |
fatal_f("too many keys"); |
if (num_keys == 0) |
if (num_keys == 0) |
fatal("%s: percent expansion without token list", |
fatal_f("percent expansion without token list"); |
__func__); |
|
} |
} |
|
|
/* Expand string */ |
/* Expand string */ |
|
|
if (dollar && string[0] == '$' && string[1] == '{') { |
if (dollar && string[0] == '$' && string[1] == '{') { |
string += 2; /* skip over '${' */ |
string += 2; /* skip over '${' */ |
if ((varend = strchr(string, '}')) == NULL) { |
if ((varend = strchr(string, '}')) == NULL) { |
error("%s: environment variable '%s' missing " |
error_f("environment variable '%s' missing " |
"closing '}'", __func__, string); |
"closing '}'", string); |
goto out; |
goto out; |
} |
} |
len = varend - string; |
len = varend - string; |
if (len == 0) { |
if (len == 0) { |
error("%s: zero-length environment variable", |
error_f("zero-length environment variable"); |
__func__); |
|
goto out; |
goto out; |
} |
} |
var = xmalloc(len + 1); |
var = xmalloc(len + 1); |
(void)strlcpy(var, string, len + 1); |
(void)strlcpy(var, string, len + 1); |
if ((val = getenv(var)) == NULL) { |
if ((val = getenv(var)) == NULL) { |
error("%s: env var ${%s} has no value", |
error_f("env var ${%s} has no value", var); |
__func__, var); |
|
missingvar = 1; |
missingvar = 1; |
} else { |
} else { |
debug3("%s: expand ${%s} -> '%s'", __func__, |
debug3_f("expand ${%s} -> '%s'", var, val); |
var, val); |
|
if ((r = sshbuf_put(buf, val, strlen(val))) !=0) |
if ((r = sshbuf_put(buf, val, strlen(val))) !=0) |
fatal("%s: sshbuf_put: %s", __func__, |
fatal_fr(r, "sshbuf_put ${}"); |
ssh_err(r)); |
|
} |
} |
free(var); |
free(var); |
string += len; |
string += len; |
|
|
*/ |
*/ |
if (*string != '%' || !percent) { |
if (*string != '%' || !percent) { |
append: |
append: |
if ((r = sshbuf_put_u8(buf, *string)) != 0) { |
if ((r = sshbuf_put_u8(buf, *string)) != 0) |
fatal("%s: sshbuf_put_u8: %s", |
fatal_fr(r, "sshbuf_put_u8 %%"); |
__func__, ssh_err(r)); |
|
} |
|
continue; |
continue; |
} |
} |
string++; |
string++; |
|
|
if (*string == '%') |
if (*string == '%') |
goto append; |
goto append; |
if (*string == '\0') { |
if (*string == '\0') { |
error("%s: invalid format", __func__); |
error_f("invalid format"); |
goto out; |
goto out; |
} |
} |
for (i = 0; i < num_keys; i++) { |
for (i = 0; i < num_keys; i++) { |
if (strchr(keys[i].key, *string) != NULL) { |
if (strchr(keys[i].key, *string) != NULL) { |
if ((r = sshbuf_put(buf, keys[i].repl, |
if ((r = sshbuf_put(buf, keys[i].repl, |
strlen(keys[i].repl))) != 0) { |
strlen(keys[i].repl))) != 0) |
fatal("%s: sshbuf_put: %s", |
fatal_fr(r, "sshbuf_put %%-repl"); |
__func__, ssh_err(r)); |
|
} |
|
break; |
break; |
} |
} |
} |
} |
if (i >= num_keys) { |
if (i >= num_keys) { |
error("%s: unknown key %%%c", __func__, *string); |
error_f("unknown key %%%c", *string); |
goto out; |
goto out; |
} |
} |
} |
} |
if (!missingvar && (ret = sshbuf_dup_string(buf)) == NULL) |
if (!missingvar && (ret = sshbuf_dup_string(buf)) == NULL) |
fatal("%s: sshbuf_dup_string failed", __func__); |
fatal_f("sshbuf_dup_string failed"); |
*parseerror = 0; |
*parseerror = 0; |
out: |
out: |
sshbuf_free(buf); |
sshbuf_free(buf); |
|
|
ret = vdollar_percent_expand(&err, 0, 1, string, ap); |
ret = vdollar_percent_expand(&err, 0, 1, string, ap); |
va_end(ap); |
va_end(ap); |
if (err) |
if (err) |
fatal("%s failed", __func__); |
fatal_f("failed"); |
return ret; |
return ret; |
} |
} |
|
|
|
|
ret = vdollar_percent_expand(&err, 1, 1, string, ap); |
ret = vdollar_percent_expand(&err, 1, 1, string, ap); |
va_end(ap); |
va_end(ap); |
if (err) |
if (err) |
fatal("%s failed", __func__); |
fatal_f("failed"); |
return ret; |
return ret; |
} |
} |
|
|
|
|
break; |
break; |
} |
} |
} else { |
} else { |
debug("%s: invalid tunnel %u", __func__, tun); |
debug_f("invalid tunnel %u", tun); |
return -1; |
return -1; |
} |
} |
|
|
if (fd == -1) { |
if (fd == -1) { |
debug("%s: %s open: %s", __func__, name, strerror(errno)); |
debug_f("%s open: %s", name, strerror(errno)); |
return -1; |
return -1; |
} |
} |
|
|
debug("%s: %s mode %d fd %d", __func__, name, mode, fd); |
debug_f("%s mode %d fd %d", name, mode, fd); |
|
|
/* Bring interface up if it is not already */ |
/* Bring interface up if it is not already */ |
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); |
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", tunbase, tun); |
|
|
goto failed; |
goto failed; |
|
|
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) { |
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) { |
debug("%s: get interface %s flags: %s", __func__, |
debug_f("get interface %s flags: %s", ifr.ifr_name, |
ifr.ifr_name, strerror(errno)); |
strerror(errno)); |
goto failed; |
goto failed; |
} |
} |
|
|
if (!(ifr.ifr_flags & IFF_UP)) { |
if (!(ifr.ifr_flags & IFF_UP)) { |
ifr.ifr_flags |= IFF_UP; |
ifr.ifr_flags |= IFF_UP; |
if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) { |
if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) { |
debug("%s: activate interface %s: %s", __func__, |
debug_f("activate interface %s: %s", ifr.ifr_name, |
ifr.ifr_name, strerror(errno)); |
strerror(errno)); |
goto failed; |
goto failed; |
} |
} |
} |
} |
|
|
} |
} |
r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX"); |
r = snprintf(s, len, "/tmp/ssh-XXXXXXXXXXXX"); |
if (r < 0 || (size_t)r >= len) |
if (r < 0 || (size_t)r >= len) |
fatal("%s: template string too short", __func__); |
fatal_f("template string too short"); |
} |
} |
|
|
static const struct { |
static const struct { |
|
|
sunaddr.sun_family = AF_UNIX; |
sunaddr.sun_family = AF_UNIX; |
if (strlcpy(sunaddr.sun_path, path, |
if (strlcpy(sunaddr.sun_path, path, |
sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) { |
sizeof(sunaddr.sun_path)) >= sizeof(sunaddr.sun_path)) { |
error("%s: path \"%s\" too long for Unix domain socket", |
error_f("path \"%s\" too long for Unix domain socket", path); |
__func__, path); |
|
errno = ENAMETOOLONG; |
errno = ENAMETOOLONG; |
return -1; |
return -1; |
} |
} |
|
|
sock = socket(PF_UNIX, SOCK_STREAM, 0); |
sock = socket(PF_UNIX, SOCK_STREAM, 0); |
if (sock == -1) { |
if (sock == -1) { |
saved_errno = errno; |
saved_errno = errno; |
error("%s: socket: %.100s", __func__, strerror(errno)); |
error_f("socket: %.100s", strerror(errno)); |
errno = saved_errno; |
errno = saved_errno; |
return -1; |
return -1; |
} |
} |
|
|
} |
} |
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) { |
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) { |
saved_errno = errno; |
saved_errno = errno; |
error("%s: cannot bind to path %s: %s", |
error_f("cannot bind to path %s: %s", path, strerror(errno)); |
__func__, path, strerror(errno)); |
|
close(sock); |
close(sock); |
errno = saved_errno; |
errno = saved_errno; |
return -1; |
return -1; |
} |
} |
if (listen(sock, backlog) == -1) { |
if (listen(sock, backlog) == -1) { |
saved_errno = errno; |
saved_errno = errno; |
error("%s: cannot listen on path %s: %s", |
error_f("cannot listen on path %s: %s", path, strerror(errno)); |
__func__, path, strerror(errno)); |
|
close(sock); |
close(sock); |
unlink(path); |
unlink(path); |
errno = saved_errno; |
errno = saved_errno; |
|
|
struct sshbuf *buf, *arg; |
struct sshbuf *buf, *arg; |
|
|
if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL) |
if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL) |
fatal("%s: sshbuf_new failed", __func__); |
fatal_f("sshbuf_new failed"); |
|
|
for (i = 0; i < argc; i++) { |
for (i = 0; i < argc; i++) { |
ws = 0; |
ws = 0; |
|
|
break; |
break; |
} |
} |
if (r != 0) |
if (r != 0) |
fatal("%s: sshbuf_put_u8: %s", |
fatal_fr(r, "sshbuf_put_u8"); |
__func__, ssh_err(r)); |
|
} |
} |
if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) || |
if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) || |
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) || |
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) || |
(r = sshbuf_putb(buf, arg)) != 0 || |
(r = sshbuf_putb(buf, arg)) != 0 || |
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0)) |
(ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0)) |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
fatal_fr(r, "assemble"); |
} |
} |
if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL) |
if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL) |
fatal("%s: malloc failed", __func__); |
fatal_f("malloc failed"); |
memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf)); |
memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf)); |
ret[sshbuf_len(buf)] = '\0'; |
ret[sshbuf_len(buf)] = '\0'; |
sshbuf_free(buf); |
sshbuf_free(buf); |
|
|
|
|
while (waitpid(pid, &status, 0) == -1) { |
while (waitpid(pid, &status, 0) == -1) { |
if (errno != EINTR) { |
if (errno != EINTR) { |
error("%s: waitpid: %s", tag, strerror(errno)); |
error("%s waitpid: %s", tag, strerror(errno)); |
return -1; |
return -1; |
} |
} |
} |
} |
|
|
int devnull, ret = 0; |
int devnull, ret = 0; |
|
|
if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { |
if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { |
error("%s: open %s: %s", __func__, _PATH_DEVNULL, |
error_f("open %s: %s", _PATH_DEVNULL, |
strerror(errno)); |
strerror(errno)); |
return -1; |
return -1; |
} |
} |
if ((do_stdin && dup2(devnull, STDIN_FILENO) == -1) || |
if ((do_stdin && dup2(devnull, STDIN_FILENO) == -1) || |
(do_stdout && dup2(devnull, STDOUT_FILENO) == -1) || |
(do_stdout && dup2(devnull, STDOUT_FILENO) == -1) || |
(do_stderr && dup2(devnull, STDERR_FILENO) == -1)) { |
(do_stderr && dup2(devnull, STDERR_FILENO) == -1)) { |
error("%s: dup2: %s", __func__, strerror(errno)); |
error_f("dup2: %s", strerror(errno)); |
ret = -1; |
ret = -1; |
} |
} |
if (devnull > STDERR_FILENO) |
if (devnull > STDERR_FILENO) |