-/* $OpenBSD: ssh.c,v 1.420 2015/07/30 00:01:34 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.451 2017/03/10 04:07:20 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
#include <string.h>
#include <unistd.h>
#include <limits.h>
+#include <locale.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "match.h"
#include "msg.h"
#include "uidswap.h"
-#include "roaming.h"
#include "version.h"
#include "ssherr.h"
#include "myproposal.h"
+#include "utf8.h"
#ifdef ENABLE_PKCS11
#include "ssh-pkcs11.h"
*/
int fork_after_authentication_flag = 0;
-/* forward stdio to remote host and port */
-char *stdio_forward_host = NULL;
-int stdio_forward_port = 0;
-
/*
* General data structure for command line options and options configurable
* in configuration files. See readconf.h.
"usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-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"
-" [-L address] [-l login_name] [-m mac_spec]\n"
-" [-O ctl_cmd] [-o option] [-p port]\n"
-" [-Q cipher | cipher-auth | mac | kex | key]\n"
-" [-R address] [-S ctl_path] [-W host:port]\n"
-" [-w local_tun[:remote_tun]] [user@]hostname [command]\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"
);
exit(255);
}
static void load_public_identity_files(void);
static void main_sigchld_handler(int);
-/* from muxclient.c */
-void muxclient(const char *);
-void muxserver_listen(void);
-
/* ~/ expand a list of paths. NB. assumes path[n] is heap-allocated. */
static void
tilde_expand_paths(char **paths, u_int num_paths)
if (port <= 0)
port = default_ssh_port();
- snprintf(strport, sizeof strport, "%u", port);
+ snprintf(strport, sizeof strport, "%d", port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = options.address_family == -1 ?
AF_UNSPEC : options.address_family;
* NB. this function must operate with a options having undefined members.
*/
static int
-check_follow_cname(char **namep, const char *cname)
+check_follow_cname(int direct, char **namep, const char *cname)
{
int i;
struct allowed_cname *rule;
return 0;
/*
* Don't attempt to canonicalize names that will be interpreted by
- * a proxy unless the user specifically requests so.
+ * a proxy or jump host unless the user specifically requests so.
*/
- if (!option_clear_or_none(options.proxy_command) &&
+ if (!direct &&
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
return 0;
debug3("%s: check \"%s\" CNAME \"%s\"", __func__, *namep, cname);
static struct addrinfo *
resolve_canonicalize(char **hostp, int port)
{
- int i, ndots;
+ int i, direct, ndots;
char *cp, *fullhost, newname[NI_MAXHOST];
struct addrinfo *addrs;
* Don't attempt to canonicalize names that will be interpreted by
* a proxy unless the user specifically requests so.
*/
- if (!option_clear_or_none(options.proxy_command) &&
+ direct = option_clear_or_none(options.proxy_command) &&
+ options.jump_host == NULL;
+ if (!direct &&
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
return NULL;
return addrs;
}
+ /* If domain name is anchored, then resolve it now */
+ if ((*hostp)[strlen(*hostp) - 1] == '.') {
+ debug3("%s: name is fully qualified", __func__);
+ fullhost = xstrdup(*hostp);
+ if ((addrs = resolve_host(fullhost, port, 0,
+ newname, sizeof(newname))) != NULL)
+ goto found;
+ free(fullhost);
+ goto notfound;
+ }
+
/* Don't apply canonicalization to sufficiently-qualified hostnames */
ndots = 0;
for (cp = *hostp; *cp != '\0'; cp++) {
free(fullhost);
continue;
}
+ found:
/* Remove trailing '.' */
fullhost[strlen(fullhost) - 1] = '\0';
/* Follow CNAME if requested */
- if (!check_follow_cname(&fullhost, newname)) {
+ if (!check_follow_cname(direct, &fullhost, newname)) {
debug("Canonicalized hostname \"%s\" => \"%s\"",
*hostp, fullhost);
}
*hostp = fullhost;
return addrs;
}
+ notfound:
if (!options.canonicalize_fallback_local)
fatal("%s: Could not resolve host \"%s\"", __progname, *hostp);
debug2("%s: host %s not found in any suffix", __func__, *hostp);
int
main(int ac, char **av)
{
- int i, r, opt, exit_status, use_syslog, config_test = 0;
+ struct ssh *ssh = NULL;
+ int i, r, opt, exit_status, use_syslog, direct, config_test = 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];
+ char cname[NI_MAXHOST], uidstr[32], *conn_hash_hex;
struct stat st;
struct passwd *pw;
int timeout_ms;
struct addrinfo *addrs = NULL;
struct ssh_digest_ctx *md;
u_char conn_hash[SSH_DIGEST_MAX_LENGTH];
- char *conn_hash_hex;
+ ssh_malloc_init(); /* must be called before any mallocs */
/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
sanitise_stdfd();
*/
umask(022);
+ msetlocale();
+
/*
* Initialize option structure to indicate that no values have been
* set.
again:
while ((opt = getopt(ac, av, "1246ab:c:e:fgi:kl:m:no:p:qstvx"
- "ACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
+ "ACD:E:F:GI:J:KL:MNO:PQ:R:S:TVw:W:XYy")) != -1) {
switch (opt) {
case '1':
options.protocol = SSH_PROTO_1;
use_syslog = 1;
break;
case 'E':
- logfile = xstrdup(optarg);
+ logfile = optarg;
break;
case 'G':
config_test = 1;
options.fwd_opts.gateway_ports = 1;
break;
case 'O':
- if (stdio_forward_host != NULL)
+ if (options.stdio_forward_host != NULL)
fatal("Cannot specify multiplexing "
"command with -W");
else if (muxclient_command != 0)
muxclient_command = SSHMUX_COMMAND_STOP;
else if (strcmp(optarg, "cancel") == 0)
muxclient_command = SSHMUX_COMMAND_CANCEL_FWD;
+ else if (strcmp(optarg, "proxy") == 0)
+ muxclient_command = SSHMUX_COMMAND_PROXY;
else
fatal("Invalid multiplex command.");
break;
else if (strcmp(optarg, "kex") == 0)
cp = kex_alg_list('\n');
else if (strcmp(optarg, "key") == 0)
- cp = key_alg_list(0, 0);
+ cp = sshkey_alg_list(0, 0, 0, '\n');
else if (strcmp(optarg, "key-cert") == 0)
- cp = key_alg_list(1, 0);
+ cp = sshkey_alg_list(1, 0, 0, '\n');
else if (strcmp(optarg, "key-plain") == 0)
- cp = key_alg_list(0, 1);
+ cp = sshkey_alg_list(0, 1, 0, '\n');
else if (strcmp(optarg, "protocol-version") == 0) {
#ifdef WITH_SSH1
cp = xstrdup("1\n2");
options.gss_deleg_creds = 1;
break;
case 'i':
- if (stat(optarg, &st) < 0) {
+ p = tilde_expand_filename(optarg, original_real_uid);
+ if (stat(p, &st) < 0)
fprintf(stderr, "Warning: Identity file %s "
- "not accessible: %s.\n", optarg,
+ "not accessible: %s.\n", p,
strerror(errno));
- break;
- }
- add_identity_file(&options, NULL, optarg, 1);
+ else
+ add_identity_file(&options, NULL, p, 1);
+ free(p);
break;
case 'I':
#ifdef ENABLE_PKCS11
+ free(options.pkcs11_provider);
options.pkcs11_provider = xstrdup(optarg);
#else
fprintf(stderr, "no support for PKCS#11.\n");
#endif
break;
+ case 'J':
+ if (options.jump_host != NULL)
+ fatal("Only a single -J option permitted");
+ if (options.proxy_command != NULL)
+ fatal("Cannot specify -J with ProxyCommand");
+ if (parse_jump(optarg, &options, 1) == -1)
+ fatal("Invalid -J argument");
+ options.proxy_command = xstrdup("none");
+ break;
case 't':
if (options.request_tty == REQUEST_TTY_YES)
options.request_tty = REQUEST_TTY_FORCE;
debug_flag = 1;
options.log_level = SYSLOG_LEVEL_DEBUG1;
} else {
- if (options.log_level < SYSLOG_LEVEL_DEBUG3)
+ if (options.log_level < SYSLOG_LEVEL_DEBUG3) {
+ debug_flag++;
options.log_level++;
+ }
}
break;
case 'V':
}
break;
case 'W':
- if (stdio_forward_host != NULL)
+ if (options.stdio_forward_host != NULL)
fatal("stdio forward already specified");
if (muxclient_command != 0)
fatal("Cannot specify stdio forward with -O");
if (parse_forward(&fwd, optarg, 1, 0)) {
- stdio_forward_host = fwd.listen_host;
- stdio_forward_port = fwd.listen_port;
+ options.stdio_forward_host = fwd.listen_host;
+ options.stdio_forward_port = fwd.listen_port;
free(fwd.connect_host);
} else {
fprintf(stderr,
}
options.request_tty = REQUEST_TTY_NO;
no_shell_flag = 1;
- options.clear_forwardings = 1;
- options.exit_on_forward_failure = 1;
break;
case 'q':
options.log_level = SYSLOG_LEVEL_QUIET;
if (ciphers_valid(*optarg == '+' ?
optarg + 1 : optarg)) {
/* SSH2 only */
+ free(options.ciphers);
options.ciphers = xstrdup(optarg);
options.cipher = SSH_CIPHER_INVALID;
break;
options.ciphers = xstrdup(KEX_CLIENT_ENCRYPT);
break;
case 'm':
- if (mac_valid(optarg))
+ if (mac_valid(optarg)) {
+ free(options.macs);
options.macs = xstrdup(optarg);
- else {
+ } else {
fprintf(stderr, "Unknown mac type '%s'\n",
optarg);
exit(255);
subsystem_flag = 1;
break;
case 'S':
- if (options.control_path != NULL)
- free(options.control_path);
+ free(options.control_path);
options.control_path = xstrdup(optarg);
break;
case 'b':
*/
if (use_syslog && logfile != NULL)
fatal("Can't specify both -y and -E");
- if (logfile != NULL) {
+ if (logfile != NULL)
log_redirect_stderr_to(logfile);
- free(logfile);
- }
log_init(argv0,
options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,
SYSLOG_FACILITY_USER, !use_syslog);
* has specifically requested canonicalisation for this case via
* CanonicalizeHostname=always
*/
- if (addrs == NULL && options.num_permitted_cnames != 0 &&
- (option_clear_or_none(options.proxy_command) ||
- options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
+ direct = option_clear_or_none(options.proxy_command) &&
+ options.jump_host == NULL;
+ if (addrs == NULL && options.num_permitted_cnames != 0 && (direct ||
+ options.canonicalize_hostname == SSH_CANONICALISE_ALWAYS)) {
if ((addrs = resolve_host(host, options.port,
option_clear_or_none(options.proxy_command),
cname, sizeof(cname))) == NULL) {
if (option_clear_or_none(options.proxy_command))
cleanup_exit(255); /* logged in resolve_host */
} else
- check_follow_cname(&host, cname);
+ check_follow_cname(direct, &host, cname);
}
/*
/* Fill configuration defaults. */
fill_default_options(&options);
+ /*
+ * If ProxyJump option specified, then construct a ProxyCommand now.
+ */
+ if (options.jump_host != NULL) {
+ char port_s[8];
+
+ /* Consistency check */
+ if (options.proxy_command != NULL)
+ fatal("inconsistent options: ProxyCommand+ProxyJump");
+ /* Never use FD passing for ProxyJump */
+ options.proxy_use_fdpass = 0;
+ snprintf(port_s, sizeof(port_s), "%d", options.jump_port);
+ xasprintf(&options.proxy_command,
+ "ssh%s%s%s%s%s%s%s%s%s%.*s -W '[%%h]:%%p' %s",
+ /* Optional "-l user" argument if jump_user set */
+ options.jump_user == NULL ? "" : " -l ",
+ options.jump_user == NULL ? "" : options.jump_user,
+ /* Optional "-p port" argument if jump_port set */
+ options.jump_port <= 0 ? "" : " -p ",
+ options.jump_port <= 0 ? "" : port_s,
+ /* Optional additional jump hosts ",..." */
+ options.jump_extra == NULL ? "" : " -J ",
+ options.jump_extra == NULL ? "" : options.jump_extra,
+ /* Optional "-F" argumment if -F specified */
+ config == NULL ? "" : " -F ",
+ config == NULL ? "" : config,
+ /* Optional "-v" arguments if -v set */
+ debug_flag ? " -" : "",
+ debug_flag, "vvv",
+ /* Mandatory hostname */
+ options.jump_host);
+ debug("Setting implicit ProxyCommand from ProxyJump: %s",
+ options.proxy_command);
+ }
+
if (options.port == 0)
options.port = default_ssh_port();
channel_set_af(options.address_family);
"disabling");
options.update_hostkeys = 0;
}
+ if (options.connection_attempts <= 0)
+ fatal("Invalid number of ConnectionAttempts");
#ifndef HAVE_CYGWIN
if (original_effective_uid != 0)
options.use_privileged_port = 0;
tty_flag = options.request_tty != REQUEST_TTY_NO;
/* Force no tty */
- if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0)
+ if (options.request_tty == REQUEST_TTY_NO ||
+ (muxclient_command && muxclient_command != SSHMUX_COMMAND_PROXY))
tty_flag = 0;
/* Do not allocate a tty if stdin is not a tty. */
if ((!isatty(fileno(stdin)) || stdin_null_flag) &&
strlcpy(shorthost, thishost, sizeof(shorthost));
shorthost[strcspn(thishost, ".")] = '\0';
snprintf(portstr, sizeof(portstr), "%d", options.port);
+ snprintf(uidstr, sizeof(uidstr), "%d", pw->pw_uid);
if ((md = ssh_digest_start(SSH_DIGEST_SHA1)) == NULL ||
ssh_digest_update(md, thishost, strlen(thishost)) < 0 ||
"p", portstr,
"r", options.user,
"u", pw->pw_name,
+ "i", uidstr,
(char *)NULL);
free(cp);
}
if (muxclient_command != 0 && options.control_path == NULL)
fatal("No ControlPath specified for \"-O\" command");
- if (options.control_path != NULL)
- muxclient(options.control_path);
+ if (options.control_path != NULL) {
+ int sock;
+ if ((sock = muxclient(options.control_path)) >= 0) {
+ packet_set_connection(sock, sock);
+ ssh = active_state; /* XXX */
+ enable_compat20(); /* XXX */
+ packet_set_mux();
+ goto skip_connect;
+ }
+ }
/*
* If hostname canonicalisation was not enabled, then we may not
* have yet resolved the hostname. Do so now.
*/
if (addrs == NULL && options.proxy_command == NULL) {
+ debug2("resolving \"%s\" port %d", host, options.port);
if ((addrs = resolve_host(host, options.port, 1,
cname, sizeof(cname))) == NULL)
cleanup_exit(255); /* resolve_host logs the error */
packet_set_timeout(options.server_alive_interval,
options.server_alive_count_max);
+ ssh = active_state; /* XXX */
+
if (timeout_ms > 0)
debug3("timeout: %d ms remain after connect", timeout_ms);
sensitive_data.keys[i] = NULL;
PRIV_START;
+#if WITH_SSH1
sensitive_data.keys[0] = key_load_private_type(KEY_RSA1,
_PATH_HOST_KEY_FILE, "", NULL, NULL);
+#endif
#ifdef OPENSSL_HAS_ECC
sensitive_data.keys[1] = key_load_private_cert(KEY_ECDSA,
_PATH_HOST_ECDSA_KEY_FILE, "", NULL);
/* load options.identity_files */
load_public_identity_files();
+ /* optionally set the SSH_AUTHSOCKET_ENV_NAME varibale */
+ if (options.identity_agent &&
+ strcmp(options.identity_agent, SSH_AUTHSOCKET_ENV_NAME) != 0) {
+ if (strcmp(options.identity_agent, "none") == 0) {
+ unsetenv(SSH_AUTHSOCKET_ENV_NAME);
+ } else {
+ p = tilde_expand_filename(options.identity_agent,
+ original_real_uid);
+ cp = percent_expand(p, "d", pw->pw_dir,
+ "u", pw->pw_name, "l", thishost, "h", host,
+ "r", options.user, (char *)NULL);
+ setenv(SSH_AUTHSOCKET_ENV_NAME, cp, 1);
+ free(cp);
+ free(p);
+ }
+ }
+
/* Expand ~ in known host file names. */
tilde_expand_paths(options.system_hostfiles,
options.num_system_hostfiles);
if (packet_connection_is_on_socket()) {
verbose("Authenticated to %s ([%s]:%d).", host,
- get_remote_ipaddr(), get_remote_port());
+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
} else {
verbose("Authenticated to %s (via proxy).", host);
}
options.identity_keys[i] = NULL;
}
}
+ for (i = 0; i < options.num_certificate_files; i++) {
+ free(options.certificate_files[i]);
+ options.certificate_files[i] = NULL;
+ }
+ skip_connect:
exit_status = compat20 ? ssh_session2() : ssh_session();
packet_close();
control_persist_detach(void)
{
pid_t pid;
- int devnull;
+ int devnull, keep_stderr;
debug("%s: backgrounding master process", __func__);
error("%s: open(\"/dev/null\"): %s", __func__,
strerror(errno));
} else {
+ keep_stderr = log_is_on_stderr() && debug_flag;
if (dup2(devnull, STDIN_FILENO) == -1 ||
- dup2(devnull, STDOUT_FILENO) == -1)
+ dup2(devnull, STDOUT_FILENO) == -1 ||
+ (!keep_stderr && dup2(devnull, STDERR_FILENO) == -1))
error("%s: dup2: %s", __func__, strerror(errno));
if (devnull > STDERR_FILENO)
close(devnull);
Channel *c;
int in, out;
- if (stdio_forward_host == NULL)
+ if (options.stdio_forward_host == NULL)
return;
if (!compat20)
fatal("stdio forwarding require Protocol 2");
- debug3("%s: %s:%d", __func__, stdio_forward_host, stdio_forward_port);
+ debug3("%s: %s:%d", __func__, options.stdio_forward_host,
+ options.stdio_forward_port);
if ((in = dup(STDIN_FILENO)) < 0 ||
(out = dup(STDOUT_FILENO)) < 0)
fatal("channel_connect_stdio_fwd: dup() in/out failed");
- if ((c = channel_connect_stdio_fwd(stdio_forward_host,
- stdio_forward_port, in, out)) == NULL)
+ if ((c = channel_connect_stdio_fwd(options.stdio_forward_host,
+ options.stdio_forward_port, in, out)) == NULL)
fatal("%s: channel_connect_stdio_fwd failed", __func__);
channel_register_cleanup(c->self, client_cleanup_stdio_fwd, 0);
channel_register_open_confirm(c->self, ssh_stdio_confirm, NULL);
struct winsize ws;
char *cp;
const char *display;
+ char *proto = NULL, *data = NULL;
/* Enable compression if requested. */
if (options.compression) {
display = getenv("DISPLAY");
if (display == NULL && options.forward_x11)
debug("X11 forwarding requested but DISPLAY not set");
- if (options.forward_x11 && display != NULL) {
- char *proto, *data;
- /* Get reasonable local authentication information. */
- client_x11_get_proto(display, options.xauth_location,
- options.forward_x11_trusted,
- options.forward_x11_timeout,
- &proto, &data);
+ if (options.forward_x11 && client_x11_get_proto(display,
+ options.xauth_location, options.forward_x11_trusted,
+ options.forward_x11_timeout, &proto, &data) == 0) {
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication "
"spoofing.");
extern char **environ;
const char *display;
int interactive = tty_flag;
+ char *proto = NULL, *data = NULL;
if (!success)
return; /* No need for error message, channels code sens one */
display = getenv("DISPLAY");
if (display == NULL && options.forward_x11)
debug("X11 forwarding requested but DISPLAY not set");
- if (options.forward_x11 && display != NULL) {
- char *proto, *data;
- /* Get reasonable local authentication information. */
- client_x11_get_proto(display, options.xauth_location,
- options.forward_x11_trusted,
- options.forward_x11_timeout, &proto, &data);
+ if (options.forward_x11 && client_x11_get_proto(display,
+ options.xauth_location, options.forward_x11_trusted,
+ options.forward_x11_timeout, &proto, &data) == 0) {
/* Request forwarding with authentication spoofing. */
debug("Requesting X11 forwarding with authentication "
"spoofing.");
ssh_init_forwarding();
/* Start listening for multiplex clients */
- muxserver_listen();
+ if (!packet_get_mux())
+ muxserver_listen();
/*
* If we are in control persist mode and have a working mux listen
options.escape_char : SSH_ESCAPECHAR_NONE, id);
}
+/* Loads all IdentityFile and CertificateFile keys */
static void
load_public_identity_files(void)
{
char *filename, *cp, thishost[NI_MAXHOST];
char *pwdir = NULL, *pwname = NULL;
- int i = 0;
Key *public;
struct passwd *pw;
- u_int n_ids;
+ int i;
+ u_int n_ids, n_certs;
char *identity_files[SSH_MAX_IDENTITY_FILES];
Key *identity_keys[SSH_MAX_IDENTITY_FILES];
+ char *certificate_files[SSH_MAX_CERTIFICATE_FILES];
+ struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
#ifdef ENABLE_PKCS11
Key **keys;
int nkeys;
#endif /* PKCS11 */
- n_ids = 0;
+ n_ids = n_certs = 0;
memset(identity_files, 0, sizeof(identity_files));
memset(identity_keys, 0, sizeof(identity_keys));
+ memset(certificate_files, 0, sizeof(certificate_files));
+ memset(certificates, 0, sizeof(certificates));
#ifdef ENABLE_PKCS11
if (options.pkcs11_provider != NULL &&
if (n_ids >= SSH_MAX_IDENTITY_FILES ||
strcasecmp(options.identity_files[i], "none") == 0) {
free(options.identity_files[i]);
+ options.identity_files[i] = NULL;
continue;
}
cp = tilde_expand_filename(options.identity_files[i],
if (++n_ids >= SSH_MAX_IDENTITY_FILES)
continue;
- /* Try to add the certificate variant too */
+ /*
+ * If no certificates have been explicitly listed then try
+ * to add the default certificate variant too.
+ */
+ if (options.num_certificate_files != 0)
+ continue;
xasprintf(&cp, "%s-cert", filename);
public = key_load_public(cp, NULL);
debug("identity file %s type %d", cp,
free(cp);
continue;
}
- identity_keys[n_ids] = public;
- /* point to the original path, most likely the private key */
+ /* NB. leave filename pointing to private key */
identity_files[n_ids] = xstrdup(filename);
+ identity_keys[n_ids] = public;
n_ids++;
}
+
+ if (options.num_certificate_files > SSH_MAX_CERTIFICATE_FILES)
+ fatal("%s: too many certificates", __func__);
+ 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,
+ "r", options.user, (char *)NULL);
+ free(cp);
+
+ public = key_load_public(filename, NULL);
+ debug("certificate file %s type %d", filename,
+ public ? public->type : -1);
+ free(options.certificate_files[i]);
+ options.certificate_files[i] = NULL;
+ if (public == NULL) {
+ free(filename);
+ continue;
+ }
+ if (!key_is_cert(public)) {
+ debug("%s: key %s type %s is not a certificate",
+ __func__, filename, key_type(public));
+ key_free(public);
+ free(filename);
+ continue;
+ }
+ certificate_files[n_certs] = filename;
+ certificates[n_certs] = public;
+ ++n_certs;
+ }
+
options.num_identity_files = n_ids;
memcpy(options.identity_files, identity_files, sizeof(identity_files));
memcpy(options.identity_keys, identity_keys, sizeof(identity_keys));
+ options.num_certificate_files = n_certs;
+ 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));