1 /* $OpenBSD: authfd.c,v 1.94 2015/01/14 20:05:27 djm Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo (at) cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo (at) 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 38 #include "includes.h" 39 40 #include <sys/types.h> 41 #include <sys/un.h> 42 #include <sys/socket.h> 43 44 #include <fcntl.h> 45 #include <stdlib.h> 46 #include <signal.h> 47 #include <stdarg.h> 48 #include <string.h> 49 #include <unistd.h> 50 #include <errno.h> 51 52 #include "xmalloc.h" 53 #include "ssh.h" 54 #include "rsa.h" 55 #include "sshbuf.h" 56 #include "sshkey.h" 57 #include "authfd.h" 58 #include "cipher.h" 59 #include "compat.h" 60 #include "log.h" 61 #include "atomicio.h" 62 #include "misc.h" 63 #include "ssherr.h" 64 65 #define MAX_AGENT_IDENTITIES 2048 /* Max keys in agent reply */ 66 #define MAX_AGENT_REPLY_LEN (256 * 1024) /* Max bytes in agent reply */ 67 68 /* macro to check for "agent failure" message */ 69 #define agent_failed(x) \ 70 ((x == SSH_AGENT_FAILURE) || \ 71 (x == SSH_COM_AGENT2_FAILURE) || \ 72 (x == SSH2_AGENT_FAILURE)) 73 74 /* Convert success/failure response from agent to a err.h status */ 75 static int 76 decode_reply(u_char type) 77 { 78 if (agent_failed(type)) 79 return SSH_ERR_AGENT_FAILURE; 80 else if (type == SSH_AGENT_SUCCESS) 81 return 0; 82 else 83 return SSH_ERR_INVALID_FORMAT; 84 } 85 86 /* Returns the number of the authentication fd, or -1 if there is none. */ 87 int 88 ssh_get_authentication_socket(int *fdp) 89 { 90 const char *authsocket; 91 int sock, oerrno; 92 struct sockaddr_un sunaddr; 93 94 if (fdp != NULL) 95 *fdp = -1; 96 97 authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); 98 if (!authsocket) 99 return SSH_ERR_AGENT_NOT_PRESENT; 100 101 memset(&sunaddr, 0, sizeof(sunaddr)); 102 sunaddr.sun_family = AF_UNIX; 103 strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); 104 105 if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) 106 return SSH_ERR_SYSTEM_ERROR; 107 108 /* close on exec */ 109 if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 || 110 connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { 111 oerrno = errno; 112 close(sock); 113 errno = oerrno; 114 return SSH_ERR_SYSTEM_ERROR; 115 } 116 if (fdp != NULL) 117 *fdp = sock; 118 else 119 close(sock); 120 return 0; 121 } 122 123 /* Communicate with agent: send request and read reply */ 124 static int 125 ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply) 126 { 127 int r; 128 size_t l, len; 129 char buf[1024]; 130 131 /* Get the length of the message, and format it in the buffer. */ 132 len = sshbuf_len(request); 133 put_u32(buf, len); 134 135 /* Send the length and then the packet to the agent. */ 136 if (atomicio(vwrite, sock, buf, 4) != 4 || 137 atomicio(vwrite, sock, (u_char *)sshbuf_ptr(request), 138 sshbuf_len(request)) != sshbuf_len(request)) 139 return SSH_ERR_AGENT_COMMUNICATION; 140 /* 141 * Wait for response from the agent. First read the length of the 142 * response packet. 143 */ 144 if (atomicio(read, sock, buf, 4) != 4) 145 return SSH_ERR_AGENT_COMMUNICATION; 146 147 /* Extract the length, and check it for sanity. */ 148 len = get_u32(buf); 149 if (len > MAX_AGENT_REPLY_LEN) 150 return SSH_ERR_INVALID_FORMAT; 151 152 /* Read the rest of the response in to the buffer. */ 153 sshbuf_reset(reply); 154 while (len > 0) { 155 l = len; 156 if (l > sizeof(buf)) 157 l = sizeof(buf); 158 if (atomicio(read, sock, buf, l) != l) 159 return SSH_ERR_AGENT_COMMUNICATION; 160 if ((r = sshbuf_put(reply, buf, l)) != 0) 161 return r; 162 len -= l; 163 } 164 return 0; 165 } 166 167 /* 168 * Closes the agent socket if it should be closed (depends on how it was 169 * obtained). The argument must have been returned by 170 * ssh_get_authentication_socket(). 171 */ 172 void 173 ssh_close_authentication_socket(int sock) 174 { 175 if (getenv(SSH_AUTHSOCKET_ENV_NAME)) 176 close(sock); 177 } 178 179 /* Lock/unlock agent */ 180 int 181 ssh_lock_agent(int sock, int lock, const char *password) 182 { 183 int r; 184 u_char type = lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK; 185 struct sshbuf *msg; 186 187 if ((msg = sshbuf_new()) == NULL) 188 return SSH_ERR_ALLOC_FAIL; 189 if ((r = sshbuf_put_u8(msg, type)) != 0 || 190 (r = sshbuf_put_cstring(msg, password)) != 0) 191 goto out; 192 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 193 goto out; 194 if ((r = sshbuf_get_u8(msg, &type)) != 0) 195 goto out; 196 r = decode_reply(type); 197 out: 198 sshbuf_free(msg); 199 return r; 200 } 201 202 #ifdef WITH_SSH1 203 static int 204 deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp) 205 { 206 struct sshkey *key; 207 int r, keybits; 208 u_int32_t bits; 209 char *comment = NULL; 210 211 if ((key = sshkey_new(KEY_RSA1)) == NULL) 212 return SSH_ERR_ALLOC_FAIL; 213 if ((r = sshbuf_get_u32(ids, &bits)) != 0 || 214 (r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 || 215 (r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 || 216 (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) 217 goto out; 218 keybits = BN_num_bits(key->rsa->n); 219 /* XXX previously we just warned here. I think we should be strict */ 220 if (keybits < 0 || bits != (u_int)keybits) { 221 r = SSH_ERR_KEY_BITS_MISMATCH; 222 goto out; 223 } 224 if (keyp != NULL) { 225 *keyp = key; 226 key = NULL; 227 } 228 if (commentp != NULL) { 229 *commentp = comment; 230 comment = NULL; 231 } 232 r = 0; 233 out: 234 sshkey_free(key); 235 free(comment); 236 return r; 237 } 238 #endif 239 240 static int 241 deserialise_identity2(struct sshbuf *ids, struct sshkey **keyp, char **commentp) 242 { 243 int r; 244 char *comment = NULL; 245 const u_char *blob; 246 size_t blen; 247 248 if ((r = sshbuf_get_string_direct(ids, &blob, &blen)) != 0 || 249 (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) 250 goto out; 251 if ((r = sshkey_from_blob(blob, blen, keyp)) != 0) 252 goto out; 253 if (commentp != NULL) { 254 *commentp = comment; 255 comment = NULL; 256 } 257 r = 0; 258 out: 259 free(comment); 260 return r; 261 } 262 263 /* 264 * Fetch list of identities held by the agent. 265 */ 266 int 267 ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp) 268 { 269 u_char type, code1 = 0, code2 = 0; 270 u_int32_t num, i; 271 struct sshbuf *msg; 272 struct ssh_identitylist *idl = NULL; 273 int r; 274 275 /* Determine request and expected response types */ 276 switch (version) { 277 case 1: 278 code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; 279 code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER; 280 break; 281 case 2: 282 code1 = SSH2_AGENTC_REQUEST_IDENTITIES; 283 code2 = SSH2_AGENT_IDENTITIES_ANSWER; 284 break; 285 default: 286 return SSH_ERR_INVALID_ARGUMENT; 287 } 288 289 /* 290 * Send a message to the agent requesting for a list of the 291 * identities it can represent. 292 */ 293 if ((msg = sshbuf_new()) == NULL) 294 return SSH_ERR_ALLOC_FAIL; 295 if ((r = sshbuf_put_u8(msg, code1)) != 0) 296 goto out; 297 298 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 299 goto out; 300 301 /* Get message type, and verify that we got a proper answer. */ 302 if ((r = sshbuf_get_u8(msg, &type)) != 0) 303 goto out; 304 if (agent_failed(type)) { 305 r = SSH_ERR_AGENT_FAILURE; 306 goto out; 307 } else if (type != code2) { 308 r = SSH_ERR_INVALID_FORMAT; 309 goto out; 310 } 311 312 /* Get the number of entries in the response and check it for sanity. */ 313 if ((r = sshbuf_get_u32(msg, &num)) != 0) 314 goto out; 315 if (num > MAX_AGENT_IDENTITIES) { 316 r = SSH_ERR_INVALID_FORMAT; 317 goto out; 318 } 319 if (num == 0) { 320 r = SSH_ERR_AGENT_NO_IDENTITIES; 321 goto out; 322 } 323 324 /* Deserialise the response into a list of keys/comments */ 325 if ((idl = calloc(1, sizeof(*idl))) == NULL || 326 (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL || 327 (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) { 328 r = SSH_ERR_ALLOC_FAIL; 329 goto out; 330 } 331 for (i = 0; i < num;) { 332 switch (version) { 333 case 1: 334 #ifdef WITH_SSH1 335 if ((r = deserialise_identity1(msg, 336 &(idl->keys[i]), &(idl->comments[i]))) != 0) 337 goto out; 338 #endif 339 break; 340 case 2: 341 if ((r = deserialise_identity2(msg, 342 &(idl->keys[i]), &(idl->comments[i]))) != 0) { 343 if (r == SSH_ERR_KEY_TYPE_UNKNOWN) { 344 /* Gracefully skip unknown key types */ 345 num--; 346 continue; 347 } else 348 goto out; 349 } 350 break; 351 } 352 i++; 353 } 354 idl->nkeys = num; 355 *idlp = idl; 356 idl = NULL; 357 r = 0; 358 out: 359 sshbuf_free(msg); 360 if (idl != NULL) 361 ssh_free_identitylist(idl); 362 return r; 363 } 364 365 void 366 ssh_free_identitylist(struct ssh_identitylist *idl) 367 { 368 size_t i; 369 370 if (idl == NULL) 371 return; 372 for (i = 0; i < idl->nkeys; i++) { 373 if (idl->keys != NULL) 374 sshkey_free(idl->keys[i]); 375 if (idl->comments != NULL) 376 free(idl->comments[i]); 377 } 378 free(idl); 379 } 380 381 /* 382 * Sends a challenge (typically from a server via ssh(1)) to the agent, 383 * and waits for a response from the agent. 384 * Returns true (non-zero) if the agent gave the correct answer, zero 385 * otherwise. 386 */ 387 388 #ifdef WITH_SSH1 389 int 390 ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, 391 u_char session_id[16], u_char response[16]) 392 { 393 struct sshbuf *msg; 394 int r; 395 u_char type; 396 397 if (key->type != KEY_RSA1) 398 return SSH_ERR_INVALID_ARGUMENT; 399 if ((msg = sshbuf_new()) == NULL) 400 return SSH_ERR_ALLOC_FAIL; 401 if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 || 402 (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || 403 (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || 404 (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 || 405 (r = sshbuf_put_bignum1(msg, challenge)) != 0 || 406 (r = sshbuf_put(msg, session_id, 16)) != 0 || 407 (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */ 408 goto out; 409 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 410 goto out; 411 if ((r = sshbuf_get_u8(msg, &type)) != 0) 412 goto out; 413 if (agent_failed(type)) { 414 r = SSH_ERR_AGENT_FAILURE; 415 goto out; 416 } else if (type != SSH_AGENT_RSA_RESPONSE) { 417 r = SSH_ERR_INVALID_FORMAT; 418 goto out; 419 } 420 if ((r = sshbuf_get(msg, response, 16)) != 0) 421 goto out; 422 r = 0; 423 out: 424 sshbuf_free(msg); 425 return r; 426 } 427 #endif 428 429 /* ask agent to sign data, returns err.h code on error, 0 on success */ 430 int 431 ssh_agent_sign(int sock, struct sshkey *key, 432 u_char **sigp, size_t *lenp, 433 const u_char *data, size_t datalen, u_int compat) 434 { 435 struct sshbuf *msg; 436 u_char *blob = NULL, type; 437 size_t blen = 0, len = 0; 438 u_int flags = 0; 439 int r = SSH_ERR_INTERNAL_ERROR; 440 441 if (sigp != NULL) 442 *sigp = NULL; 443 if (lenp != NULL) 444 *lenp = 0; 445 446 if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) 447 return SSH_ERR_INVALID_ARGUMENT; 448 if (compat & SSH_BUG_SIGBLOB) 449 flags |= SSH_AGENT_OLD_SIGNATURE; 450 if ((msg = sshbuf_new()) == NULL) 451 return SSH_ERR_ALLOC_FAIL; 452 if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) 453 goto out; 454 if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || 455 (r = sshbuf_put_string(msg, blob, blen)) != 0 || 456 (r = sshbuf_put_string(msg, data, datalen)) != 0 || 457 (r = sshbuf_put_u32(msg, flags)) != 0) 458 goto out; 459 if ((r = ssh_request_reply(sock, msg, msg) != 0)) 460 goto out; 461 if ((r = sshbuf_get_u8(msg, &type)) != 0) 462 goto out; 463 if (agent_failed(type)) { 464 r = SSH_ERR_AGENT_FAILURE; 465 goto out; 466 } else if (type != SSH2_AGENT_SIGN_RESPONSE) { 467 r = SSH_ERR_INVALID_FORMAT; 468 goto out; 469 } 470 if ((r = sshbuf_get_string(msg, sigp, &len)) != 0) 471 goto out; 472 *lenp = len; 473 r = 0; 474 out: 475 if (blob != NULL) { 476 explicit_bzero(blob, blen); 477 free(blob); 478 } 479 sshbuf_free(msg); 480 return r; 481 } 482 483 /* Encode key for a message to the agent. */ 484 485 #ifdef WITH_SSH1 486 static int 487 ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment) 488 { 489 int r; 490 491 /* To keep within the protocol: p < q for ssh. in SSL p > q */ 492 if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 || 493 (r = sshbuf_put_bignum1(b, key->n)) != 0 || 494 (r = sshbuf_put_bignum1(b, key->e)) != 0 || 495 (r = sshbuf_put_bignum1(b, key->d)) != 0 || 496 (r = sshbuf_put_bignum1(b, key->iqmp)) != 0 || 497 (r = sshbuf_put_bignum1(b, key->q)) != 0 || 498 (r = sshbuf_put_bignum1(b, key->p)) != 0 || 499 (r = sshbuf_put_cstring(b, comment)) != 0) 500 return r; 501 return 0; 502 } 503 #endif 504 505 static int 506 ssh_encode_identity_ssh2(struct sshbuf *b, struct sshkey *key, 507 const char *comment) 508 { 509 int r; 510 511 if ((r = sshkey_private_serialize(key, b)) != 0 || 512 (r = sshbuf_put_cstring(b, comment)) != 0) 513 return r; 514 return 0; 515 } 516 517 static int 518 encode_constraints(struct sshbuf *m, u_int life, u_int confirm) 519 { 520 int r; 521 522 if (life != 0) { 523 if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_LIFETIME)) != 0 || 524 (r = sshbuf_put_u32(m, life)) != 0) 525 goto out; 526 } 527 if (confirm != 0) { 528 if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0) 529 goto out; 530 } 531 r = 0; 532 out: 533 return r; 534 } 535 536 /* 537 * Adds an identity to the authentication server. 538 * This call is intended only for use by ssh-add(1) and like applications. 539 */ 540 int 541 ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment, 542 u_int life, u_int confirm) 543 { 544 struct sshbuf *msg; 545 int r, constrained = (life || confirm); 546 u_char type; 547 548 if ((msg = sshbuf_new()) == NULL) 549 return SSH_ERR_ALLOC_FAIL; 550 551 switch (key->type) { 552 #ifdef WITH_SSH1 553 case KEY_RSA1: 554 type = constrained ? 555 SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : 556 SSH_AGENTC_ADD_RSA_IDENTITY; 557 if ((r = sshbuf_put_u8(msg, type)) != 0 || 558 (r = ssh_encode_identity_rsa1(msg, key->rsa, comment)) != 0) 559 goto out; 560 break; 561 #endif 562 #ifdef WITH_OPENSSL 563 case KEY_RSA: 564 case KEY_RSA_CERT: 565 case KEY_RSA_CERT_V00: 566 case KEY_DSA: 567 case KEY_DSA_CERT: 568 case KEY_DSA_CERT_V00: 569 case KEY_ECDSA: 570 case KEY_ECDSA_CERT: 571 #endif 572 case KEY_ED25519: 573 case KEY_ED25519_CERT: 574 type = constrained ? 575 SSH2_AGENTC_ADD_ID_CONSTRAINED : 576 SSH2_AGENTC_ADD_IDENTITY; 577 if ((r = sshbuf_put_u8(msg, type)) != 0 || 578 (r = ssh_encode_identity_ssh2(msg, key, comment)) != 0) 579 goto out; 580 break; 581 default: 582 r = SSH_ERR_INVALID_ARGUMENT; 583 goto out; 584 } 585 if (constrained && 586 (r = encode_constraints(msg, life, confirm)) != 0) 587 goto out; 588 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 589 goto out; 590 if ((r = sshbuf_get_u8(msg, &type)) != 0) 591 goto out; 592 r = decode_reply(type); 593 out: 594 sshbuf_free(msg); 595 return r; 596 } 597 598 /* 599 * Removes an identity from the authentication server. 600 * This call is intended only for use by ssh-add(1) and like applications. 601 */ 602 int 603 ssh_remove_identity(int sock, struct sshkey *key) 604 { 605 struct sshbuf *msg; 606 int r; 607 u_char type, *blob = NULL; 608 size_t blen; 609 610 if ((msg = sshbuf_new()) == NULL) 611 return SSH_ERR_ALLOC_FAIL; 612 613 #ifdef WITH_SSH1 614 if (key->type == KEY_RSA1) { 615 if ((r = sshbuf_put_u8(msg, 616 SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 || 617 (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || 618 (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || 619 (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0) 620 goto out; 621 } else 622 #endif 623 if (key->type != KEY_UNSPEC) { 624 if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) 625 goto out; 626 if ((r = sshbuf_put_u8(msg, 627 SSH2_AGENTC_REMOVE_IDENTITY)) != 0 || 628 (r = sshbuf_put_string(msg, blob, blen)) != 0) 629 goto out; 630 } else { 631 r = SSH_ERR_INVALID_ARGUMENT; 632 goto out; 633 } 634 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 635 goto out; 636 if ((r = sshbuf_get_u8(msg, &type)) != 0) 637 goto out; 638 r = decode_reply(type); 639 out: 640 if (blob != NULL) { 641 explicit_bzero(blob, blen); 642 free(blob); 643 } 644 sshbuf_free(msg); 645 return r; 646 } 647 648 /* 649 * Add/remove an token-based identity from the authentication server. 650 * This call is intended only for use by ssh-add(1) and like applications. 651 */ 652 int 653 ssh_update_card(int sock, int add, const char *reader_id, const char *pin, 654 u_int life, u_int confirm) 655 { 656 struct sshbuf *msg; 657 int r, constrained = (life || confirm); 658 u_char type; 659 660 if (add) { 661 type = constrained ? 662 SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED : 663 SSH_AGENTC_ADD_SMARTCARD_KEY; 664 } else 665 type = SSH_AGENTC_REMOVE_SMARTCARD_KEY; 666 667 if ((msg = sshbuf_new()) == NULL) 668 return SSH_ERR_ALLOC_FAIL; 669 if ((r = sshbuf_put_u8(msg, type)) != 0 || 670 (r = sshbuf_put_cstring(msg, reader_id)) != 0 || 671 (r = sshbuf_put_cstring(msg, pin)) != 0) 672 goto out; 673 if (constrained && 674 (r = encode_constraints(msg, life, confirm)) != 0) 675 goto out; 676 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 677 goto out; 678 if ((r = sshbuf_get_u8(msg, &type)) != 0) 679 goto out; 680 r = decode_reply(type); 681 out: 682 sshbuf_free(msg); 683 return r; 684 } 685 686 /* 687 * Removes all identities from the agent. 688 * This call is intended only for use by ssh-add(1) and like applications. 689 */ 690 int 691 ssh_remove_all_identities(int sock, int version) 692 { 693 struct sshbuf *msg; 694 u_char type = (version == 1) ? 695 SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : 696 SSH2_AGENTC_REMOVE_ALL_IDENTITIES; 697 int r; 698 699 if ((msg = sshbuf_new()) == NULL) 700 return SSH_ERR_ALLOC_FAIL; 701 if ((r = sshbuf_put_u8(msg, type)) != 0) 702 goto out; 703 if ((r = ssh_request_reply(sock, msg, msg)) != 0) 704 goto out; 705 if ((r = sshbuf_get_u8(msg, &type)) != 0) 706 goto out; 707 r = decode_reply(type); 708 out: 709 sshbuf_free(msg); 710 return r; 711 } 712