=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh.c,v retrieving revision 1.465 retrieving revision 1.466 diff -u -r1.465 -r1.466 --- src/usr.bin/ssh/ssh.c 2017/10/21 23:06:24 1.465 +++ src/usr.bin/ssh/ssh.c 2017/10/23 05:08:00 1.466 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.465 2017/10/21 23:06:24 millert Exp $ */ +/* $OpenBSD: ssh.c,v 1.466 2017/10/23 05:08:00 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -152,6 +152,10 @@ */ char *host; +/* 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; + /* socket address the host resolves to */ struct sockaddr_storage hostaddr; @@ -192,8 +196,8 @@ exit(255); } -static int ssh_session2(struct ssh *); -static void load_public_identity_files(void); +static int ssh_session2(struct ssh *, struct passwd *); +static void load_public_identity_files(struct passwd *); static void main_sigchld_handler(int); /* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */ @@ -440,14 +444,14 @@ * file if the user specifies a config file on the command line. */ static void -process_config_files(const char *host_arg, struct passwd *pw, int post_canon) +process_config_files(const char *host_name, struct passwd *pw, int post_canon) { char buf[PATH_MAX]; int r; if (config != NULL) { if (strcasecmp(config, "none") != 0 && - !read_config_file(config, pw, host, host_arg, &options, + !read_config_file(config, pw, host, host_name, &options, SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0))) fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); @@ -455,13 +459,13 @@ r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); if (r > 0 && (size_t)r < sizeof(buf)) - (void)read_config_file(buf, pw, host, host_arg, + (void)read_config_file(buf, pw, host, host_name, &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | (post_canon ? SSHCONF_POSTCANON : 0)); /* Read systemwide configuration file after user config. */ (void)read_config_file(_PATH_HOST_CONFIG_FILE, pw, - host, host_arg, &options, + host, host_name, &options, post_canon ? SSHCONF_POSTCANON : 0); } } @@ -495,9 +499,8 @@ struct ssh *ssh = NULL; int i, r, opt, exit_status, use_syslog, direct, timeout_ms; int config_test = 0, opt_terminated = 0; - char *p, *cp, *line, *argv0, buf[PATH_MAX], *host_arg, *logfile; - char thishost[NI_MAXHOST], shorthost[NI_MAXHOST], portstr[NI_MAXSERV]; - char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex; + char *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile; + char cname[NI_MAXHOST]; struct stat st; struct passwd *pw; extern int optind, optreset; @@ -1169,6 +1172,7 @@ if (options.user == NULL) options.user = xstrdup(pw->pw_name); + /* Set up strings used to percent_expand() arguments */ if (gethostname(thishost, sizeof(thishost)) == -1) fatal("gethostname: %s", strerror(errno)); strlcpy(shorthost, thishost, sizeof(shorthost)); @@ -1186,24 +1190,11 @@ ssh_digest_free(md); conn_hash_hex = tohex(conn_hash, ssh_digest_bytes(SSH_DIGEST_SHA1)); - if (options.local_command != NULL) { - debug3("expanding LocalCommand: %s", options.local_command); - cp = options.local_command; - options.local_command = percent_expand(cp, - "C", conn_hash_hex, - "L", shorthost, - "d", pw->pw_dir, - "h", host, - "l", thishost, - "n", host_arg, - "p", portstr, - "r", options.user, - "u", pw->pw_name, - (char *)NULL); - debug3("expanded LocalCommand: %s", options.local_command); - free(cp); - } - + /* + * Expand tokens in arguments. NB. LocalCommand is expanded later, + * after port-forwarding is set up, so it may pick up any local + * tunnel interface name allocated. + */ if (options.remote_command != NULL) { debug3("expanding RemoteCommand: %s", options.remote_command); cp = options.remote_command; @@ -1222,7 +1213,6 @@ free(cp); buffer_append(&command, options.remote_command, strlen(options.remote_command)); - } if (options.control_path != NULL) { @@ -1377,7 +1367,7 @@ } /* load options.identity_files */ - load_public_identity_files(); + load_public_identity_files(pw); /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */ if (options.identity_agent && @@ -1441,7 +1431,7 @@ } skip_connect: - exit_status = ssh_session2(ssh); + exit_status = ssh_session2(ssh, pw); packet_close(); if (options.control_path != NULL && muxserver_sock != -1) @@ -1600,7 +1590,7 @@ } static void -ssh_init_forwarding(struct ssh *ssh) +ssh_init_forwarding(struct ssh *ssh, char **ifname) { int success = 0; int i; @@ -1658,8 +1648,9 @@ /* Initiate tunnel forwarding. */ if (options.tun_open != SSH_TUNMODE_NO) { - if (client_request_tun_fwd(ssh, options.tun_open, - options.tun_local, options.tun_remote) == -1) { + if ((*ifname = client_request_tun_fwd(ssh, + options.tun_open, options.tun_local, + options.tun_remote)) == NULL) { if (options.exit_on_forward_failure) fatal("Could not request tunnel forwarding."); else @@ -1774,15 +1765,36 @@ } static int -ssh_session2(struct ssh *ssh) +ssh_session2(struct ssh *ssh, struct passwd *pw) { int id = -1; + char *cp, *tun_fwd_ifname = NULL; /* XXX should be pre-session */ if (!options.control_persist) ssh_init_stdio_forwarding(ssh); - ssh_init_forwarding(ssh); + ssh_init_forwarding(ssh, &tun_fwd_ifname); + + if (options.local_command != NULL) { + debug3("expanding LocalCommand: %s", options.local_command); + cp = options.local_command; + options.local_command = percent_expand(cp, + "C", conn_hash_hex, + "L", shorthost, + "d", pw->pw_dir, + "h", host, + "l", thishost, + "n", host_arg, + "p", portstr, + "r", options.user, + "u", pw->pw_name, + "T", tun_fwd_ifname == NULL ? "NONE" : tun_fwd_ifname, + (char *)NULL); + debug3("expanded LocalCommand: %s", options.local_command); + free(cp); + } + /* Start listening for multiplex clients */ if (!packet_get_mux()) muxserver_listen(ssh); @@ -1857,12 +1869,10 @@ /* Loads all IdentityFile and CertificateFile keys */ static void -load_public_identity_files(void) +load_public_identity_files(struct passwd *pw) { - char *filename, *cp, thishost[NI_MAXHOST]; - char *pwdir = NULL, *pwname = NULL; + char *filename, *cp; struct sshkey *public; - struct passwd *pw; int i; u_int n_ids, n_certs; char *identity_files[SSH_MAX_IDENTITY_FILES]; @@ -1901,11 +1911,6 @@ #endif /* ENABLE_PKCS11 */ if ((pw = getpwuid(original_real_uid)) == NULL) fatal("load_public_identity_files: getpwuid failed"); - pwname = xstrdup(pw->pw_name); - pwdir = xstrdup(pw->pw_dir); - if (gethostname(thishost, sizeof(thishost)) == -1) - fatal("load_public_identity_files: gethostname: %s", - strerror(errno)); for (i = 0; i < options.num_identity_files; i++) { if (n_ids >= SSH_MAX_IDENTITY_FILES || strcasecmp(options.identity_files[i], "none") == 0) { @@ -1915,8 +1920,8 @@ } cp = tilde_expand_filename(options.identity_files[i], original_real_uid); - filename = percent_expand(cp, "d", pwdir, - "u", pwname, "l", thishost, "h", host, + filename = percent_expand(cp, "d", pw->pw_dir, + "u", pw->pw_name, "l", thishost, "h", host, "r", options.user, (char *)NULL); free(cp); public = key_load_public(filename, NULL); @@ -1961,8 +1966,8 @@ for (i = 0; i < options.num_certificate_files; i++) { cp = tilde_expand_filename(options.certificate_files[i], original_real_uid); - filename = percent_expand(cp, "d", pwdir, - "u", pwname, "l", thishost, "h", host, + filename = percent_expand(cp, "d", pw->pw_dir, + "u", pw->pw_name, "l", thishost, "h", host, "r", options.user, (char *)NULL); free(cp); @@ -1995,11 +2000,6 @@ memcpy(options.certificate_files, certificate_files, sizeof(certificate_files)); memcpy(options.certificates, certificates, sizeof(certificates)); - - explicit_bzero(pwname, strlen(pwname)); - free(pwname); - explicit_bzero(pwdir, strlen(pwdir)); - free(pwdir); } static void