diff options
Diffstat (limited to 'ssh.c')
| -rw-r--r-- | ssh.c | 344 | 
1 files changed, 225 insertions, 119 deletions
| @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.464 2017/09/21 19:16:53 markus Exp $ */ +/* $OpenBSD: ssh.c,v 1.475 2018/02/23 15:58:38 markus Exp $ */  /*   * Author: Tatu Ylonen <ylo@cs.hut.fi>   * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -168,6 +168,10 @@ char *config = NULL;   */  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; @@ -197,19 +201,19 @@ static void  usage(void)  {  	fprintf(stderr, -"usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]\n" -"           [-D [bind_address:]port] [-E log_file] [-e escape_char]\n" -"           [-F configfile] [-I pkcs11] [-i identity_file]\n" -"           [-J [user@]host[:port]] [-L address] [-l login_name] [-m mac_spec]\n" -"           [-O ctl_cmd] [-o option] [-p port] [-Q query_option] [-R address]\n" -"           [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]\n" -"           [user@]hostname [command]\n" +"usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]\n" +"           [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]\n" +"           [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]\n" +"           [-i identity_file] [-J [user@]host[:port]] [-L address]\n" +"           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" +"           [-Q query_option] [-R address] [-S ctl_path] [-W host:port]\n" +"           [-w local_tun[:remote_tun]] destination [command]\n"  	);  	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. */ @@ -267,6 +271,40 @@ resolve_host(const char *name, int port, int logerr, char *cname, size_t clen)  	return res;  } +/* Returns non-zero if name can only be an address and not a hostname */ +static int +is_addr_fast(const char *name) +{ +	return (strchr(name, '%') != NULL || strchr(name, ':') != NULL || +	    strspn(name, "0123456789.") == strlen(name)); +} + +/* Returns non-zero if name represents a valid, single address */ +static int +is_addr(const char *name) +{ +	char strport[NI_MAXSERV]; +	struct addrinfo hints, *res; + +	if (is_addr_fast(name)) +		return 1; + +	snprintf(strport, sizeof strport, "%u", default_ssh_port()); +	memset(&hints, 0, sizeof(hints)); +	hints.ai_family = options.address_family == -1 ? +	    AF_UNSPEC : options.address_family; +	hints.ai_socktype = SOCK_STREAM; +	hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV; +	if (getaddrinfo(name, strport, &hints, &res) != 0) +		return 0; +	if (res == NULL || res->ai_next != NULL) { +		freeaddrinfo(res); +		return 0; +	} +	freeaddrinfo(res); +	return 1; +} +  /*   * Attempt to resolve a numeric host address / port to a single address.   * Returns a canonical address string. @@ -372,20 +410,10 @@ resolve_canonicalize(char **hostp, int port)  	char *cp, *fullhost, newname[NI_MAXHOST];  	struct addrinfo *addrs; -	if (options.canonicalize_hostname == SSH_CANONICALISE_NO) -		return NULL; -  	/* -	 * Don't attempt to canonicalize names that will be interpreted by -	 * a proxy unless the user specifically requests so. +	 * Attempt to canonicalise addresses, regardless of +	 * whether hostname canonicalisation was requested  	 */ -	direct = option_clear_or_none(options.proxy_command) && -	    options.jump_host == NULL; -	if (!direct && -	    options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) -		return NULL; - -	/* Try numeric hostnames first */  	if ((addrs = resolve_addr(*hostp, port,  	    newname, sizeof(newname))) != NULL) {  		debug2("%s: hostname %.100s is address", __func__, *hostp); @@ -398,6 +426,30 @@ resolve_canonicalize(char **hostp, int port)  		return addrs;  	} +	/* +	 * If this looks like an address but didn't parse as one, it might +	 * be an address with an invalid interface scope. Skip further +	 * attempts at canonicalisation. +	 */ +	if (is_addr_fast(*hostp)) { +		debug("%s: hostname %.100s is an unrecognised address", +		    __func__, *hostp); +		return NULL; +	} + +	if (options.canonicalize_hostname == SSH_CANONICALISE_NO) +		return NULL; + +	/* +	 * Don't attempt to canonicalize names that will be interpreted by +	 * a proxy unless the user specifically requests so. +	 */ +	direct = option_clear_or_none(options.proxy_command) && +	    options.jump_host == NULL; +	if (!direct && +	    options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS) +		return NULL; +  	/* If domain name is anchored, then resolve it now */  	if ((*hostp)[strlen(*hostp) - 1] == '.') {  		debug3("%s: name is fully qualified", __func__); @@ -456,14 +508,14 @@ resolve_canonicalize(char **hostp, int port)   * 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)); @@ -471,13 +523,13 @@ process_config_files(const char *host_arg, struct passwd *pw, int post_canon)  		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);  	}  } @@ -510,10 +562,9 @@ main(int ac, char **av)  {  	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; +	int was_addr, config_test = 0, opt_terminated = 0; +	char *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile; +	char cname[NI_MAXHOST];  	struct stat st;  	struct passwd *pw;  	extern int optind, optreset; @@ -612,7 +663,7 @@ main(int ac, char **av)   again:  	while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx" -	    "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) { +	    "AB:CD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {  		switch (opt) {  		case '1':  			fatal("SSH protocol v.1 is no longer supported"); @@ -846,14 +897,18 @@ main(int ac, char **av)  				options.control_master = SSHCTL_MASTER_YES;  			break;  		case 'p': -			options.port = a2port(optarg); -			if (options.port <= 0) { -				fprintf(stderr, "Bad port '%s'\n", optarg); -				exit(255); +			if (options.port == -1) { +				options.port = a2port(optarg); +				if (options.port <= 0) { +					fprintf(stderr, "Bad port '%s'\n", +					    optarg); +					exit(255); +				}  			}  			break;  		case 'l': -			options.user = optarg; +			if (options.user == NULL) +				options.user = optarg;  			break;  		case 'L': @@ -918,6 +973,9 @@ main(int ac, char **av)  		case 'b':  			options.bind_address = optarg;  			break; +		case 'B': +			options.bind_interface = optarg; +			break;  		case 'F':  			config = optarg;  			break; @@ -933,16 +991,38 @@ main(int ac, char **av)  	av += optind;  	if (ac > 0 && !host) { -		if (strrchr(*av, '@')) { +		int tport; +		char *tuser; +		switch (parse_ssh_uri(*av, &tuser, &host, &tport)) { +		case -1: +			usage(); +			break; +		case 0: +			if (options.user == NULL) { +				options.user = tuser; +				tuser = NULL; +			} +			free(tuser); +			if (options.port == -1 && tport != -1) +				options.port = tport; +			break; +		default:  			p = xstrdup(*av);  			cp = strrchr(p, '@'); -			if (cp == NULL || cp == p) -				usage(); -			options.user = p; -			*cp = '\0'; -			host = xstrdup(++cp); -		} else -			host = xstrdup(*av); +			if (cp != NULL) { +				if (cp == p) +					usage(); +				if (options.user == NULL) { +					options.user = p; +					p = NULL; +				} +				*cp++ = '\0'; +				host = xstrdup(cp); +				free(p); +			} else +				host = p; +			break; +		}  		if (ac > 1 && !opt_terminated) {  			optind = optreset = 1;  			goto again; @@ -994,9 +1074,9 @@ main(int ac, char **av)  	if (logfile != NULL)  		log_redirect_stderr_to(logfile);  	log_init(argv0, -	    options.log_level == SYSLOG_LEVEL_NOT_SET ?  +	    options.log_level == SYSLOG_LEVEL_NOT_SET ?  	    SYSLOG_LEVEL_INFO : options.log_level, -	    options.log_facility == SYSLOG_FACILITY_NOT_SET ?  +	    options.log_facility == SYSLOG_FACILITY_NOT_SET ?  	    SYSLOG_FACILITY_USER : options.log_facility,  	    !use_syslog); @@ -1026,16 +1106,22 @@ main(int ac, char **av)  		options.hostname = xstrdup(host);  	} -	/* If canonicalization requested then try to apply it */ -	lowercase(host); -	if (options.canonicalize_hostname != SSH_CANONICALISE_NO) +	/* Don't lowercase addresses, they will be explicitly canonicalised */ +	if ((was_addr = is_addr(host)) == 0) +		lowercase(host); + +	/* +	 * Try to canonicalize if requested by configuration or the +	 * hostname is an address. +	 */ +	if (options.canonicalize_hostname != SSH_CANONICALISE_NO || was_addr)  		addrs = resolve_canonicalize(&host, options.port);  	/*  	 * If CanonicalizePermittedCNAMEs have been specified but  	 * other canonicalization did not happen (by not being requested  	 * or by failing with fallback) then the hostname may still be changed -	 * as a result of CNAME following.  +	 * as a result of CNAME following.  	 *  	 * Try to resolve the bare hostname name using the system resolver's  	 * usual search rules and then apply the CNAME follow rules. @@ -1177,6 +1263,7 @@ main(int ac, char **av)  	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)); @@ -1194,24 +1281,11 @@ main(int ac, char **av)  	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; @@ -1230,7 +1304,6 @@ main(int ac, char **av)  		free(cp);  		buffer_append(&command, options.remote_command,  		    strlen(options.remote_command)); -  	}  	if (options.control_path != NULL) { @@ -1311,7 +1384,7 @@ main(int ac, char **av)  	sensitive_data.keys = NULL;  	sensitive_data.external_keysign = 0;  	if (options.hostbased_authentication) { -		sensitive_data.nkeys = 9; +		sensitive_data.nkeys = 11;  		sensitive_data.keys = xcalloc(sensitive_data.nkeys,  		    sizeof(struct sshkey));	/* XXX */  		for (i = 0; i < sensitive_data.nkeys; i++) @@ -1338,6 +1411,10 @@ main(int ac, char **av)  		    _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL);  		sensitive_data.keys[8] = key_load_private_type(KEY_DSA,  		    _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); +		sensitive_data.keys[9] = key_load_private_cert(KEY_XMSS, +		    _PATH_HOST_XMSS_KEY_FILE, "", NULL); +		sensitive_data.keys[10] = key_load_private_type(KEY_XMSS, +		    _PATH_HOST_XMSS_KEY_FILE, "", NULL, NULL);  		PRIV_END;  		if (options.hostbased_authentication == 1 && @@ -1345,7 +1422,8 @@ main(int ac, char **av)  		    sensitive_data.keys[5] == NULL &&  		    sensitive_data.keys[6] == NULL &&  		    sensitive_data.keys[7] == NULL && -		    sensitive_data.keys[8] == NULL) { +		    sensitive_data.keys[8] == NULL && +		    sensitive_data.keys[9] == NULL) {  #ifdef OPENSSL_HAS_ECC  			sensitive_data.keys[1] = key_load_cert(  			    _PATH_HOST_ECDSA_KEY_FILE); @@ -1366,6 +1444,10 @@ main(int ac, char **av)  			    _PATH_HOST_RSA_KEY_FILE, NULL);  			sensitive_data.keys[8] = key_load_public(  			    _PATH_HOST_DSA_KEY_FILE, NULL); +			sensitive_data.keys[9] = key_load_cert( +			    _PATH_HOST_XMSS_KEY_FILE); +			sensitive_data.keys[10] = key_load_public( +			    _PATH_HOST_XMSS_KEY_FILE, NULL);  			sensitive_data.external_keysign = 1;  		}  	} @@ -1401,7 +1483,7 @@ main(int ac, char **av)  		}  	}  	/* 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 && @@ -1465,7 +1547,7 @@ main(int ac, char **av)  	}   skip_connect: -	exit_status = ssh_session2(ssh); +	exit_status = ssh_session2(ssh, pw);  	packet_close();  	if (options.control_path != NULL && muxserver_sock != -1) @@ -1485,29 +1567,29 @@ control_persist_detach(void)  	debug("%s: backgrounding master process", __func__); - 	/* - 	 * master (current process) into the background, and make the - 	 * foreground process a client of the backgrounded master. - 	 */ +	/* +	 * master (current process) into the background, and make the +	 * foreground process a client of the backgrounded master. +	 */  	switch ((pid = fork())) {  	case -1:  		fatal("%s: fork: %s", __func__, strerror(errno));  	case 0:  		/* Child: master process continues mainloop */ - 		break; - 	default: +		break; +	default:  		/* Parent: set up mux slave to connect to backgrounded master */  		debug2("%s: background process is %ld", __func__, (long)pid);  		stdin_null_flag = ostdin_null_flag;  		options.request_tty = orequest_tty;  		tty_flag = otty_flag; - 		close(muxserver_sock); - 		muxserver_sock = -1; +		close(muxserver_sock); +		muxserver_sock = -1;  		options.control_master = SSHCTL_MASTER_NO; - 		muxclient(options.control_path); +		muxclient(options.control_path);  		/* muxclient() doesn't return on success. */ - 		fatal("Failed to connect to new control master"); - 	} +		fatal("Failed to connect to new control master"); +	}  	if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {  		error("%s: open(\"/dev/null\"): %s", __func__,  		    strerror(errno)); @@ -1562,7 +1644,7 @@ ssh_confirm_remote_forward(struct ssh *ssh, int type, u_int32_t seq, void *ctxt)  			channel_update_permitted_opens(ssh, rfwd->handle, -1);  		}  	} -	 +  	if (type == SSH2_MSG_REQUEST_FAILURE) {  		if (options.exit_on_forward_failure) {  			if (rfwd->listen_path != NULL) @@ -1624,7 +1706,7 @@ ssh_init_stdio_forwarding(struct ssh *ssh)  }  static void -ssh_init_forwarding(struct ssh *ssh) +ssh_init_forwarding(struct ssh *ssh, char **ifname)  {  	int success = 0;  	int i; @@ -1682,14 +1764,15 @@ ssh_init_forwarding(struct ssh *ssh)  	/* 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  				error("Could not request tunnel forwarding.");  		} -	}			 +	}  }  static void @@ -1798,20 +1881,41 @@ ssh_session2_open(struct ssh *ssh)  }  static int -ssh_session2(struct ssh *ssh) +ssh_session2(struct ssh *ssh, struct passwd *pw)  { -	int id = -1; +	int devnull, 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); - 	/* +	/*  	 * If we are in control persist mode and have a working mux listen  	 * socket, then prepare to background ourselves and have a foreground  	 * client attach as a control slave. @@ -1820,18 +1924,18 @@ ssh_session2(struct ssh *ssh)  	 * after the connection is fully established (in particular,  	 * async rfwd replies have been received for ExitOnForwardFailure).  	 */ - 	if (options.control_persist && muxserver_sock != -1) { +	if (options.control_persist && muxserver_sock != -1) {  		ostdin_null_flag = stdin_null_flag;  		ono_shell_flag = no_shell_flag;  		orequest_tty = options.request_tty;  		otty_flag = tty_flag; - 		stdin_null_flag = 1; - 		no_shell_flag = 1; - 		tty_flag = 0; +		stdin_null_flag = 1; +		no_shell_flag = 1; +		tty_flag = 0;  		if (!fork_after_authentication_flag)  			need_controlpersist_detach = 1;  		fork_after_authentication_flag = 1; - 	} +	}  	/*  	 * ControlPersist mux listen socket setup failed, attempt the  	 * stdio forward setup that we skipped earlier. @@ -1839,7 +1943,7 @@ ssh_session2(struct ssh *ssh)  	if (options.control_persist && muxserver_sock == -1)  		ssh_init_stdio_forwarding(ssh); -	if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) +	if (!no_shell_flag)  		id = ssh_session2_open(ssh);  	else {  		packet_set_interactive( @@ -1863,6 +1967,22 @@ ssh_session2(struct ssh *ssh)  		ssh_local_cmd(options.local_command);  	/* +	 * stdout is now owned by the session channel; clobber it here +	 * so future channel closes are propagated to the local fd. +	 * NB. this can only happen after LocalCommand has completed, +	 * as it may want to write to stdout. +	 */ +	if (!need_controlpersist_detach) { +		if ((devnull = open(_PATH_DEVNULL, O_WRONLY)) == -1) +			error("%s: open %s: %s", __func__, +			    _PATH_DEVNULL, strerror(errno)); +		if (dup2(devnull, STDOUT_FILENO) < 0) +			fatal("%s: dup2() stdout failed", __func__); +		if (devnull > STDERR_FILENO) +			close(devnull); +	} + +	/*  	 * If requested and we are not interested in replies to remote  	 * forwarding requests, then let ssh continue in the background.  	 */ @@ -1881,12 +2001,10 @@ ssh_session2(struct ssh *ssh)  /* 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]; @@ -1925,11 +2043,6 @@ load_public_identity_files(void)  #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) { @@ -1939,8 +2052,8 @@ load_public_identity_files(void)  		}  		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); @@ -1985,8 +2098,8 @@ load_public_identity_files(void)  	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); @@ -2019,11 +2132,6 @@ load_public_identity_files(void)  	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 @@ -2036,7 +2144,5 @@ main_sigchld_handler(int sig)  	while ((pid = waitpid(-1, &status, WNOHANG)) > 0 ||  	    (pid < 0 && errno == EINTR))  		; - -	signal(sig, main_sigchld_handler);  	errno = save_errno;  } | 
