diff options
-rw-r--r-- | readconf.c | 17 | ||||
-rw-r--r-- | readconf.h | 3 | ||||
-rw-r--r-- | ssh.c | 18 | ||||
-rw-r--r-- | sshconnect2.c | 111 |
4 files changed, 120 insertions, 29 deletions
diff --git a/readconf.c b/readconf.c index f78b4d6fe..f18194580 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.c,v 1.309 2019/09/06 14:45:34 naddy Exp $ */ | 1 | /* $OpenBSD: readconf.c,v 1.310 2019/10/31 21:18:28 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -174,6 +174,7 @@ typedef enum { | |||
174 | oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, | 174 | oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, |
175 | oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, | 175 | oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes, |
176 | oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump, | 176 | oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump, |
177 | oSecurityKeyProvider, | ||
177 | oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported | 178 | oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported |
178 | } OpCodes; | 179 | } OpCodes; |
179 | 180 | ||
@@ -214,6 +215,7 @@ static struct { | |||
214 | { "smartcarddevice", oUnsupported }, | 215 | { "smartcarddevice", oUnsupported }, |
215 | { "pkcs11provider", oUnsupported }, | 216 | { "pkcs11provider", oUnsupported }, |
216 | #endif | 217 | #endif |
218 | { "securitykeyprovider", oSecurityKeyProvider }, | ||
217 | { "rsaauthentication", oUnsupported }, | 219 | { "rsaauthentication", oUnsupported }, |
218 | { "rhostsrsaauthentication", oUnsupported }, | 220 | { "rhostsrsaauthentication", oUnsupported }, |
219 | { "compressionlevel", oUnsupported }, | 221 | { "compressionlevel", oUnsupported }, |
@@ -1146,6 +1148,10 @@ parse_char_array: | |||
1146 | charptr = &options->pkcs11_provider; | 1148 | charptr = &options->pkcs11_provider; |
1147 | goto parse_string; | 1149 | goto parse_string; |
1148 | 1150 | ||
1151 | case oSecurityKeyProvider: | ||
1152 | charptr = &options->sk_provider; | ||
1153 | goto parse_string; | ||
1154 | |||
1149 | case oProxyCommand: | 1155 | case oProxyCommand: |
1150 | charptr = &options->proxy_command; | 1156 | charptr = &options->proxy_command; |
1151 | /* Ignore ProxyCommand if ProxyJump already specified */ | 1157 | /* Ignore ProxyCommand if ProxyJump already specified */ |
@@ -1906,6 +1912,7 @@ initialize_options(Options * options) | |||
1906 | options->bind_address = NULL; | 1912 | options->bind_address = NULL; |
1907 | options->bind_interface = NULL; | 1913 | options->bind_interface = NULL; |
1908 | options->pkcs11_provider = NULL; | 1914 | options->pkcs11_provider = NULL; |
1915 | options->sk_provider = NULL; | ||
1909 | options->enable_ssh_keysign = - 1; | 1916 | options->enable_ssh_keysign = - 1; |
1910 | options->no_host_authentication_for_localhost = - 1; | 1917 | options->no_host_authentication_for_localhost = - 1; |
1911 | options->identities_only = - 1; | 1918 | options->identities_only = - 1; |
@@ -2043,6 +2050,8 @@ fill_default_options(Options * options) | |||
2043 | add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0); | 2050 | add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0); |
2044 | #ifdef OPENSSL_HAS_ECC | 2051 | #ifdef OPENSSL_HAS_ECC |
2045 | add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0); | 2052 | add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0); |
2053 | add_identity_file(options, "~/", | ||
2054 | _PATH_SSH_CLIENT_ID_ECDSA_SK, 0); | ||
2046 | #endif | 2055 | #endif |
2047 | add_identity_file(options, "~/", | 2056 | add_identity_file(options, "~/", |
2048 | _PATH_SSH_CLIENT_ID_ED25519, 0); | 2057 | _PATH_SSH_CLIENT_ID_ED25519, 0); |
@@ -2118,6 +2127,8 @@ fill_default_options(Options * options) | |||
2118 | options->fingerprint_hash = SSH_FP_HASH_DEFAULT; | 2127 | options->fingerprint_hash = SSH_FP_HASH_DEFAULT; |
2119 | if (options->update_hostkeys == -1) | 2128 | if (options->update_hostkeys == -1) |
2120 | options->update_hostkeys = 0; | 2129 | options->update_hostkeys = 0; |
2130 | if (options->sk_provider == NULL) | ||
2131 | options->sk_provider = xstrdup("$SSH_SK_PROVIDER"); | ||
2121 | 2132 | ||
2122 | /* Expand KEX name lists */ | 2133 | /* Expand KEX name lists */ |
2123 | all_cipher = cipher_alg_list(',', 0); | 2134 | all_cipher = cipher_alg_list(',', 0); |
@@ -2135,7 +2146,7 @@ fill_default_options(Options * options) | |||
2135 | ASSEMBLE(macs, KEX_CLIENT_MAC, all_mac); | 2146 | ASSEMBLE(macs, KEX_CLIENT_MAC, all_mac); |
2136 | ASSEMBLE(kex_algorithms, KEX_CLIENT_KEX, all_kex); | 2147 | ASSEMBLE(kex_algorithms, KEX_CLIENT_KEX, all_kex); |
2137 | ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key); | 2148 | ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key); |
2138 | ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key); | 2149 | ASSEMBLE(pubkey_key_types, PUBKEY_DEFAULT_PK_ALG, all_key); |
2139 | ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig); | 2150 | ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig); |
2140 | #undef ASSEMBLE | 2151 | #undef ASSEMBLE |
2141 | free(all_cipher); | 2152 | free(all_cipher); |
@@ -2157,6 +2168,7 @@ fill_default_options(Options * options) | |||
2157 | CLEAR_ON_NONE(options->control_path); | 2168 | CLEAR_ON_NONE(options->control_path); |
2158 | CLEAR_ON_NONE(options->revoked_host_keys); | 2169 | CLEAR_ON_NONE(options->revoked_host_keys); |
2159 | CLEAR_ON_NONE(options->pkcs11_provider); | 2170 | CLEAR_ON_NONE(options->pkcs11_provider); |
2171 | CLEAR_ON_NONE(options->sk_provider); | ||
2160 | if (options->jump_host != NULL && | 2172 | if (options->jump_host != NULL && |
2161 | strcmp(options->jump_host, "none") == 0 && | 2173 | strcmp(options->jump_host, "none") == 0 && |
2162 | options->jump_port == 0 && options->jump_user == NULL) { | 2174 | options->jump_port == 0 && options->jump_user == NULL) { |
@@ -2673,6 +2685,7 @@ dump_client_config(Options *o, const char *host) | |||
2673 | #ifdef ENABLE_PKCS11 | 2685 | #ifdef ENABLE_PKCS11 |
2674 | dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); | 2686 | dump_cfg_string(oPKCS11Provider, o->pkcs11_provider); |
2675 | #endif | 2687 | #endif |
2688 | dump_cfg_string(oSecurityKeyProvider, o->sk_provider); | ||
2676 | dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); | 2689 | dump_cfg_string(oPreferredAuthentications, o->preferred_authentications); |
2677 | dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types); | 2690 | dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types); |
2678 | dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); | 2691 | dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys); |
diff --git a/readconf.h b/readconf.h index 8e36bf32a..51d540b88 100644 --- a/readconf.h +++ b/readconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: readconf.h,v 1.129 2018/11/23 05:08:07 djm Exp $ */ | 1 | /* $OpenBSD: readconf.h,v 1.130 2019/10/31 21:18:28 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -82,6 +82,7 @@ typedef struct { | |||
82 | char *bind_address; /* local socket address for connection to sshd */ | 82 | char *bind_address; /* local socket address for connection to sshd */ |
83 | char *bind_interface; /* local interface for bind address */ | 83 | char *bind_interface; /* local interface for bind address */ |
84 | char *pkcs11_provider; /* PKCS#11 provider */ | 84 | char *pkcs11_provider; /* PKCS#11 provider */ |
85 | char *sk_provider; /* Security key provider */ | ||
85 | int verify_host_key_dns; /* Verify host key using DNS */ | 86 | int verify_host_key_dns; /* Verify host key using DNS */ |
86 | 87 | ||
87 | int num_identity_files; /* Number of files for RSA/DSA identities. */ | 88 | int num_identity_files; /* Number of files for RSA/DSA identities. */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.507 2019/09/13 04:27:35 djm Exp $ */ | 1 | /* $OpenBSD: ssh.c,v 1.508 2019/10/31 21:18:28 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -1344,6 +1344,22 @@ main(int ac, char **av) | |||
1344 | exit(0); | 1344 | exit(0); |
1345 | } | 1345 | } |
1346 | 1346 | ||
1347 | /* Expand SecurityKeyProvider if it refers to an environment variable */ | ||
1348 | if (options.sk_provider != NULL && *options.sk_provider == '$' && | ||
1349 | strlen(options.sk_provider) > 1) { | ||
1350 | if ((cp = getenv(options.sk_provider + 1)) == NULL) { | ||
1351 | debug("Security key provider %s did not resolve; " | ||
1352 | "disabling", options.sk_provider); | ||
1353 | free(options.sk_provider); | ||
1354 | options.sk_provider = NULL; | ||
1355 | } else { | ||
1356 | debug2("resolved SecurityKeyProvider %s => %s", | ||
1357 | options.sk_provider, cp); | ||
1358 | free(options.sk_provider); | ||
1359 | options.sk_provider = xstrdup(cp); | ||
1360 | } | ||
1361 | } | ||
1362 | |||
1347 | if (muxclient_command != 0 && options.control_path == NULL) | 1363 | if (muxclient_command != 0 && options.control_path == NULL) |
1348 | fatal("No ControlPath specified for \"-O\" command"); | 1364 | fatal("No ControlPath specified for \"-O\" command"); |
1349 | if (options.control_path != NULL) { | 1365 | if (options.control_path != NULL) { |
diff --git a/sshconnect2.c b/sshconnect2.c index 87fa70a40..62f0c3e76 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.308 2019/08/05 11:50:33 dtucker Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.309 2019/10/31 21:18:28 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2008 Damien Miller. All rights reserved. |
@@ -72,6 +72,7 @@ | |||
72 | #include "hostfile.h" | 72 | #include "hostfile.h" |
73 | #include "ssherr.h" | 73 | #include "ssherr.h" |
74 | #include "utf8.h" | 74 | #include "utf8.h" |
75 | #include "ssh-sk.h" | ||
75 | 76 | ||
76 | #ifdef GSSAPI | 77 | #ifdef GSSAPI |
77 | #include "ssh-gss.h" | 78 | #include "ssh-gss.h" |
@@ -601,17 +602,23 @@ static char * | |||
601 | format_identity(Identity *id) | 602 | format_identity(Identity *id) |
602 | { | 603 | { |
603 | char *fp = NULL, *ret = NULL; | 604 | char *fp = NULL, *ret = NULL; |
605 | const char *note = ""; | ||
604 | 606 | ||
605 | if (id->key != NULL) { | 607 | if (id->key != NULL) { |
606 | fp = sshkey_fingerprint(id->key, options.fingerprint_hash, | 608 | fp = sshkey_fingerprint(id->key, options.fingerprint_hash, |
607 | SSH_FP_DEFAULT); | 609 | SSH_FP_DEFAULT); |
608 | } | 610 | } |
611 | if (id->key) { | ||
612 | if ((id->key->flags & SSHKEY_FLAG_EXT) != 0) | ||
613 | note = " token"; | ||
614 | else if (sshkey_type_plain(id->key->type) == KEY_ECDSA_SK) | ||
615 | note = " security-key"; | ||
616 | } | ||
609 | xasprintf(&ret, "%s %s%s%s%s%s%s", | 617 | xasprintf(&ret, "%s %s%s%s%s%s%s", |
610 | id->filename, | 618 | id->filename, |
611 | id->key ? sshkey_type(id->key) : "", id->key ? " " : "", | 619 | id->key ? sshkey_type(id->key) : "", id->key ? " " : "", |
612 | fp ? fp : "", | 620 | fp ? fp : "", |
613 | id->userprovided ? " explicit" : "", | 621 | id->userprovided ? " explicit" : "", note, |
614 | (id->key && (id->key->flags & SSHKEY_FLAG_EXT)) ? " token" : "", | ||
615 | id->agent_fd != -1 ? " agent" : ""); | 622 | id->agent_fd != -1 ? " agent" : ""); |
616 | free(fp); | 623 | free(fp); |
617 | return ret; | 624 | return ret; |
@@ -1140,8 +1147,11 @@ static int | |||
1140 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, | 1147 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, |
1141 | const u_char *data, size_t datalen, u_int compat, const char *alg) | 1148 | const u_char *data, size_t datalen, u_int compat, const char *alg) |
1142 | { | 1149 | { |
1143 | struct sshkey *prv; | 1150 | struct sshkey *sign_key = NULL, *prv = NULL; |
1144 | int r; | 1151 | int r = SSH_ERR_INTERNAL_ERROR; |
1152 | |||
1153 | *sigp = NULL; | ||
1154 | *lenp = 0; | ||
1145 | 1155 | ||
1146 | /* The agent supports this key. */ | 1156 | /* The agent supports this key. */ |
1147 | if (id->key != NULL && id->agent_fd != -1) { | 1157 | if (id->key != NULL && id->agent_fd != -1) { |
@@ -1155,27 +1165,46 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, | |||
1155 | */ | 1165 | */ |
1156 | if (id->key != NULL && | 1166 | if (id->key != NULL && |
1157 | (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) { | 1167 | (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) { |
1158 | if ((r = sshkey_sign(id->key, sigp, lenp, data, datalen, | 1168 | sign_key = id->key; |
1159 | alg, compat)) != 0) | 1169 | } else { |
1160 | return r; | 1170 | /* Load the private key from the file. */ |
1161 | /* | 1171 | if ((prv = load_identity_file(id)) == NULL) |
1162 | * PKCS#11 tokens may not support all signature algorithms, | 1172 | return SSH_ERR_KEY_NOT_FOUND; |
1163 | * so check what we get back. | 1173 | if (id->key != NULL && !sshkey_equal_public(prv, id->key)) { |
1164 | */ | 1174 | error("%s: private key %s contents do not match public", |
1165 | if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) | 1175 | __func__, id->filename); |
1166 | return r; | 1176 | r = SSH_ERR_KEY_NOT_FOUND; |
1167 | return 0; | 1177 | goto out; |
1178 | } | ||
1179 | sign_key = prv; | ||
1168 | } | 1180 | } |
1169 | 1181 | ||
1170 | /* Load the private key from the file. */ | 1182 | if (sshkey_type_plain(sign_key->type) == KEY_ECDSA_SK) { |
1171 | if ((prv = load_identity_file(id)) == NULL) | 1183 | if (options.sk_provider == NULL) { |
1172 | return SSH_ERR_KEY_NOT_FOUND; | 1184 | /* Shouldn't happen here; checked in pubkey_prepare() */ |
1173 | if (id->key != NULL && !sshkey_equal_public(prv, id->key)) { | 1185 | fatal("%s: missing SecurityKeyProvider", __func__); |
1174 | error("%s: private key %s contents do not match public", | 1186 | } |
1175 | __func__, id->filename); | 1187 | if ((r = sshsk_ecdsa_sign(options.sk_provider, sign_key, |
1176 | return SSH_ERR_KEY_NOT_FOUND; | 1188 | sigp, lenp, data, datalen, compat)) != 0) { |
1189 | debug("%s: sshsk_ecdsa_sign: %s", __func__, ssh_err(r)); | ||
1190 | goto out; | ||
1191 | } | ||
1192 | } else if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, | ||
1193 | alg, compat)) != 0) { | ||
1194 | debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); | ||
1195 | goto out; | ||
1177 | } | 1196 | } |
1178 | r = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); | 1197 | /* |
1198 | * PKCS#11 tokens may not support all signature algorithms, | ||
1199 | * so check what we get back. | ||
1200 | */ | ||
1201 | if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) { | ||
1202 | debug("%s: sshkey_check_sigtype: %s", __func__, ssh_err(r)); | ||
1203 | goto out; | ||
1204 | } | ||
1205 | /* success */ | ||
1206 | r = 0; | ||
1207 | out: | ||
1179 | sshkey_free(prv); | 1208 | sshkey_free(prv); |
1180 | return r; | 1209 | return r; |
1181 | } | 1210 | } |
@@ -1450,6 +1479,15 @@ load_identity_file(Identity *id) | |||
1450 | quit = 1; | 1479 | quit = 1; |
1451 | break; | 1480 | break; |
1452 | } | 1481 | } |
1482 | if (private != NULL && | ||
1483 | sshkey_type_plain(private->type) == KEY_ECDSA_SK && | ||
1484 | options.sk_provider == NULL) { | ||
1485 | debug("key \"%s\" is a security key, but no " | ||
1486 | "provider specified", id->filename); | ||
1487 | sshkey_free(private); | ||
1488 | private = NULL; | ||
1489 | quit = 1; | ||
1490 | } | ||
1453 | if (!quit && private != NULL && id->agent_fd == -1 && | 1491 | if (!quit && private != NULL && id->agent_fd == -1 && |
1454 | !(id->key && id->isprivate)) | 1492 | !(id->key && id->isprivate)) |
1455 | maybe_add_key_to_agent(id->filename, private, comment, | 1493 | maybe_add_key_to_agent(id->filename, private, comment, |
@@ -1520,8 +1558,20 @@ pubkey_prepare(Authctxt *authctxt) | |||
1520 | /* list of keys stored in the filesystem and PKCS#11 */ | 1558 | /* list of keys stored in the filesystem and PKCS#11 */ |
1521 | for (i = 0; i < options.num_identity_files; i++) { | 1559 | for (i = 0; i < options.num_identity_files; i++) { |
1522 | key = options.identity_keys[i]; | 1560 | key = options.identity_keys[i]; |
1523 | if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER) | 1561 | if (key && key->cert && |
1562 | key->cert->type != SSH2_CERT_TYPE_USER) { | ||
1563 | debug("%s: ignoring certificate %s: not a user " | ||
1564 | "certificate", __func__, | ||
1565 | options.identity_files[i]); | ||
1566 | continue; | ||
1567 | } | ||
1568 | if (key && sshkey_type_plain(key->type) == KEY_ECDSA_SK && | ||
1569 | options.sk_provider == NULL) { | ||
1570 | debug("%s: ignoring security key %s as no " | ||
1571 | "SecurityKeyProvider has been specified", | ||
1572 | __func__, options.identity_files[i]); | ||
1524 | continue; | 1573 | continue; |
1574 | } | ||
1525 | options.identity_keys[i] = NULL; | 1575 | options.identity_keys[i] = NULL; |
1526 | id = xcalloc(1, sizeof(*id)); | 1576 | id = xcalloc(1, sizeof(*id)); |
1527 | id->agent_fd = -1; | 1577 | id->agent_fd = -1; |
@@ -1534,8 +1584,19 @@ pubkey_prepare(Authctxt *authctxt) | |||
1534 | for (i = 0; i < options.num_certificate_files; i++) { | 1584 | for (i = 0; i < options.num_certificate_files; i++) { |
1535 | key = options.certificates[i]; | 1585 | key = options.certificates[i]; |
1536 | if (!sshkey_is_cert(key) || key->cert == NULL || | 1586 | if (!sshkey_is_cert(key) || key->cert == NULL || |
1537 | key->cert->type != SSH2_CERT_TYPE_USER) | 1587 | key->cert->type != SSH2_CERT_TYPE_USER) { |
1588 | debug("%s: ignoring certificate %s: not a user " | ||
1589 | "certificate", __func__, | ||
1590 | options.identity_files[i]); | ||
1538 | continue; | 1591 | continue; |
1592 | } | ||
1593 | if (key && sshkey_type_plain(key->type) == KEY_ECDSA_SK && | ||
1594 | options.sk_provider == NULL) { | ||
1595 | debug("%s: ignoring security key certificate %s as no " | ||
1596 | "SecurityKeyProvider has been specified", | ||
1597 | __func__, options.identity_files[i]); | ||
1598 | continue; | ||
1599 | } | ||
1539 | id = xcalloc(1, sizeof(*id)); | 1600 | id = xcalloc(1, sizeof(*id)); |
1540 | id->agent_fd = -1; | 1601 | id->agent_fd = -1; |
1541 | id->key = key; | 1602 | id->key = key; |