version 1.543, 2020/12/17 23:10:27 |
version 1.544, 2020/12/17 23:26:11 |
|
|
*/ |
*/ |
char *forward_agent_sock_path = NULL; |
char *forward_agent_sock_path = NULL; |
|
|
/* Various strings used to to percent_expand() arguments */ |
|
static char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; |
|
static char uidstr[32], *host_arg, *conn_hash_hex; |
|
static const char *keyalias; |
|
|
|
/* socket address the host resolves to */ |
/* socket address the host resolves to */ |
struct sockaddr_storage hostaddr; |
struct sockaddr_storage hostaddr; |
|
|
|
|
exit(255); |
exit(255); |
} |
} |
|
|
static int ssh_session2(struct ssh *, struct passwd *); |
static int ssh_session2(struct ssh *, const struct ssh_conn_info *); |
static void load_public_identity_files(struct passwd *); |
static void load_public_identity_files(const struct ssh_conn_info *); |
static void main_sigchld_handler(int); |
static void main_sigchld_handler(int); |
|
|
/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ |
/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ |
|
|
} |
} |
|
|
#define DEFAULT_CLIENT_PERCENT_EXPAND_ARGS \ |
#define DEFAULT_CLIENT_PERCENT_EXPAND_ARGS \ |
"C", conn_hash_hex, \ |
"C", cinfo->conn_hash_hex, \ |
"L", shorthost, \ |
"L", cinfo->shorthost, \ |
"i", uidstr, \ |
"i", cinfo->uidstr, \ |
"k", keyalias, \ |
"k", cinfo->keyalias, \ |
"l", thishost, \ |
"l", cinfo->thishost, \ |
"n", host_arg, \ |
"n", cinfo->host_arg, \ |
"p", portstr |
"p", cinfo->portstr |
|
|
/* |
/* |
* Expands the set of percent_expand options used by the majority of keywords |
* Expands the set of percent_expand options used by the majority of keywords |
|
|
* Caller must free returned string. |
* Caller must free returned string. |
*/ |
*/ |
static char * |
static char * |
default_client_percent_expand(const char *str, const char *homedir, |
default_client_percent_expand(const char *str, |
const char *remhost, const char *remuser, const char *locuser) |
const struct ssh_conn_info *cinfo) |
{ |
{ |
return percent_expand(str, |
return percent_expand(str, |
/* values from statics above */ |
/* values from statics above */ |
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, |
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, |
/* values from arguments */ |
/* values from arguments */ |
"d", homedir, |
"d", cinfo->homedir, |
"h", remhost, |
"h", cinfo->remhost, |
"r", remuser, |
"r", cinfo->remuser, |
"u", locuser, |
"u", cinfo->locuser, |
(char *)NULL); |
(char *)NULL); |
} |
} |
|
|
|
|
* Caller must free returned string. |
* Caller must free returned string. |
*/ |
*/ |
static char * |
static char * |
default_client_percent_dollar_expand(const char *str, const char *homedir, |
default_client_percent_dollar_expand(const char *str, |
const char *remhost, const char *remuser, const char *locuser) |
const struct ssh_conn_info *cinfo) |
{ |
{ |
char *ret; |
char *ret; |
|
|
|
|
/* values from statics above */ |
/* values from statics above */ |
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, |
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, |
/* values from arguments */ |
/* values from arguments */ |
"d", homedir, |
"d", cinfo->homedir, |
"h", remhost, |
"h", cinfo->remhost, |
"r", remuser, |
"r", cinfo->remuser, |
"u", locuser, |
"u", cinfo->locuser, |
(char *)NULL); |
(char *)NULL); |
if (ret == NULL) |
if (ret == NULL) |
fatal("invalid environment variable expansion"); |
fatal("invalid environment variable expansion"); |
|
|
} |
} |
} |
} |
|
|
|
static void |
|
ssh_conn_info_free(struct ssh_conn_info *cinfo) |
|
{ |
|
if (cinfo == NULL) |
|
return; |
|
free(cinfo->conn_hash_hex); |
|
free(cinfo->shorthost); |
|
free(cinfo->uidstr); |
|
free(cinfo->keyalias); |
|
free(cinfo->thishost); |
|
free(cinfo->host_arg); |
|
free(cinfo->portstr); |
|
free(cinfo->remhost); |
|
free(cinfo->remuser); |
|
free(cinfo->homedir); |
|
free(cinfo->locuser); |
|
free(cinfo); |
|
} |
|
|
/* |
/* |
* Main program for the ssh client. |
* Main program for the ssh client. |
*/ |
*/ |
|
|
struct ssh *ssh = NULL; |
struct ssh *ssh = NULL; |
int i, r, opt, exit_status, use_syslog, direct, timeout_ms; |
int i, r, opt, exit_status, use_syslog, direct, timeout_ms; |
int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0; |
int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0; |
char *p, *cp, *line, *argv0, *logfile; |
char *p, *cp, *line, *argv0, *logfile, *host_arg; |
char cname[NI_MAXHOST]; |
char cname[NI_MAXHOST], thishost[NI_MAXHOST]; |
struct stat st; |
struct stat st; |
struct passwd *pw; |
struct passwd *pw; |
extern int optind, optreset; |
extern int optind, optreset; |
|
|
struct addrinfo *addrs = NULL; |
struct addrinfo *addrs = NULL; |
size_t n, len; |
size_t n, len; |
u_int j; |
u_int j; |
|
struct ssh_conn_info *cinfo = NULL; |
|
|
|
|
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ |
sanitise_stdfd(); |
sanitise_stdfd(); |
|
|
|
|
} |
} |
|
|
/* Set up strings used to percent_expand() arguments */ |
/* Set up strings used to percent_expand() arguments */ |
|
cinfo = xcalloc(1, sizeof(*cinfo)); |
if (gethostname(thishost, sizeof(thishost)) == -1) |
if (gethostname(thishost, sizeof(thishost)) == -1) |
fatal("gethostname: %s", strerror(errno)); |
fatal("gethostname: %s", strerror(errno)); |
strlcpy(shorthost, thishost, sizeof(shorthost)); |
cinfo->thishost = xstrdup(thishost); |
shorthost[strcspn(thishost, ".")] = '\0'; |
thishost[strcspn(thishost, ".")] = '\0'; |
snprintf(portstr, sizeof(portstr), "%d", options.port); |
cinfo->shorthost = xstrdup(thishost); |
snprintf(uidstr, sizeof(uidstr), "%llu", |
xasprintf(&cinfo->portstr, "%d", options.port); |
|
xasprintf(&cinfo->uidstr, "%llu", |
(unsigned long long)pw->pw_uid); |
(unsigned long long)pw->pw_uid); |
keyalias = options.host_key_alias ? options.host_key_alias : host_arg; |
cinfo->keyalias = xstrdup(options.host_key_alias ? |
|
options.host_key_alias : host_arg); |
|
cinfo->conn_hash_hex = ssh_connection_hash(cinfo->thishost, host, |
|
cinfo->portstr, options.user); |
|
cinfo->host_arg = xstrdup(host_arg); |
|
cinfo->remhost = xstrdup(host); |
|
cinfo->remuser = xstrdup(options.user); |
|
cinfo->homedir = xstrdup(pw->pw_dir); |
|
cinfo->locuser = xstrdup(pw->pw_name); |
|
|
conn_hash_hex = ssh_connection_hash(thishost, host, portstr, |
|
options.user); |
|
|
|
/* |
/* |
* Expand tokens in arguments. NB. LocalCommand is expanded later, |
* Expand tokens in arguments. NB. LocalCommand is expanded later, |
* after port-forwarding is set up, so it may pick up any local |
* after port-forwarding is set up, so it may pick up any local |
|
|
debug3("expanding RemoteCommand: %s", options.remote_command); |
debug3("expanding RemoteCommand: %s", options.remote_command); |
cp = options.remote_command; |
cp = options.remote_command; |
options.remote_command = default_client_percent_expand(cp, |
options.remote_command = default_client_percent_expand(cp, |
pw->pw_dir, host, options.user, pw->pw_name); |
cinfo); |
debug3("expanded RemoteCommand: %s", options.remote_command); |
debug3("expanded RemoteCommand: %s", options.remote_command); |
free(cp); |
free(cp); |
if ((r = sshbuf_put(command, options.remote_command, |
if ((r = sshbuf_put(command, options.remote_command, |
|
|
cp = tilde_expand_filename(options.control_path, getuid()); |
cp = tilde_expand_filename(options.control_path, getuid()); |
free(options.control_path); |
free(options.control_path); |
options.control_path = default_client_percent_dollar_expand(cp, |
options.control_path = default_client_percent_dollar_expand(cp, |
pw->pw_dir, host, options.user, pw->pw_name); |
cinfo); |
free(cp); |
free(cp); |
} |
} |
|
|
if (options.identity_agent != NULL) { |
if (options.identity_agent != NULL) { |
p = tilde_expand_filename(options.identity_agent, getuid()); |
p = tilde_expand_filename(options.identity_agent, getuid()); |
cp = default_client_percent_dollar_expand(p, |
cp = default_client_percent_dollar_expand(p, cinfo); |
pw->pw_dir, host, options.user, pw->pw_name); |
|
free(p); |
free(p); |
free(options.identity_agent); |
free(options.identity_agent); |
options.identity_agent = cp; |
options.identity_agent = cp; |
|
|
if (options.forward_agent_sock_path != NULL) { |
if (options.forward_agent_sock_path != NULL) { |
p = tilde_expand_filename(options.forward_agent_sock_path, |
p = tilde_expand_filename(options.forward_agent_sock_path, |
getuid()); |
getuid()); |
cp = default_client_percent_dollar_expand(p, |
cp = default_client_percent_dollar_expand(p, cinfo); |
pw->pw_dir, host, options.user, pw->pw_name); |
|
free(p); |
free(p); |
free(options.forward_agent_sock_path); |
free(options.forward_agent_sock_path); |
options.forward_agent_sock_path = cp; |
options.forward_agent_sock_path = cp; |
|
|
if (options.user_hostfiles[j] != NULL) { |
if (options.user_hostfiles[j] != NULL) { |
cp = tilde_expand_filename(options.user_hostfiles[j], |
cp = tilde_expand_filename(options.user_hostfiles[j], |
getuid()); |
getuid()); |
p = default_client_percent_dollar_expand(cp, |
p = default_client_percent_dollar_expand(cp, cinfo); |
pw->pw_dir, host, options.user, pw->pw_name); |
|
if (strcmp(options.user_hostfiles[j], p) != 0) |
if (strcmp(options.user_hostfiles[j], p) != 0) |
debug3("expanded UserKnownHostsFile '%s' -> " |
debug3("expanded UserKnownHostsFile '%s' -> " |
"'%s'", options.user_hostfiles[j], p); |
"'%s'", options.user_hostfiles[j], p); |
|
|
if (options.local_forwards[i].listen_path != NULL) { |
if (options.local_forwards[i].listen_path != NULL) { |
cp = options.local_forwards[i].listen_path; |
cp = options.local_forwards[i].listen_path; |
p = options.local_forwards[i].listen_path = |
p = options.local_forwards[i].listen_path = |
default_client_percent_expand(cp, |
default_client_percent_expand(cp, cinfo); |
pw->pw_dir, host, options.user, pw->pw_name); |
|
if (strcmp(cp, p) != 0) |
if (strcmp(cp, p) != 0) |
debug3("expanded LocalForward listen path " |
debug3("expanded LocalForward listen path " |
"'%s' -> '%s'", cp, p); |
"'%s' -> '%s'", cp, p); |
|
|
if (options.local_forwards[i].connect_path != NULL) { |
if (options.local_forwards[i].connect_path != NULL) { |
cp = options.local_forwards[i].connect_path; |
cp = options.local_forwards[i].connect_path; |
p = options.local_forwards[i].connect_path = |
p = options.local_forwards[i].connect_path = |
default_client_percent_expand(cp, |
default_client_percent_expand(cp, cinfo); |
pw->pw_dir, host, options.user, pw->pw_name); |
|
if (strcmp(cp, p) != 0) |
if (strcmp(cp, p) != 0) |
debug3("expanded LocalForward connect path " |
debug3("expanded LocalForward connect path " |
"'%s' -> '%s'", cp, p); |
"'%s' -> '%s'", cp, p); |
|
|
if (options.remote_forwards[i].listen_path != NULL) { |
if (options.remote_forwards[i].listen_path != NULL) { |
cp = options.remote_forwards[i].listen_path; |
cp = options.remote_forwards[i].listen_path; |
p = options.remote_forwards[i].listen_path = |
p = options.remote_forwards[i].listen_path = |
default_client_percent_expand(cp, |
default_client_percent_expand(cp, cinfo); |
pw->pw_dir, host, options.user, pw->pw_name); |
|
if (strcmp(cp, p) != 0) |
if (strcmp(cp, p) != 0) |
debug3("expanded RemoteForward listen path " |
debug3("expanded RemoteForward listen path " |
"'%s' -> '%s'", cp, p); |
"'%s' -> '%s'", cp, p); |
|
|
if (options.remote_forwards[i].connect_path != NULL) { |
if (options.remote_forwards[i].connect_path != NULL) { |
cp = options.remote_forwards[i].connect_path; |
cp = options.remote_forwards[i].connect_path; |
p = options.remote_forwards[i].connect_path = |
p = options.remote_forwards[i].connect_path = |
default_client_percent_expand(cp, |
default_client_percent_expand(cp, cinfo); |
pw->pw_dir, host, options.user, pw->pw_name); |
|
if (strcmp(cp, p) != 0) |
if (strcmp(cp, p) != 0) |
debug3("expanded RemoteForward connect path " |
debug3("expanded RemoteForward connect path " |
"'%s' -> '%s'", cp, p); |
"'%s' -> '%s'", cp, p); |
|
|
} |
} |
|
|
/* load options.identity_files */ |
/* load options.identity_files */ |
load_public_identity_files(pw); |
load_public_identity_files(cinfo); |
|
|
/* optionally set the SSH_AUTHSOCKET_ENV_NAME variable */ |
/* optionally set the SSH_AUTHSOCKET_ENV_NAME variable */ |
if (options.identity_agent && |
if (options.identity_agent && |
|
|
} |
} |
|
|
skip_connect: |
skip_connect: |
exit_status = ssh_session2(ssh, pw); |
exit_status = ssh_session2(ssh, cinfo); |
|
ssh_conn_info_free(cinfo); |
ssh_packet_close(ssh); |
ssh_packet_close(ssh); |
|
|
if (options.control_path != NULL && muxserver_sock != -1) |
if (options.control_path != NULL && muxserver_sock != -1) |
|
|
} |
} |
|
|
static int |
static int |
ssh_session2(struct ssh *ssh, struct passwd *pw) |
ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo) |
{ |
{ |
int r, id = -1; |
int r, id = -1; |
char *cp, *tun_fwd_ifname = NULL; |
char *cp, *tun_fwd_ifname = NULL; |
|
|
cp = options.local_command; |
cp = options.local_command; |
options.local_command = percent_expand(cp, |
options.local_command = percent_expand(cp, |
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, |
DEFAULT_CLIENT_PERCENT_EXPAND_ARGS, |
"d", pw->pw_dir, |
"d", cinfo->homedir, |
"h", host, |
"h", cinfo->remhost, |
"r", options.user, |
"r", cinfo->remuser, |
"u", pw->pw_name, |
"u", cinfo->locuser, |
"T", tun_fwd_ifname == NULL ? "NONE" : tun_fwd_ifname, |
"T", tun_fwd_ifname == NULL ? "NONE" : tun_fwd_ifname, |
(char *)NULL); |
(char *)NULL); |
debug3("expanded LocalCommand: %s", options.local_command); |
debug3("expanded LocalCommand: %s", options.local_command); |
|
|
|
|
/* Loads all IdentityFile and CertificateFile keys */ |
/* Loads all IdentityFile and CertificateFile keys */ |
static void |
static void |
load_public_identity_files(struct passwd *pw) |
load_public_identity_files(const struct ssh_conn_info *cinfo) |
{ |
{ |
char *filename, *cp; |
char *filename, *cp; |
struct sshkey *public; |
struct sshkey *public; |
|
|
continue; |
continue; |
} |
} |
cp = tilde_expand_filename(options.identity_files[i], getuid()); |
cp = tilde_expand_filename(options.identity_files[i], getuid()); |
filename = default_client_percent_dollar_expand(cp, |
filename = default_client_percent_dollar_expand(cp, cinfo); |
pw->pw_dir, host, options.user, pw->pw_name); |
|
free(cp); |
free(cp); |
check_load(sshkey_load_public(filename, &public, NULL), |
check_load(sshkey_load_public(filename, &public, NULL), |
filename, "pubkey"); |
filename, "pubkey"); |
|
|
for (i = 0; i < options.num_certificate_files; i++) { |
for (i = 0; i < options.num_certificate_files; i++) { |
cp = tilde_expand_filename(options.certificate_files[i], |
cp = tilde_expand_filename(options.certificate_files[i], |
getuid()); |
getuid()); |
filename = default_client_percent_dollar_expand(cp, |
filename = default_client_percent_dollar_expand(cp, cinfo); |
pw->pw_dir, host, options.user, pw->pw_name); |
|
free(cp); |
free(cp); |
|
|
check_load(sshkey_load_public(filename, &public, NULL), |
check_load(sshkey_load_public(filename, &public, NULL), |