1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Author: Tatu Ylonen <ylo@cs.hut.fi> 8 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 9 * All rights reserved 10 * The authentication agent program. 11 * 12 * As far as I am concerned, the code I have written for this software 13 * can be used freely for any purpose. Any derived versions of this 14 * software must be clearly marked as such, and if the derived work is 15 * incompatible with the protocol description in the RFC file, it must be 16 * called by a name other than "ssh" or "Secure Shell". 17 * 18 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 19 * 20 * Redistribution and use in source and binary forms, with or without 21 * modification, are permitted provided that the following conditions 22 * are met: 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 2. Redistributions in binary form must reproduce the above copyright 26 * notice, this list of conditions and the following disclaimer in the 27 * documentation and/or other materials provided with the distribution. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 30 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 31 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 32 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 34 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 38 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 #include "includes.h" 42 #include "sys-queue.h" 43 RCSID("$OpenBSD: ssh-agent.c,v 1.159 2008/06/28 14:05:15 djm Exp $"); 44 45 #ifdef HAVE_SOLARIS_PRIVILEGE 46 #include <priv.h> 47 #endif /* HAVE_SOLARIS_PRIVILEGE */ 48 49 #include <openssl/evp.h> 50 #include <openssl/md5.h> 51 52 #include "ssh.h" 53 #include "rsa.h" 54 #include "buffer.h" 55 #include "bufaux.h" 56 #include "xmalloc.h" 57 #include "key.h" 58 #include "authfd.h" 59 #include "compat.h" 60 #include "log.h" 61 #include "readpass.h" 62 #include "misc.h" 63 64 typedef enum { 65 AUTH_UNUSED, 66 AUTH_SOCKET, 67 AUTH_CONNECTION 68 } sock_type; 69 70 typedef struct { 71 int fd; 72 sock_type type; 73 Buffer input; 74 Buffer output; 75 Buffer request; 76 } SocketEntry; 77 78 u_int sockets_alloc = 0; 79 SocketEntry *sockets = NULL; 80 81 typedef struct identity { 82 TAILQ_ENTRY(identity) next; 83 Key *key; 84 char *comment; 85 u_int death; 86 u_int confirm; 87 } Identity; 88 89 typedef struct { 90 int nentries; 91 TAILQ_HEAD(idqueue, identity) idlist; 92 } Idtab; 93 94 /* private key table, one per protocol version */ 95 Idtab idtable[3]; 96 97 int max_fd = 0; 98 99 /* pid of shell == parent of agent */ 100 pid_t parent_pid = -1; 101 u_int parent_alive_interval = 0; 102 103 /* pathname and directory for AUTH_SOCKET */ 104 char socket_name[MAXPATHLEN]; 105 char socket_dir[MAXPATHLEN]; 106 107 /* locking */ 108 int locked = 0; 109 char *lock_passwd = NULL; 110 111 #ifdef HAVE___PROGNAME 112 extern char *__progname; 113 #else 114 char *__progname; 115 #endif 116 117 /* Default lifetime (0 == forever) */ 118 static int lifetime = 0; 119 120 static void 121 close_socket(SocketEntry *e) 122 { 123 close(e->fd); 124 e->fd = -1; 125 e->type = AUTH_UNUSED; 126 buffer_free(&e->input); 127 buffer_free(&e->output); 128 buffer_free(&e->request); 129 } 130 131 static void 132 idtab_init(void) 133 { 134 int i; 135 136 for (i = 0; i <=2; i++) { 137 TAILQ_INIT(&idtable[i].idlist); 138 idtable[i].nentries = 0; 139 } 140 } 141 142 /* return private key table for requested protocol version */ 143 static Idtab * 144 idtab_lookup(int version) 145 { 146 if (version < 1 || version > 2) 147 fatal("internal error, bad protocol version %d", version); 148 return &idtable[version]; 149 } 150 151 static void 152 free_identity(Identity *id) 153 { 154 key_free(id->key); 155 xfree(id->comment); 156 xfree(id); 157 } 158 159 /* return matching private key for given public key */ 160 static Identity * 161 lookup_identity(Key *key, int version) 162 { 163 Identity *id; 164 165 Idtab *tab = idtab_lookup(version); 166 TAILQ_FOREACH(id, &tab->idlist, next) { 167 if (key_equal(key, id->key)) 168 return (id); 169 } 170 return (NULL); 171 } 172 173 /* Check confirmation of keysign request */ 174 static int 175 confirm_key(Identity *id) 176 { 177 char *p; 178 int ret = -1; 179 180 p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); 181 if (ask_permission( 182 gettext("Allow use of key %s?\nKey fingerprint %s."), 183 id->comment, p)) 184 ret = 0; 185 xfree(p); 186 187 return (ret); 188 } 189 190 /* send list of supported public keys to 'client' */ 191 static void 192 process_request_identities(SocketEntry *e, int version) 193 { 194 Idtab *tab = idtab_lookup(version); 195 Identity *id; 196 Buffer msg; 197 198 buffer_init(&msg); 199 buffer_put_char(&msg, (version == 1) ? 200 SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER); 201 buffer_put_int(&msg, tab->nentries); 202 TAILQ_FOREACH(id, &tab->idlist, next) { 203 if (id->key->type == KEY_RSA1) { 204 buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); 205 buffer_put_bignum(&msg, id->key->rsa->e); 206 buffer_put_bignum(&msg, id->key->rsa->n); 207 } else { 208 u_char *blob; 209 u_int blen; 210 key_to_blob(id->key, &blob, &blen); 211 buffer_put_string(&msg, blob, blen); 212 xfree(blob); 213 } 214 buffer_put_cstring(&msg, id->comment); 215 } 216 buffer_put_int(&e->output, buffer_len(&msg)); 217 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); 218 buffer_free(&msg); 219 } 220 221 /* ssh1 only */ 222 static void 223 process_authentication_challenge1(SocketEntry *e) 224 { 225 u_char buf[32], mdbuf[16], session_id[16]; 226 u_int response_type; 227 BIGNUM *challenge; 228 Identity *id; 229 int i, len; 230 Buffer msg; 231 MD5_CTX md; 232 Key *key; 233 234 buffer_init(&msg); 235 key = key_new(KEY_RSA1); 236 if ((challenge = BN_new()) == NULL) 237 fatal("process_authentication_challenge1: BN_new failed"); 238 239 (void) buffer_get_int(&e->request); /* ignored */ 240 buffer_get_bignum(&e->request, key->rsa->e); 241 buffer_get_bignum(&e->request, key->rsa->n); 242 buffer_get_bignum(&e->request, challenge); 243 244 /* Only protocol 1.1 is supported */ 245 if (buffer_len(&e->request) == 0) 246 goto failure; 247 buffer_get(&e->request, session_id, 16); 248 response_type = buffer_get_int(&e->request); 249 if (response_type != 1) 250 goto failure; 251 252 id = lookup_identity(key, 1); 253 if (id != NULL && (!id->confirm || confirm_key(id) == 0)) { 254 Key *private = id->key; 255 /* Decrypt the challenge using the private key. */ 256 if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) 257 goto failure; 258 259 /* The response is MD5 of decrypted challenge plus session id. */ 260 len = BN_num_bytes(challenge); 261 if (len <= 0 || len > 32) { 262 log("process_authentication_challenge: bad challenge length %d", len); 263 goto failure; 264 } 265 memset(buf, 0, 32); 266 BN_bn2bin(challenge, buf + 32 - len); 267 MD5_Init(&md); 268 MD5_Update(&md, buf, 32); 269 MD5_Update(&md, session_id, 16); 270 MD5_Final(mdbuf, &md); 271 272 /* Send the response. */ 273 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE); 274 for (i = 0; i < 16; i++) 275 buffer_put_char(&msg, mdbuf[i]); 276 goto send; 277 } 278 279 failure: 280 /* Unknown identity or protocol error. Send failure. */ 281 buffer_put_char(&msg, SSH_AGENT_FAILURE); 282 send: 283 buffer_put_int(&e->output, buffer_len(&msg)); 284 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); 285 key_free(key); 286 BN_clear_free(challenge); 287 buffer_free(&msg); 288 } 289 290 /* ssh2 only */ 291 static void 292 process_sign_request2(SocketEntry *e) 293 { 294 u_char *blob, *data, *signature = NULL; 295 u_int blen, dlen, slen = 0; 296 extern uint32_t datafellows; 297 int odatafellows; 298 int ok = -1, flags; 299 Buffer msg; 300 Key *key; 301 302 datafellows = 0; 303 304 blob = buffer_get_string(&e->request, &blen); 305 data = buffer_get_string(&e->request, &dlen); 306 307 flags = buffer_get_int(&e->request); 308 odatafellows = datafellows; 309 if (flags & SSH_AGENT_OLD_SIGNATURE) 310 datafellows = SSH_BUG_SIGBLOB; 311 312 key = key_from_blob(blob, blen); 313 if (key != NULL) { 314 Identity *id = lookup_identity(key, 2); 315 if (id != NULL && (!id->confirm || confirm_key(id) == 0)) 316 ok = key_sign(id->key, &signature, &slen, data, dlen); 317 key_free(key); 318 } 319 buffer_init(&msg); 320 if (ok == 0) { 321 buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE); 322 buffer_put_string(&msg, signature, slen); 323 } else { 324 buffer_put_char(&msg, SSH_AGENT_FAILURE); 325 } 326 buffer_put_int(&e->output, buffer_len(&msg)); 327 buffer_append(&e->output, buffer_ptr(&msg), 328 buffer_len(&msg)); 329 buffer_free(&msg); 330 xfree(data); 331 xfree(blob); 332 if (signature != NULL) 333 xfree(signature); 334 datafellows = odatafellows; 335 } 336 337 /* shared */ 338 static void 339 process_remove_identity(SocketEntry *e, int version) 340 { 341 u_int blen, bits; 342 int success = 0; 343 Key *key = NULL; 344 u_char *blob; 345 346 switch (version) { 347 case 1: 348 key = key_new(KEY_RSA1); 349 bits = buffer_get_int(&e->request); 350 buffer_get_bignum(&e->request, key->rsa->e); 351 buffer_get_bignum(&e->request, key->rsa->n); 352 353 if (bits != key_size(key)) 354 log("Warning: identity keysize mismatch: actual %u, announced %u", 355 key_size(key), bits); 356 break; 357 case 2: 358 blob = buffer_get_string(&e->request, &blen); 359 key = key_from_blob(blob, blen); 360 xfree(blob); 361 break; 362 } 363 if (key != NULL) { 364 Identity *id = lookup_identity(key, version); 365 if (id != NULL) { 366 /* 367 * We have this key. Free the old key. Since we 368 * don't want to leave empty slots in the middle of 369 * the array, we actually free the key there and move 370 * all the entries between the empty slot and the end 371 * of the array. 372 */ 373 Idtab *tab = idtab_lookup(version); 374 if (tab->nentries < 1) 375 fatal("process_remove_identity: " 376 "internal error: tab->nentries %d", 377 tab->nentries); 378 TAILQ_REMOVE(&tab->idlist, id, next); 379 free_identity(id); 380 tab->nentries--; 381 success = 1; 382 } 383 key_free(key); 384 } 385 buffer_put_int(&e->output, 1); 386 buffer_put_char(&e->output, 387 success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); 388 } 389 390 static void 391 process_remove_all_identities(SocketEntry *e, int version) 392 { 393 Idtab *tab = idtab_lookup(version); 394 Identity *id; 395 396 /* Loop over all identities and clear the keys. */ 397 for (id = TAILQ_FIRST(&tab->idlist); id; 398 id = TAILQ_FIRST(&tab->idlist)) { 399 TAILQ_REMOVE(&tab->idlist, id, next); 400 free_identity(id); 401 } 402 403 /* Mark that there are no identities. */ 404 tab->nentries = 0; 405 406 /* Send success. */ 407 buffer_put_int(&e->output, 1); 408 buffer_put_char(&e->output, SSH_AGENT_SUCCESS); 409 } 410 411 /* removes expired keys and returns number of seconds until the next expiry */ 412 static u_int 413 reaper(void) 414 { 415 u_int deadline = 0, now = time(NULL); 416 Identity *id, *nxt; 417 int version; 418 Idtab *tab; 419 420 for (version = 1; version < 3; version++) { 421 tab = idtab_lookup(version); 422 for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) { 423 nxt = TAILQ_NEXT(id, next); 424 if (id->death == 0) 425 continue; 426 if (now >= id->death) { 427 debug("expiring key '%s'", id->comment); 428 TAILQ_REMOVE(&tab->idlist, id, next); 429 free_identity(id); 430 tab->nentries--; 431 } else 432 deadline = (deadline == 0) ? id->death : 433 MIN(deadline, id->death); 434 } 435 } 436 if (deadline == 0 || deadline <= now) 437 return 0; 438 else 439 return (deadline - now); 440 } 441 442 static void 443 process_add_identity(SocketEntry *e, int version) 444 { 445 Idtab *tab = idtab_lookup(version); 446 Identity *id; 447 int type, success = 0, death = 0, confirm = 0; 448 char *type_name, *comment; 449 Key *k = NULL; 450 451 switch (version) { 452 case 1: 453 k = key_new_private(KEY_RSA1); 454 (void) buffer_get_int(&e->request); /* ignored */ 455 buffer_get_bignum(&e->request, k->rsa->n); 456 buffer_get_bignum(&e->request, k->rsa->e); 457 buffer_get_bignum(&e->request, k->rsa->d); 458 buffer_get_bignum(&e->request, k->rsa->iqmp); 459 460 /* SSH and SSL have p and q swapped */ 461 buffer_get_bignum(&e->request, k->rsa->q); /* p */ 462 buffer_get_bignum(&e->request, k->rsa->p); /* q */ 463 464 /* Generate additional parameters */ 465 rsa_generate_additional_parameters(k->rsa); 466 break; 467 case 2: 468 type_name = buffer_get_string(&e->request, NULL); 469 type = key_type_from_name(type_name); 470 xfree(type_name); 471 switch (type) { 472 case KEY_DSA: 473 k = key_new_private(type); 474 buffer_get_bignum2(&e->request, k->dsa->p); 475 buffer_get_bignum2(&e->request, k->dsa->q); 476 buffer_get_bignum2(&e->request, k->dsa->g); 477 buffer_get_bignum2(&e->request, k->dsa->pub_key); 478 buffer_get_bignum2(&e->request, k->dsa->priv_key); 479 break; 480 case KEY_RSA: 481 k = key_new_private(type); 482 buffer_get_bignum2(&e->request, k->rsa->n); 483 buffer_get_bignum2(&e->request, k->rsa->e); 484 buffer_get_bignum2(&e->request, k->rsa->d); 485 buffer_get_bignum2(&e->request, k->rsa->iqmp); 486 buffer_get_bignum2(&e->request, k->rsa->p); 487 buffer_get_bignum2(&e->request, k->rsa->q); 488 489 /* Generate additional parameters */ 490 rsa_generate_additional_parameters(k->rsa); 491 break; 492 default: 493 buffer_clear(&e->request); 494 goto send; 495 } 496 break; 497 } 498 /* enable blinding */ 499 switch (k->type) { 500 case KEY_RSA: 501 case KEY_RSA1: 502 if (RSA_blinding_on(k->rsa, NULL) != 1) { 503 error("process_add_identity: RSA_blinding_on failed"); 504 key_free(k); 505 goto send; 506 } 507 break; 508 } 509 comment = buffer_get_string(&e->request, NULL); 510 if (k == NULL) { 511 xfree(comment); 512 goto send; 513 } 514 while (buffer_len(&e->request)) { 515 switch ((type = buffer_get_char(&e->request))) { 516 case SSH_AGENT_CONSTRAIN_LIFETIME: 517 death = time(NULL) + buffer_get_int(&e->request); 518 break; 519 case SSH_AGENT_CONSTRAIN_CONFIRM: 520 confirm = 1; 521 break; 522 default: 523 error("process_add_identity: " 524 "Unknown constraint type %d", type); 525 xfree(comment); 526 key_free(k); 527 goto send; 528 } 529 } 530 success = 1; 531 if (lifetime && !death) 532 death = time(NULL) + lifetime; 533 if ((id = lookup_identity(k, version)) == NULL) { 534 id = xmalloc(sizeof(Identity)); 535 id->key = k; 536 TAILQ_INSERT_TAIL(&tab->idlist, id, next); 537 /* Increment the number of identities. */ 538 tab->nentries++; 539 } else { 540 key_free(k); 541 xfree(id->comment); 542 } 543 id->comment = comment; 544 id->death = death; 545 id->confirm = confirm; 546 send: 547 buffer_put_int(&e->output, 1); 548 buffer_put_char(&e->output, 549 success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); 550 } 551 552 /* XXX todo: encrypt sensitive data with passphrase */ 553 static void 554 process_lock_agent(SocketEntry *e, int lock) 555 { 556 int success = 0; 557 char *passwd; 558 559 passwd = buffer_get_string(&e->request, NULL); 560 if (locked && !lock && strcmp(passwd, lock_passwd) == 0) { 561 locked = 0; 562 memset(lock_passwd, 0, strlen(lock_passwd)); 563 xfree(lock_passwd); 564 lock_passwd = NULL; 565 success = 1; 566 } else if (!locked && lock) { 567 locked = 1; 568 lock_passwd = xstrdup(passwd); 569 success = 1; 570 } 571 memset(passwd, 0, strlen(passwd)); 572 xfree(passwd); 573 574 buffer_put_int(&e->output, 1); 575 buffer_put_char(&e->output, 576 success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); 577 } 578 579 static void 580 no_identities(SocketEntry *e, u_int type) 581 { 582 Buffer msg; 583 584 buffer_init(&msg); 585 buffer_put_char(&msg, 586 (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ? 587 SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER); 588 buffer_put_int(&msg, 0); 589 buffer_put_int(&e->output, buffer_len(&msg)); 590 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); 591 buffer_free(&msg); 592 } 593 594 /* dispatch incoming messages */ 595 596 static void 597 process_message(SocketEntry *e) 598 { 599 u_int msg_len, type; 600 u_char *cp; 601 602 if (buffer_len(&e->input) < 5) 603 return; /* Incomplete message. */ 604 cp = buffer_ptr(&e->input); 605 msg_len = get_u32(cp); 606 if (msg_len > 256 * 1024) { 607 close_socket(e); 608 return; 609 } 610 if (buffer_len(&e->input) < msg_len + 4) 611 return; 612 613 /* move the current input to e->request */ 614 buffer_consume(&e->input, 4); 615 buffer_clear(&e->request); 616 buffer_append(&e->request, buffer_ptr(&e->input), msg_len); 617 buffer_consume(&e->input, msg_len); 618 type = buffer_get_char(&e->request); 619 620 /* check wheter agent is locked */ 621 if (locked && type != SSH_AGENTC_UNLOCK) { 622 buffer_clear(&e->request); 623 switch (type) { 624 case SSH_AGENTC_REQUEST_RSA_IDENTITIES: 625 case SSH2_AGENTC_REQUEST_IDENTITIES: 626 /* send empty lists */ 627 no_identities(e, type); 628 break; 629 default: 630 /* send a fail message for all other request types */ 631 buffer_put_int(&e->output, 1); 632 buffer_put_char(&e->output, SSH_AGENT_FAILURE); 633 } 634 return; 635 } 636 637 debug("type %d", type); 638 switch (type) { 639 case SSH_AGENTC_LOCK: 640 case SSH_AGENTC_UNLOCK: 641 process_lock_agent(e, type == SSH_AGENTC_LOCK); 642 break; 643 /* ssh1 */ 644 case SSH_AGENTC_RSA_CHALLENGE: 645 process_authentication_challenge1(e); 646 break; 647 case SSH_AGENTC_REQUEST_RSA_IDENTITIES: 648 process_request_identities(e, 1); 649 break; 650 case SSH_AGENTC_ADD_RSA_IDENTITY: 651 case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED: 652 process_add_identity(e, 1); 653 break; 654 case SSH_AGENTC_REMOVE_RSA_IDENTITY: 655 process_remove_identity(e, 1); 656 break; 657 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES: 658 process_remove_all_identities(e, 1); 659 break; 660 /* ssh2 */ 661 case SSH2_AGENTC_SIGN_REQUEST: 662 process_sign_request2(e); 663 break; 664 case SSH2_AGENTC_REQUEST_IDENTITIES: 665 process_request_identities(e, 2); 666 break; 667 case SSH2_AGENTC_ADD_IDENTITY: 668 case SSH2_AGENTC_ADD_ID_CONSTRAINED: 669 process_add_identity(e, 2); 670 break; 671 case SSH2_AGENTC_REMOVE_IDENTITY: 672 process_remove_identity(e, 2); 673 break; 674 case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: 675 process_remove_all_identities(e, 2); 676 break; 677 default: 678 /* Unknown message. Respond with failure. */ 679 error("Unknown message %d", type); 680 buffer_clear(&e->request); 681 buffer_put_int(&e->output, 1); 682 buffer_put_char(&e->output, SSH_AGENT_FAILURE); 683 break; 684 } 685 } 686 687 static void 688 new_socket(sock_type type, int fd) 689 { 690 u_int i, old_alloc, new_alloc; 691 692 set_nonblock(fd); 693 694 if (fd > max_fd) 695 max_fd = fd; 696 697 for (i = 0; i < sockets_alloc; i++) 698 if (sockets[i].type == AUTH_UNUSED) { 699 sockets[i].fd = fd; 700 buffer_init(&sockets[i].input); 701 buffer_init(&sockets[i].output); 702 buffer_init(&sockets[i].request); 703 sockets[i].type = type; 704 return; 705 } 706 old_alloc = sockets_alloc; 707 new_alloc = sockets_alloc + 10; 708 sockets = xrealloc(sockets, new_alloc * sizeof(sockets[0])); 709 for (i = old_alloc; i < new_alloc; i++) 710 sockets[i].type = AUTH_UNUSED; 711 sockets_alloc = new_alloc; 712 sockets[old_alloc].fd = fd; 713 buffer_init(&sockets[old_alloc].input); 714 buffer_init(&sockets[old_alloc].output); 715 buffer_init(&sockets[old_alloc].request); 716 sockets[old_alloc].type = type; 717 } 718 719 static int 720 prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp, 721 struct timeval **tvpp) 722 { 723 u_int i, sz, deadline; 724 int n = 0; 725 static struct timeval tv; 726 727 for (i = 0; i < sockets_alloc; i++) { 728 switch (sockets[i].type) { 729 case AUTH_SOCKET: 730 case AUTH_CONNECTION: 731 n = MAX(n, sockets[i].fd); 732 break; 733 case AUTH_UNUSED: 734 break; 735 default: 736 fatal("Unknown socket type %d", sockets[i].type); 737 break; 738 } 739 } 740 741 sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); 742 if (*fdrp == NULL || sz > *nallocp) { 743 if (*fdrp) 744 xfree(*fdrp); 745 if (*fdwp) 746 xfree(*fdwp); 747 *fdrp = xmalloc(sz); 748 *fdwp = xmalloc(sz); 749 *nallocp = sz; 750 } 751 if (n < *fdl) 752 debug("XXX shrink: %d < %d", n, *fdl); 753 *fdl = n; 754 memset(*fdrp, 0, sz); 755 memset(*fdwp, 0, sz); 756 757 for (i = 0; i < sockets_alloc; i++) { 758 switch (sockets[i].type) { 759 case AUTH_SOCKET: 760 case AUTH_CONNECTION: 761 FD_SET(sockets[i].fd, *fdrp); 762 if (buffer_len(&sockets[i].output) > 0) 763 FD_SET(sockets[i].fd, *fdwp); 764 break; 765 default: 766 break; 767 } 768 } 769 deadline = reaper(); 770 if (parent_alive_interval != 0) 771 deadline = (deadline == 0) ? parent_alive_interval : 772 MIN(deadline, parent_alive_interval); 773 if (deadline == 0) { 774 *tvpp = NULL; 775 } else { 776 tv.tv_sec = deadline; 777 tv.tv_usec = 0; 778 *tvpp = &tv; 779 } 780 return (1); 781 } 782 783 static void 784 after_select(fd_set *readset, fd_set *writeset) 785 { 786 struct sockaddr_un sunaddr; 787 socklen_t slen; 788 char buf[1024]; 789 int len, sock; 790 u_int i; 791 uid_t euid; 792 gid_t egid; 793 794 for (i = 0; i < sockets_alloc; i++) 795 switch (sockets[i].type) { 796 case AUTH_UNUSED: 797 break; 798 case AUTH_SOCKET: 799 if (FD_ISSET(sockets[i].fd, readset)) { 800 slen = sizeof(sunaddr); 801 sock = accept(sockets[i].fd, 802 (struct sockaddr *)&sunaddr, &slen); 803 if (sock < 0) { 804 error("accept from AUTH_SOCKET: %s", 805 strerror(errno)); 806 break; 807 } 808 if (getpeereid(sock, &euid, &egid) < 0) { 809 error("getpeereid %d failed: %s", 810 sock, strerror(errno)); 811 close(sock); 812 break; 813 } 814 if ((euid != 0) && (getuid() != euid)) { 815 error("uid mismatch: " 816 "peer euid %u != uid %u", 817 (u_int) euid, (u_int) getuid()); 818 close(sock); 819 break; 820 } 821 new_socket(AUTH_CONNECTION, sock); 822 } 823 break; 824 case AUTH_CONNECTION: 825 if (buffer_len(&sockets[i].output) > 0 && 826 FD_ISSET(sockets[i].fd, writeset)) { 827 do { 828 len = write(sockets[i].fd, 829 buffer_ptr(&sockets[i].output), 830 buffer_len(&sockets[i].output)); 831 if (len == -1 && (errno == EAGAIN || 832 errno == EINTR || 833 errno == EWOULDBLOCK)) 834 continue; 835 break; 836 } while (1); 837 if (len <= 0) { 838 close_socket(&sockets[i]); 839 break; 840 } 841 buffer_consume(&sockets[i].output, len); 842 } 843 if (FD_ISSET(sockets[i].fd, readset)) { 844 do { 845 len = read(sockets[i].fd, buf, sizeof(buf)); 846 if (len == -1 && (errno == EAGAIN || 847 errno == EINTR || 848 errno == EWOULDBLOCK)) 849 continue; 850 break; 851 } while (1); 852 if (len <= 0) { 853 close_socket(&sockets[i]); 854 break; 855 } 856 buffer_append(&sockets[i].input, buf, len); 857 process_message(&sockets[i]); 858 } 859 break; 860 default: 861 fatal("Unknown type %d", sockets[i].type); 862 } 863 } 864 865 static void 866 cleanup_socket(void) 867 { 868 if (socket_name[0]) 869 unlink(socket_name); 870 if (socket_dir[0]) 871 rmdir(socket_dir); 872 } 873 874 void 875 cleanup_exit(int i) 876 { 877 cleanup_socket(); 878 _exit(i); 879 } 880 881 /*ARGSUSED*/ 882 static void 883 cleanup_handler(int sig) 884 { 885 cleanup_socket(); 886 _exit(2); 887 } 888 889 static void 890 check_parent_exists(void) 891 { 892 if (parent_pid != -1 && kill(parent_pid, 0) < 0) { 893 /* printf("Parent has died - Authentication agent exiting.\n"); */ 894 cleanup_socket(); 895 _exit(2); 896 } 897 } 898 899 static void 900 usage(void) 901 { 902 fprintf(stderr, 903 gettext("Usage: %s [options] [command [args ...]]\n" 904 "Options:\n" 905 " -c Generate C-shell commands on stdout.\n" 906 " -s Generate Bourne shell commands on stdout.\n" 907 " -k Kill the current agent.\n" 908 " -d Debug mode.\n" 909 " -a socket Bind agent socket to given name.\n" 910 " -t life Default identity lifetime (seconds).\n"), 911 __progname); 912 exit(1); 913 } 914 915 int 916 main(int ac, char **av) 917 { 918 int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0; 919 int sock, fd, ch, result, saved_errno; 920 u_int nalloc; 921 char *shell, *pidstr, *agentsocket = NULL; 922 const char *format; 923 fd_set *readsetp = NULL, *writesetp = NULL; 924 struct sockaddr_un sunaddr; 925 #ifdef HAVE_SETRLIMIT 926 struct rlimit rlim; 927 #endif 928 int prev_mask; 929 extern int optind; 930 extern char *optarg; 931 pid_t pid; 932 char pidstrbuf[1 + 3 * sizeof pid]; 933 struct timeval *tvp = NULL; 934 #ifdef HAVE_SOLARIS_PRIVILEGE 935 priv_set_t *myprivs; 936 #endif /* HAVE_SOLARIS_PRIVILEGE */ 937 938 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 939 sanitise_stdfd(); 940 941 /* drop */ 942 setegid(getgid()); 943 setgid(getgid()); 944 945 SSLeay_add_all_algorithms(); 946 947 __progname = get_progname(av[0]); 948 init_rng(); 949 seed_rng(); 950 951 while ((ch = getopt(ac, av, "cdksa:t:")) != -1) { 952 switch (ch) { 953 case 'c': 954 if (s_flag) 955 usage(); 956 c_flag++; 957 break; 958 case 'k': 959 k_flag++; 960 break; 961 case 's': 962 if (c_flag) 963 usage(); 964 s_flag++; 965 break; 966 case 'd': 967 if (d_flag) 968 usage(); 969 d_flag++; 970 break; 971 case 'a': 972 agentsocket = optarg; 973 break; 974 case 't': 975 if ((lifetime = convtime(optarg)) == -1) { 976 fprintf(stderr, gettext("Invalid lifetime\n")); 977 usage(); 978 } 979 break; 980 default: 981 usage(); 982 } 983 } 984 ac -= optind; 985 av += optind; 986 987 if (ac > 0 && (c_flag || k_flag || s_flag || d_flag)) 988 usage(); 989 990 if (ac == 0 && !c_flag && !s_flag) { 991 shell = getenv("SHELL"); 992 if (shell != NULL && 993 strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) 994 c_flag = 1; 995 } 996 if (k_flag) { 997 pidstr = getenv(SSH_AGENTPID_ENV_NAME); 998 if (pidstr == NULL) { 999 fprintf(stderr, 1000 gettext("%s not set, cannot kill agent\n"), 1001 SSH_AGENTPID_ENV_NAME); 1002 exit(1); 1003 } 1004 pid = atoi(pidstr); 1005 if (pid < 1) { 1006 fprintf(stderr, 1007 gettext("%s not set, cannot kill agent\n"), 1008 SSH_AGENTPID_ENV_NAME); 1009 exit(1); 1010 } 1011 if (kill(pid, SIGTERM) == -1) { 1012 perror("kill"); 1013 exit(1); 1014 } 1015 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n"; 1016 printf(format, SSH_AUTHSOCKET_ENV_NAME); 1017 printf(format, SSH_AGENTPID_ENV_NAME); 1018 printf("echo "); 1019 printf(gettext("Agent pid %ld killed;\n"), (long)pid); 1020 exit(0); 1021 } 1022 parent_pid = getpid(); 1023 1024 if (agentsocket == NULL) { 1025 /* Create private directory for agent socket */ 1026 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXXXX", sizeof socket_dir); 1027 if (mkdtemp(socket_dir) == NULL) { 1028 perror("mkdtemp: private socket dir"); 1029 exit(1); 1030 } 1031 snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir, 1032 (long)parent_pid); 1033 } else { 1034 /* Try to use specified agent socket */ 1035 socket_dir[0] = '\0'; 1036 strlcpy(socket_name, agentsocket, sizeof socket_name); 1037 } 1038 1039 /* 1040 * Create socket early so it will exist before command gets run from 1041 * the parent. 1042 */ 1043 sock = socket(AF_UNIX, SOCK_STREAM, 0); 1044 if (sock < 0) { 1045 perror("socket"); 1046 *socket_name = '\0'; /* Don't unlink any existing file */ 1047 cleanup_exit(1); 1048 } 1049 memset(&sunaddr, 0, sizeof(sunaddr)); 1050 sunaddr.sun_family = AF_UNIX; 1051 strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path)); 1052 prev_mask = umask(0177); 1053 if (bind(sock, (struct sockaddr *) &sunaddr, sizeof(sunaddr)) < 0) { 1054 perror("bind"); 1055 *socket_name = '\0'; /* Don't unlink any existing file */ 1056 umask(prev_mask); 1057 cleanup_exit(1); 1058 } 1059 umask(prev_mask); 1060 if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { 1061 perror("listen"); 1062 cleanup_exit(1); 1063 } 1064 1065 /* 1066 * Fork, and have the parent execute the command, if any, or present 1067 * the socket data. The child continues as the authentication agent. 1068 */ 1069 if (d_flag) { 1070 log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1); 1071 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; 1072 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, 1073 SSH_AUTHSOCKET_ENV_NAME); 1074 printf("echo "); 1075 printf(gettext("Agent pid %ld;\n"), (long)parent_pid); 1076 goto skip; 1077 } 1078 pid = fork(); 1079 if (pid == -1) { 1080 perror("fork"); 1081 cleanup_exit(1); 1082 } 1083 if (pid != 0) { /* Parent - execute the given command. */ 1084 close(sock); 1085 snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid); 1086 if (ac == 0) { 1087 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; 1088 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, 1089 SSH_AUTHSOCKET_ENV_NAME); 1090 printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf, 1091 SSH_AGENTPID_ENV_NAME); 1092 printf("echo "); 1093 printf(gettext("Agent pid %ld;\n"), (long)pid); 1094 exit(0); 1095 } 1096 if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 || 1097 setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) { 1098 perror("setenv"); 1099 exit(1); 1100 } 1101 execvp(av[0], av); 1102 perror(av[0]); 1103 exit(1); 1104 } 1105 /* child */ 1106 log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0); 1107 1108 #ifdef HAVE_SOLARIS_PRIVILEGE 1109 /* 1110 * Drop unneeded privs, including basic ones like fork/exec. 1111 * 1112 * Idiom: remove from 'basic' privs we know we don't want, 1113 * invert the result and remove the resulting set from P. 1114 * 1115 * None of the priv_delset() calls below, nor the setppriv call 1116 * below can fail, so their return values are not checked. 1117 */ 1118 if ((myprivs = priv_str_to_set("basic", ",", NULL)) == NULL) 1119 fatal("priv_str_to_set failed: %m"); 1120 (void) priv_delset(myprivs, PRIV_PROC_EXEC); 1121 (void) priv_delset(myprivs, PRIV_PROC_FORK); 1122 (void) priv_delset(myprivs, PRIV_FILE_LINK_ANY); 1123 (void) priv_delset(myprivs, PRIV_PROC_INFO); 1124 (void) priv_delset(myprivs, PRIV_PROC_SESSION); 1125 priv_inverse(myprivs); 1126 (void) setppriv(PRIV_OFF, PRIV_PERMITTED, myprivs); 1127 (void) priv_freeset(myprivs); 1128 #endif /* HAVE_SOLARIS_PRIVILEGE */ 1129 1130 if (setsid() == -1) { 1131 error("setsid: %s", strerror(errno)); 1132 cleanup_exit(1); 1133 } 1134 1135 (void)chdir("/"); 1136 if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 1137 /* XXX might close listen socket */ 1138 (void)dup2(fd, STDIN_FILENO); 1139 (void)dup2(fd, STDOUT_FILENO); 1140 (void)dup2(fd, STDERR_FILENO); 1141 if (fd > 2) 1142 close(fd); 1143 } 1144 1145 #ifdef HAVE_SETRLIMIT 1146 /* deny core dumps, since memory contains unencrypted private keys */ 1147 rlim.rlim_cur = rlim.rlim_max = 0; 1148 if (setrlimit(RLIMIT_CORE, &rlim) < 0) { 1149 error("setrlimit RLIMIT_CORE: %s", strerror(errno)); 1150 cleanup_exit(1); 1151 } 1152 #endif 1153 1154 skip: 1155 new_socket(AUTH_SOCKET, sock); 1156 if (ac > 0) 1157 parent_alive_interval = 10; 1158 idtab_init(); 1159 if (!d_flag) 1160 signal(SIGINT, SIG_IGN); 1161 signal(SIGPIPE, SIG_IGN); 1162 signal(SIGHUP, cleanup_handler); 1163 signal(SIGTERM, cleanup_handler); 1164 nalloc = 0; 1165 1166 while (1) { 1167 prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp); 1168 result = select(max_fd + 1, readsetp, writesetp, NULL, tvp); 1169 saved_errno = errno; 1170 if (parent_alive_interval != 0) 1171 check_parent_exists(); 1172 (void) reaper(); /* remove expired keys */ 1173 if (result < 0) { 1174 if (saved_errno == EINTR) 1175 continue; 1176 fatal("select: %s", strerror(saved_errno)); 1177 } else if (result > 0) 1178 after_select(readsetp, writesetp); 1179 } 1180 /* NOTREACHED */ 1181 return (0); /* keep lint happy */ 1182 } 1183