authfd.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. /* $OpenBSD: authfd.c,v 1.124 2020/06/26 05:03:36 djm Exp $ */
  2. /*
  3. * Author: Tatu Ylonen <ylo@cs.hut.fi>
  4. * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  5. * All rights reserved
  6. * Functions for connecting the local authentication agent.
  7. *
  8. * As far as I am concerned, the code I have written for this software
  9. * can be used freely for any purpose. Any derived versions of this
  10. * software must be clearly marked as such, and if the derived work is
  11. * incompatible with the protocol description in the RFC file, it must be
  12. * called by a name other than "ssh" or "Secure Shell".
  13. *
  14. * SSH2 implementation,
  15. * Copyright (c) 2000 Markus Friedl. All rights reserved.
  16. *
  17. * Redistribution and use in source and binary forms, with or without
  18. * modification, are permitted provided that the following conditions
  19. * are met:
  20. * 1. Redistributions of source code must retain the above copyright
  21. * notice, this list of conditions and the following disclaimer.
  22. * 2. Redistributions in binary form must reproduce the above copyright
  23. * notice, this list of conditions and the following disclaimer in the
  24. * documentation and/or other materials provided with the distribution.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  27. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  28. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  29. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  30. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  31. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  32. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  33. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  34. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  35. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. */
  37. #include "includes.h"
  38. #include <sys/types.h>
  39. #include <sys/un.h>
  40. #include <sys/socket.h>
  41. #include <fcntl.h>
  42. #include <stdlib.h>
  43. #include <signal.h>
  44. #include <string.h>
  45. #include <stdarg.h>
  46. #include <unistd.h>
  47. #include <errno.h>
  48. #include "xmalloc.h"
  49. #include "ssh.h"
  50. #include "sshbuf.h"
  51. #include "sshkey.h"
  52. #include "authfd.h"
  53. #include "cipher.h"
  54. #include "compat.h"
  55. #include "log.h"
  56. #include "atomicio.h"
  57. #include "misc.h"
  58. #include "ssherr.h"
  59. #define MAX_AGENT_IDENTITIES 2048 /* Max keys in agent reply */
  60. #define MAX_AGENT_REPLY_LEN (256 * 1024) /* Max bytes in agent reply */
  61. /* macro to check for "agent failure" message */
  62. #define agent_failed(x) \
  63. ((x == SSH_AGENT_FAILURE) || \
  64. (x == SSH_COM_AGENT2_FAILURE) || \
  65. (x == SSH2_AGENT_FAILURE))
  66. /* Convert success/failure response from agent to a err.h status */
  67. static int
  68. decode_reply(u_char type)
  69. {
  70. if (agent_failed(type))
  71. return SSH_ERR_AGENT_FAILURE;
  72. else if (type == SSH_AGENT_SUCCESS)
  73. return 0;
  74. else
  75. return SSH_ERR_INVALID_FORMAT;
  76. }
  77. /*
  78. * Opens an authentication socket at the provided path and stores the file
  79. * descriptor in fdp. Returns 0 on success and an error on failure.
  80. */
  81. int
  82. ssh_get_authentication_socket_path(const char *authsocket, int *fdp)
  83. {
  84. int sock, oerrno;
  85. struct sockaddr_un sunaddr;
  86. memset(&sunaddr, 0, sizeof(sunaddr));
  87. sunaddr.sun_family = AF_UNIX;
  88. strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
  89. if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
  90. return SSH_ERR_SYSTEM_ERROR;
  91. /* close on exec */
  92. if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 ||
  93. connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
  94. oerrno = errno;
  95. close(sock);
  96. errno = oerrno;
  97. return SSH_ERR_SYSTEM_ERROR;
  98. }
  99. if (fdp != NULL)
  100. *fdp = sock;
  101. else
  102. close(sock);
  103. return 0;
  104. }
  105. /*
  106. * Opens the default authentication socket and stores the file descriptor in
  107. * fdp. Returns 0 on success and an error on failure.
  108. */
  109. int
  110. ssh_get_authentication_socket(int *fdp)
  111. {
  112. const char *authsocket;
  113. if (fdp != NULL)
  114. *fdp = -1;
  115. authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
  116. if (authsocket == NULL || *authsocket == '\0')
  117. return SSH_ERR_AGENT_NOT_PRESENT;
  118. return ssh_get_authentication_socket_path(authsocket, fdp);
  119. }
  120. /* Communicate with agent: send request and read reply */
  121. static int
  122. ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply)
  123. {
  124. int r;
  125. size_t l, len;
  126. char buf[1024];
  127. /* Get the length of the message, and format it in the buffer. */
  128. len = sshbuf_len(request);
  129. POKE_U32(buf, len);
  130. /* Send the length and then the packet to the agent. */
  131. if (atomicio(vwrite, sock, buf, 4) != 4 ||
  132. atomicio(vwrite, sock, sshbuf_mutable_ptr(request),
  133. sshbuf_len(request)) != sshbuf_len(request))
  134. return SSH_ERR_AGENT_COMMUNICATION;
  135. /*
  136. * Wait for response from the agent. First read the length of the
  137. * response packet.
  138. */
  139. if (atomicio(read, sock, buf, 4) != 4)
  140. return SSH_ERR_AGENT_COMMUNICATION;
  141. /* Extract the length, and check it for sanity. */
  142. len = PEEK_U32(buf);
  143. if (len > MAX_AGENT_REPLY_LEN)
  144. return SSH_ERR_INVALID_FORMAT;
  145. /* Read the rest of the response in to the buffer. */
  146. sshbuf_reset(reply);
  147. while (len > 0) {
  148. l = len;
  149. if (l > sizeof(buf))
  150. l = sizeof(buf);
  151. if (atomicio(read, sock, buf, l) != l)
  152. return SSH_ERR_AGENT_COMMUNICATION;
  153. if ((r = sshbuf_put(reply, buf, l)) != 0)
  154. return r;
  155. len -= l;
  156. }
  157. return 0;
  158. }
  159. /* Communicate with agent: sent request, read and decode status reply */
  160. static int
  161. ssh_request_reply_decode(int sock, struct sshbuf *request)
  162. {
  163. struct sshbuf *reply;
  164. int r;
  165. u_char type;
  166. if ((reply = sshbuf_new()) == NULL)
  167. return SSH_ERR_ALLOC_FAIL;
  168. if ((r = ssh_request_reply(sock, request, reply)) != 0 ||
  169. (r = sshbuf_get_u8(reply, &type)) != 0 ||
  170. (r = decode_reply(type)) != 0)
  171. goto out;
  172. /* success */
  173. r = 0;
  174. out:
  175. sshbuf_free(reply);
  176. return r;
  177. }
  178. /*
  179. * Closes the agent socket if it should be closed (depends on how it was
  180. * obtained). The argument must have been returned by
  181. * ssh_get_authentication_socket().
  182. */
  183. void
  184. ssh_close_authentication_socket(int sock)
  185. {
  186. if (getenv(SSH_AUTHSOCKET_ENV_NAME))
  187. close(sock);
  188. }
  189. /* Lock/unlock agent */
  190. int
  191. ssh_lock_agent(int sock, int lock, const char *password)
  192. {
  193. int r;
  194. u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK;
  195. struct sshbuf *msg;
  196. if ((msg = sshbuf_new()) == NULL)
  197. return SSH_ERR_ALLOC_FAIL;
  198. if ((r = sshbuf_put_u8(msg, type)) != 0 ||
  199. (r = sshbuf_put_cstring(msg, password)) != 0 ||
  200. (r = ssh_request_reply_decode(sock, msg)) != 0)
  201. goto out;
  202. /* success */
  203. r = 0;
  204. out:
  205. sshbuf_free(msg);
  206. return r;
  207. }
  208. static int
  209. deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
  210. {
  211. int r;
  212. char *comment = NULL;
  213. const u_char *blob;
  214. size_t blen;
  215. if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 ||
  216. (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
  217. goto out;
  218. if ((r = sshkey_from_blob(blob, blen, keyp)) != 0)
  219. goto out;
  220. if (commentp != NULL) {
  221. *commentp = comment;
  222. comment = NULL;
  223. }
  224. r = 0;
  225. out:
  226. free(comment);
  227. return r;
  228. }
  229. /*
  230. * Fetch list of identities held by the agent.
  231. */
  232. int
  233. ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp)
  234. {
  235. u_char type;
  236. u_int32_t num, i;
  237. struct sshbuf *msg;
  238. struct ssh_identitylist *idl = NULL;
  239. int r;
  240. /*
  241. * Send a message to the agent requesting for a list of the
  242. * identities it can represent.
  243. */
  244. if ((msg = sshbuf_new()) == NULL)
  245. return SSH_ERR_ALLOC_FAIL;
  246. if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_REQUEST_IDENTITIES)) != 0)
  247. goto out;
  248. if ((r = ssh_request_reply(sock, msg, msg)) != 0)
  249. goto out;
  250. /* Get message type, and verify that we got a proper answer. */
  251. if ((r = sshbuf_get_u8(msg, &type)) != 0)
  252. goto out;
  253. if (agent_failed(type)) {
  254. r = SSH_ERR_AGENT_FAILURE;
  255. goto out;
  256. } else if (type != SSH2_AGENT_IDENTITIES_ANSWER) {
  257. r = SSH_ERR_INVALID_FORMAT;
  258. goto out;
  259. }
  260. /* Get the number of entries in the response and check it for sanity. */
  261. if ((r = sshbuf_get_u32(msg, &num)) != 0)
  262. goto out;
  263. if (num > MAX_AGENT_IDENTITIES) {
  264. r = SSH_ERR_INVALID_FORMAT;
  265. goto out;
  266. }
  267. if (num == 0) {
  268. r = SSH_ERR_AGENT_NO_IDENTITIES;
  269. goto out;
  270. }
  271. /* Deserialise the response into a list of keys/comments */
  272. if ((idl = calloc(1, sizeof(*idl))) == NULL ||
  273. (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL ||
  274. (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) {
  275. r = SSH_ERR_ALLOC_FAIL;
  276. goto out;
  277. }
  278. for (i = 0; i < num;) {
  279. if ((r = deserialise_identity2(msg, &(idl->keys[i]),
  280. &(idl->comments[i]))) != 0) {
  281. if (r == SSH_ERR_KEY_TYPE_UNKNOWN) {
  282. /* Gracefully skip unknown key types */
  283. num--;
  284. continue;
  285. } else
  286. goto out;
  287. }
  288. i++;
  289. }
  290. idl->nkeys = num;
  291. *idlp = idl;
  292. idl = NULL;
  293. r = 0;
  294. out:
  295. sshbuf_free(msg);
  296. if (idl != NULL)
  297. ssh_free_identitylist(idl);
  298. return r;
  299. }
  300. void
  301. ssh_free_identitylist(struct ssh_identitylist *idl)
  302. {
  303. size_t i;
  304. if (idl == NULL)
  305. return;
  306. for (i = 0; i < idl->nkeys; i++) {
  307. if (idl->keys != NULL)
  308. sshkey_free(idl->keys[i]);
  309. if (idl->comments != NULL)
  310. free(idl->comments[i]);
  311. }
  312. free(idl->keys);
  313. free(idl->comments);
  314. free(idl);
  315. }
  316. /*
  317. * Check if the ssh agent has a given key.
  318. * Returns 0 if found, or a negative SSH_ERR_* error code on failure.
  319. */
  320. int
  321. ssh_agent_has_key(int sock, const struct sshkey *key)
  322. {
  323. int r, ret = SSH_ERR_KEY_NOT_FOUND;
  324. size_t i;
  325. struct ssh_identitylist *idlist = NULL;
  326. if ((r = ssh_fetch_identitylist(sock, &idlist)) != 0) {
  327. return r;
  328. }
  329. for (i = 0; i < idlist->nkeys; i++) {
  330. if (sshkey_equal_public(idlist->keys[i], key)) {
  331. ret = 0;
  332. break;
  333. }
  334. }
  335. ssh_free_identitylist(idlist);
  336. return ret;
  337. }
  338. /*
  339. * Sends a challenge (typically from a server via ssh(1)) to the agent,
  340. * and waits for a response from the agent.
  341. * Returns true (non-zero) if the agent gave the correct answer, zero
  342. * otherwise.
  343. */
  344. /* encode signature algorithm in flag bits, so we can keep the msg format */
  345. static u_int
  346. agent_encode_alg(const struct sshkey *key, const char *alg)
  347. {
  348. if (alg != NULL && sshkey_type_plain(key->type) == KEY_RSA) {
  349. if (strcmp(alg, "rsa-sha2-256") == 0 ||
  350. strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0)
  351. return SSH_AGENT_RSA_SHA2_256;
  352. if (strcmp(alg, "rsa-sha2-512") == 0 ||
  353. strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0)
  354. return SSH_AGENT_RSA_SHA2_512;
  355. }
  356. return 0;
  357. }
  358. /* ask agent to sign data, returns err.h code on error, 0 on success */
  359. int
  360. ssh_agent_sign(int sock, const struct sshkey *key,
  361. u_char **sigp, size_t *lenp,
  362. const u_char *data, size_t datalen, const char *alg, u_int compat)
  363. {
  364. struct sshbuf *msg;
  365. u_char *sig = NULL, type = 0;
  366. size_t len = 0;
  367. u_int flags = 0;
  368. int r = SSH_ERR_INTERNAL_ERROR;
  369. *sigp = NULL;
  370. *lenp = 0;
  371. if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
  372. return SSH_ERR_INVALID_ARGUMENT;
  373. if ((msg = sshbuf_new()) == NULL)
  374. return SSH_ERR_ALLOC_FAIL;
  375. flags |= agent_encode_alg(key, alg);
  376. if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 ||
  377. (r = sshkey_puts(key, msg)) != 0 ||
  378. (r = sshbuf_put_string(msg, data, datalen)) != 0 ||
  379. (r = sshbuf_put_u32(msg, flags)) != 0)
  380. goto out;
  381. if ((r = ssh_request_reply(sock, msg, msg)) != 0)
  382. goto out;
  383. if ((r = sshbuf_get_u8(msg, &type)) != 0)
  384. goto out;
  385. if (agent_failed(type)) {
  386. r = SSH_ERR_AGENT_FAILURE;
  387. goto out;
  388. } else if (type != SSH2_AGENT_SIGN_RESPONSE) {
  389. r = SSH_ERR_INVALID_FORMAT;
  390. goto out;
  391. }
  392. if ((r = sshbuf_get_string(msg, &sig, &len)) != 0)
  393. goto out;
  394. /* Check what we actually got back from the agent. */
  395. if ((r = sshkey_check_sigtype(sig, len, alg)) != 0)
  396. goto out;
  397. /* success */
  398. *sigp = sig;
  399. *lenp = len;
  400. sig = NULL;
  401. len = 0;
  402. r = 0;
  403. out:
  404. freezero(sig, len);
  405. sshbuf_free(msg);
  406. return r;
  407. }
  408. /* Encode key for a message to the agent. */
  409. static int
  410. encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign,
  411. const char *provider)
  412. {
  413. int r;
  414. if (life != 0) {
  415. if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 ||
  416. (r = sshbuf_put_u32(m, life)) != 0)
  417. goto out;
  418. }
  419. if (confirm != 0) {
  420. if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0)
  421. goto out;
  422. }
  423. if (maxsign != 0) {
  424. if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_MAXSIGN)) != 0 ||
  425. (r = sshbuf_put_u32(m, maxsign)) != 0)
  426. goto out;
  427. }
  428. if (provider != NULL) {
  429. if ((r = sshbuf_put_u8(m,
  430. SSH_AGENT_CONSTRAIN_EXTENSION)) != 0 ||
  431. (r = sshbuf_put_cstring(m,
  432. "sk-provider@openssh.com")) != 0 ||
  433. (r = sshbuf_put_cstring(m, provider)) != 0)
  434. goto out;
  435. }
  436. r = 0;
  437. out:
  438. return r;
  439. }
  440. /*
  441. * Adds an identity to the authentication server.
  442. * This call is intended only for use by ssh-add(1) and like applications.
  443. */
  444. int
  445. ssh_add_identity_constrained(int sock, struct sshkey *key,
  446. const char *comment, u_int life, u_int confirm, u_int maxsign,
  447. const char *provider)
  448. {
  449. struct sshbuf *msg;
  450. int r, constrained = (life || confirm || maxsign || provider);
  451. u_char type;
  452. if ((msg = sshbuf_new()) == NULL)
  453. return SSH_ERR_ALLOC_FAIL;
  454. switch (key->type) {
  455. #ifdef WITH_OPENSSL
  456. case KEY_RSA:
  457. case KEY_RSA_CERT:
  458. case KEY_DSA:
  459. case KEY_DSA_CERT:
  460. case KEY_ECDSA:
  461. case KEY_ECDSA_CERT:
  462. case KEY_ECDSA_SK:
  463. case KEY_ECDSA_SK_CERT:
  464. #endif
  465. case KEY_ED25519:
  466. case KEY_ED25519_CERT:
  467. case KEY_ED25519_SK:
  468. case KEY_ED25519_SK_CERT:
  469. case KEY_XMSS:
  470. case KEY_XMSS_CERT:
  471. type = constrained ?
  472. SSH2_AGENTC_ADD_ID_CONSTRAINED :
  473. SSH2_AGENTC_ADD_IDENTITY;
  474. if ((r = sshbuf_put_u8(msg, type)) != 0 ||
  475. (r = sshkey_private_serialize_maxsign(key, msg, maxsign,
  476. NULL)) != 0 ||
  477. (r = sshbuf_put_cstring(msg, comment)) != 0)
  478. goto out;
  479. break;
  480. default:
  481. r = SSH_ERR_INVALID_ARGUMENT;
  482. goto out;
  483. }
  484. if (constrained &&
  485. (r = encode_constraints(msg, life, confirm, maxsign,
  486. provider)) != 0)
  487. goto out;
  488. if ((r = ssh_request_reply_decode(sock, msg)) != 0)
  489. goto out;
  490. /* success */
  491. r = 0;
  492. out:
  493. sshbuf_free(msg);
  494. return r;
  495. }
  496. /*
  497. * Removes an identity from the authentication server.
  498. * This call is intended only for use by ssh-add(1) and like applications.
  499. */
  500. int
  501. ssh_remove_identity(int sock, const struct sshkey *key)
  502. {
  503. struct sshbuf *msg;
  504. int r;
  505. u_char *blob = NULL;
  506. size_t blen;
  507. if ((msg = sshbuf_new()) == NULL)
  508. return SSH_ERR_ALLOC_FAIL;
  509. if (key->type != KEY_UNSPEC) {
  510. if ((r = sshkey_to_blob(key, &blob, &blen)) != 0)
  511. goto out;
  512. if ((r = sshbuf_put_u8(msg,
  513. SSH2_AGENTC_REMOVE_IDENTITY)) != 0 ||
  514. (r = sshbuf_put_string(msg, blob, blen)) != 0)
  515. goto out;
  516. } else {
  517. r = SSH_ERR_INVALID_ARGUMENT;
  518. goto out;
  519. }
  520. if ((r = ssh_request_reply_decode(sock, msg)) != 0)
  521. goto out;
  522. /* success */
  523. r = 0;
  524. out:
  525. if (blob != NULL)
  526. freezero(blob, blen);
  527. sshbuf_free(msg);
  528. return r;
  529. }
  530. /*
  531. * Add/remove an token-based identity from the authentication server.
  532. * This call is intended only for use by ssh-add(1) and like applications.
  533. */
  534. int
  535. ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
  536. u_int life, u_int confirm)
  537. {
  538. struct sshbuf *msg;
  539. int r, constrained = (life || confirm);
  540. u_char type;
  541. if (add) {
  542. type = constrained ?
  543. SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED :
  544. SSH_AGENTC_ADD_SMARTCARD_KEY;
  545. } else
  546. type = SSH_AGENTC_REMOVE_SMARTCARD_KEY;
  547. if ((msg = sshbuf_new()) == NULL)
  548. return SSH_ERR_ALLOC_FAIL;
  549. if ((r = sshbuf_put_u8(msg, type)) != 0 ||
  550. (r = sshbuf_put_cstring(msg, reader_id)) != 0 ||
  551. (r = sshbuf_put_cstring(msg, pin)) != 0)
  552. goto out;
  553. if (constrained &&
  554. (r = encode_constraints(msg, life, confirm, 0, NULL)) != 0)
  555. goto out;
  556. if ((r = ssh_request_reply_decode(sock, msg)) != 0)
  557. goto out;
  558. /* success */
  559. r = 0;
  560. out:
  561. sshbuf_free(msg);
  562. return r;
  563. }
  564. /*
  565. * Removes all identities from the agent.
  566. * This call is intended only for use by ssh-add(1) and like applications.
  567. *
  568. * This supports the SSH protocol 1 message to because, when clearing all
  569. * keys from an agent, we generally want to clear both protocol v1 and v2
  570. * keys.
  571. */
  572. int
  573. ssh_remove_all_identities(int sock, int version)
  574. {
  575. struct sshbuf *msg;
  576. u_char type = (version == 1) ?
  577. SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES :
  578. SSH2_AGENTC_REMOVE_ALL_IDENTITIES;
  579. int r;
  580. if ((msg = sshbuf_new()) == NULL)
  581. return SSH_ERR_ALLOC_FAIL;
  582. if ((r = sshbuf_put_u8(msg, type)) != 0)
  583. goto out;
  584. if ((r = ssh_request_reply_decode(sock, msg)) != 0)
  585. goto out;
  586. /* success */
  587. r = 0;
  588. out:
  589. sshbuf_free(msg);
  590. return r;
  591. }