diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 306 |
1 files changed, 198 insertions, 108 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 48882e3a5..804194aab 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.222 2015/01/28 22:36:00 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.223 2015/01/30 11:43:14 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. |
@@ -273,6 +273,8 @@ struct cauthctxt { | |||
273 | int agent_fd; | 273 | int agent_fd; |
274 | /* hostbased */ | 274 | /* hostbased */ |
275 | Sensitive *sensitive; | 275 | Sensitive *sensitive; |
276 | char *oktypes, *ktypes; | ||
277 | const char *active_ktype; | ||
276 | /* kbd-interactive */ | 278 | /* kbd-interactive */ |
277 | int info_req_seen; | 279 | int info_req_seen; |
278 | /* generic */ | 280 | /* generic */ |
@@ -401,6 +403,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, | |||
401 | authctxt.authlist = NULL; | 403 | authctxt.authlist = NULL; |
402 | authctxt.methoddata = NULL; | 404 | authctxt.methoddata = NULL; |
403 | authctxt.sensitive = sensitive; | 405 | authctxt.sensitive = sensitive; |
406 | authctxt.active_ktype = authctxt.oktypes = authctxt.ktypes = NULL; | ||
404 | authctxt.info_req_seen = 0; | 407 | authctxt.info_req_seen = 0; |
405 | authctxt.agent_fd = -1; | 408 | authctxt.agent_fd = -1; |
406 | if (authctxt.method == NULL) | 409 | if (authctxt.method == NULL) |
@@ -1452,78 +1455,116 @@ input_userauth_info_req(int type, u_int32_t seq, void *ctxt) | |||
1452 | } | 1455 | } |
1453 | 1456 | ||
1454 | static int | 1457 | static int |
1455 | ssh_keysign(Key *key, u_char **sigp, u_int *lenp, | 1458 | ssh_keysign(struct sshkey *key, u_char **sigp, size_t *lenp, |
1456 | u_char *data, u_int datalen) | 1459 | const u_char *data, size_t datalen) |
1457 | { | 1460 | { |
1458 | Buffer b; | 1461 | struct sshbuf *b; |
1459 | struct stat st; | 1462 | struct stat st; |
1460 | pid_t pid; | 1463 | pid_t pid; |
1461 | int to[2], from[2], status, version = 2; | 1464 | int i, r, to[2], from[2], status, sock = packet_get_connection_in(); |
1465 | u_char rversion = 0, version = 2; | ||
1466 | void (*osigchld)(int); | ||
1462 | 1467 | ||
1463 | debug2("ssh_keysign called"); | 1468 | *sigp = NULL; |
1469 | *lenp = 0; | ||
1464 | 1470 | ||
1465 | if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { | 1471 | if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { |
1466 | error("ssh_keysign: not installed: %s", strerror(errno)); | 1472 | error("%s: not installed: %s", __func__, strerror(errno)); |
1473 | return -1; | ||
1474 | } | ||
1475 | if (fflush(stdout) != 0) { | ||
1476 | error("%s: fflush: %s", __func__, strerror(errno)); | ||
1467 | return -1; | 1477 | return -1; |
1468 | } | 1478 | } |
1469 | if (fflush(stdout) != 0) | ||
1470 | error("ssh_keysign: fflush: %s", strerror(errno)); | ||
1471 | if (pipe(to) < 0) { | 1479 | if (pipe(to) < 0) { |
1472 | error("ssh_keysign: pipe: %s", strerror(errno)); | 1480 | error("%s: pipe: %s", __func__, strerror(errno)); |
1473 | return -1; | 1481 | return -1; |
1474 | } | 1482 | } |
1475 | if (pipe(from) < 0) { | 1483 | if (pipe(from) < 0) { |
1476 | error("ssh_keysign: pipe: %s", strerror(errno)); | 1484 | error("%s: pipe: %s", __func__, strerror(errno)); |
1477 | return -1; | 1485 | return -1; |
1478 | } | 1486 | } |
1479 | if ((pid = fork()) < 0) { | 1487 | if ((pid = fork()) < 0) { |
1480 | error("ssh_keysign: fork: %s", strerror(errno)); | 1488 | error("%s: fork: %s", __func__, strerror(errno)); |
1481 | return -1; | 1489 | return -1; |
1482 | } | 1490 | } |
1491 | osigchld = signal(SIGCHLD, SIG_DFL); | ||
1483 | if (pid == 0) { | 1492 | if (pid == 0) { |
1484 | /* keep the socket on exec */ | 1493 | /* keep the socket on exec */ |
1485 | fcntl(packet_get_connection_in(), F_SETFD, 0); | 1494 | fcntl(sock, F_SETFD, 0); |
1486 | permanently_drop_suid(getuid()); | 1495 | permanently_drop_suid(getuid()); |
1487 | close(from[0]); | 1496 | close(from[0]); |
1488 | if (dup2(from[1], STDOUT_FILENO) < 0) | 1497 | if (dup2(from[1], STDOUT_FILENO) < 0) |
1489 | fatal("ssh_keysign: dup2: %s", strerror(errno)); | 1498 | fatal("%s: dup2: %s", __func__, strerror(errno)); |
1490 | close(to[1]); | 1499 | close(to[1]); |
1491 | if (dup2(to[0], STDIN_FILENO) < 0) | 1500 | if (dup2(to[0], STDIN_FILENO) < 0) |
1492 | fatal("ssh_keysign: dup2: %s", strerror(errno)); | 1501 | fatal("%s: dup2: %s", __func__, strerror(errno)); |
1493 | close(from[1]); | 1502 | close(from[1]); |
1494 | close(to[0]); | 1503 | close(to[0]); |
1504 | /* Close everything but stdio and the socket */ | ||
1505 | for (i = STDERR_FILENO + 1; i < sock; i++) | ||
1506 | close(i); | ||
1507 | closefrom(sock + 1); | ||
1508 | debug3("%s: [child] pid=%ld, exec %s", | ||
1509 | __func__, (long)getpid(), _PATH_SSH_KEY_SIGN); | ||
1495 | execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); | 1510 | execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); |
1496 | fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN, | 1511 | fatal("%s: exec(%s): %s", __func__, _PATH_SSH_KEY_SIGN, |
1497 | strerror(errno)); | 1512 | strerror(errno)); |
1498 | } | 1513 | } |
1499 | close(from[1]); | 1514 | close(from[1]); |
1500 | close(to[0]); | 1515 | close(to[0]); |
1501 | 1516 | ||
1502 | buffer_init(&b); | 1517 | if ((b = sshbuf_new()) == NULL) |
1503 | buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */ | 1518 | fatal("%s: sshbuf_new failed", __func__); |
1504 | buffer_put_string(&b, data, datalen); | 1519 | /* send # of sock, data to be signed */ |
1505 | if (ssh_msg_send(to[1], version, &b) == -1) | 1520 | if ((r = sshbuf_put_u32(b, sock) != 0) || |
1506 | fatal("ssh_keysign: couldn't send request"); | 1521 | (r = sshbuf_put_string(b, data, datalen)) != 0) |
1507 | 1522 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | |
1508 | if (ssh_msg_recv(from[0], &b) < 0) { | 1523 | if (ssh_msg_send(to[1], version, b) == -1) |
1509 | error("ssh_keysign: no reply"); | 1524 | fatal("%s: couldn't send request", __func__); |
1510 | buffer_free(&b); | 1525 | sshbuf_reset(b); |
1511 | return -1; | 1526 | r = ssh_msg_recv(from[0], b); |
1512 | } | ||
1513 | close(from[0]); | 1527 | close(from[0]); |
1514 | close(to[1]); | 1528 | close(to[1]); |
1529 | if (r < 0) { | ||
1530 | error("%s: no reply", __func__); | ||
1531 | goto fail; | ||
1532 | } | ||
1515 | 1533 | ||
1516 | while (waitpid(pid, &status, 0) < 0) | 1534 | errno = 0; |
1517 | if (errno != EINTR) | 1535 | while (waitpid(pid, &status, 0) < 0) { |
1518 | break; | 1536 | if (errno != EINTR) { |
1519 | 1537 | error("%s: waitpid %ld: %s", | |
1520 | if (buffer_get_char(&b) != version) { | 1538 | __func__, (long)pid, strerror(errno)); |
1521 | error("ssh_keysign: bad version"); | 1539 | goto fail; |
1522 | buffer_free(&b); | 1540 | } |
1541 | } | ||
1542 | if (!WIFEXITED(status)) { | ||
1543 | error("%s: exited abnormally", __func__); | ||
1544 | goto fail; | ||
1545 | } | ||
1546 | if (WEXITSTATUS(status) != 0) { | ||
1547 | error("%s: exited with status %d", | ||
1548 | __func__, WEXITSTATUS(status)); | ||
1549 | goto fail; | ||
1550 | } | ||
1551 | if ((r = sshbuf_get_u8(b, &rversion)) != 0) { | ||
1552 | error("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1553 | goto fail; | ||
1554 | } | ||
1555 | if (rversion != version) { | ||
1556 | error("%s: bad version", __func__); | ||
1557 | goto fail; | ||
1558 | } | ||
1559 | if ((r = sshbuf_get_string(b, sigp, lenp)) != 0) { | ||
1560 | error("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1561 | fail: | ||
1562 | signal(SIGCHLD, osigchld); | ||
1563 | sshbuf_free(b); | ||
1523 | return -1; | 1564 | return -1; |
1524 | } | 1565 | } |
1525 | *sigp = buffer_get_string(&b, lenp); | 1566 | signal(SIGCHLD, osigchld); |
1526 | buffer_free(&b); | 1567 | sshbuf_free(b); |
1527 | 1568 | ||
1528 | return 0; | 1569 | return 0; |
1529 | } | 1570 | } |
@@ -1531,100 +1572,149 @@ ssh_keysign(Key *key, u_char **sigp, u_int *lenp, | |||
1531 | int | 1572 | int |
1532 | userauth_hostbased(Authctxt *authctxt) | 1573 | userauth_hostbased(Authctxt *authctxt) |
1533 | { | 1574 | { |
1534 | Key *private = NULL; | 1575 | struct ssh *ssh = active_state; |
1535 | Sensitive *sensitive = authctxt->sensitive; | 1576 | struct sshkey *private = NULL; |
1536 | Buffer b; | 1577 | struct sshbuf *b = NULL; |
1537 | u_char *signature, *blob; | ||
1538 | char *chost, *pkalg, *p; | ||
1539 | const char *service; | 1578 | const char *service; |
1540 | u_int blen, slen; | 1579 | u_char *sig = NULL, *keyblob = NULL; |
1541 | int ok, i, found = 0; | 1580 | char *fp = NULL, *chost = NULL, *lname = NULL; |
1542 | 1581 | size_t siglen = 0, keylen = 0; | |
1543 | /* XXX provide some way to allow user to specify key types attempted */ | 1582 | int i, r, success = 0; |
1583 | |||
1584 | if (authctxt->ktypes == NULL) { | ||
1585 | authctxt->oktypes = xstrdup(options.hostbased_key_types); | ||
1586 | authctxt->ktypes = authctxt->oktypes; | ||
1587 | } | ||
1544 | 1588 | ||
1545 | /* check for a useful key */ | 1589 | /* |
1546 | for (i = 0; i < sensitive->nkeys; i++) { | 1590 | * Work through each listed type pattern in HostbasedKeyTypes, |
1547 | private = sensitive->keys[i]; | 1591 | * trying each hostkey that matches the type in turn. |
1548 | if (private && private->type != KEY_RSA1) { | 1592 | */ |
1549 | found = 1; | 1593 | for (;;) { |
1594 | if (authctxt->active_ktype == NULL) | ||
1595 | authctxt->active_ktype = strsep(&authctxt->ktypes, ","); | ||
1596 | if (authctxt->active_ktype == NULL || | ||
1597 | *authctxt->active_ktype == '\0') | ||
1598 | break; | ||
1599 | debug3("%s: trying key type %s", __func__, | ||
1600 | authctxt->active_ktype); | ||
1601 | |||
1602 | /* check for a useful key */ | ||
1603 | private = NULL; | ||
1604 | for (i = 0; i < authctxt->sensitive->nkeys; i++) { | ||
1605 | if (authctxt->sensitive->keys[i] == NULL || | ||
1606 | authctxt->sensitive->keys[i]->type == KEY_RSA1 || | ||
1607 | authctxt->sensitive->keys[i]->type == KEY_UNSPEC) | ||
1608 | continue; | ||
1609 | if (match_pattern_list( | ||
1610 | sshkey_ssh_name(authctxt->sensitive->keys[i]), | ||
1611 | authctxt->active_ktype, | ||
1612 | strlen(authctxt->active_ktype), 0) != 1) | ||
1613 | continue; | ||
1550 | /* we take and free the key */ | 1614 | /* we take and free the key */ |
1551 | sensitive->keys[i] = NULL; | 1615 | private = authctxt->sensitive->keys[i]; |
1616 | authctxt->sensitive->keys[i] = NULL; | ||
1552 | break; | 1617 | break; |
1553 | } | 1618 | } |
1619 | /* Found one */ | ||
1620 | if (private != NULL) | ||
1621 | break; | ||
1622 | /* No more keys of this type; advance */ | ||
1623 | authctxt->active_ktype = NULL; | ||
1554 | } | 1624 | } |
1555 | if (!found) { | 1625 | if (private == NULL) { |
1626 | free(authctxt->oktypes); | ||
1627 | authctxt->oktypes = authctxt->ktypes = NULL; | ||
1628 | authctxt->active_ktype = NULL; | ||
1556 | debug("No more client hostkeys for hostbased authentication."); | 1629 | debug("No more client hostkeys for hostbased authentication."); |
1557 | return 0; | 1630 | goto out; |
1558 | } | 1631 | } |
1559 | 1632 | ||
1560 | debug("%s: trying hostkey type %s", __func__, key_type(private)); | 1633 | if ((fp = sshkey_fingerprint(private, options.fingerprint_hash, |
1561 | 1634 | SSH_FP_DEFAULT)) == NULL) { | |
1562 | if (key_to_blob(private, &blob, &blen) == 0) { | 1635 | error("%s: sshkey_fingerprint failed", __func__); |
1563 | key_free(private); | 1636 | goto out; |
1564 | return 0; | ||
1565 | } | 1637 | } |
1638 | debug("%s: trying hostkey %s %s", | ||
1639 | __func__, sshkey_ssh_name(private), fp); | ||
1566 | 1640 | ||
1567 | /* figure out a name for the client host */ | 1641 | /* figure out a name for the client host */ |
1568 | p = get_local_name(packet_get_connection_in()); | 1642 | if ((lname = get_local_name(packet_get_connection_in())) == NULL) { |
1569 | if (p == NULL) { | 1643 | error("%s: cannot get local ipaddr/name", __func__); |
1570 | error("userauth_hostbased: cannot get local ipaddr/name"); | 1644 | goto out; |
1571 | key_free(private); | ||
1572 | free(blob); | ||
1573 | return 0; | ||
1574 | } | 1645 | } |
1575 | xasprintf(&chost, "%s.", p); | 1646 | |
1576 | debug2("userauth_hostbased: chost %s", chost); | 1647 | /* XXX sshbuf_put_stringf? */ |
1577 | free(p); | 1648 | xasprintf(&chost, "%s.", lname); |
1649 | debug2("%s: chost %s", __func__, chost); | ||
1578 | 1650 | ||
1579 | service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : | 1651 | service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : |
1580 | authctxt->service; | 1652 | authctxt->service; |
1581 | pkalg = xstrdup(key_ssh_name(private)); | 1653 | |
1582 | buffer_init(&b); | ||
1583 | /* construct data */ | 1654 | /* construct data */ |
1584 | buffer_put_string(&b, session_id2, session_id2_len); | 1655 | if ((b = sshbuf_new()) == NULL) { |
1585 | buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); | 1656 | error("%s: sshbuf_new failed", __func__); |
1586 | buffer_put_cstring(&b, authctxt->server_user); | 1657 | goto out; |
1587 | buffer_put_cstring(&b, service); | 1658 | } |
1588 | buffer_put_cstring(&b, authctxt->method->name); | 1659 | if ((r = sshkey_to_blob(private, &keyblob, &keylen)) != 0) { |
1589 | buffer_put_cstring(&b, pkalg); | 1660 | error("%s: sshkey_to_blob: %s", __func__, ssh_err(r)); |
1590 | buffer_put_string(&b, blob, blen); | 1661 | goto out; |
1591 | buffer_put_cstring(&b, chost); | 1662 | } |
1592 | buffer_put_cstring(&b, authctxt->local_user); | 1663 | if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || |
1664 | (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || | ||
1665 | (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || | ||
1666 | (r = sshbuf_put_cstring(b, service)) != 0 || | ||
1667 | (r = sshbuf_put_cstring(b, authctxt->method->name)) != 0 || | ||
1668 | (r = sshbuf_put_cstring(b, key_ssh_name(private))) != 0 || | ||
1669 | (r = sshbuf_put_string(b, keyblob, keylen)) != 0 || | ||
1670 | (r = sshbuf_put_cstring(b, chost)) != 0 || | ||
1671 | (r = sshbuf_put_cstring(b, authctxt->local_user)) != 0) { | ||
1672 | error("%s: buffer error: %s", __func__, ssh_err(r)); | ||
1673 | goto out; | ||
1674 | } | ||
1675 | |||
1593 | #ifdef DEBUG_PK | 1676 | #ifdef DEBUG_PK |
1594 | buffer_dump(&b); | 1677 | sshbuf_dump(b, stderr); |
1595 | #endif | 1678 | #endif |
1596 | if (sensitive->external_keysign) | 1679 | if (authctxt->sensitive->external_keysign) |
1597 | ok = ssh_keysign(private, &signature, &slen, | 1680 | r = ssh_keysign(private, &sig, &siglen, |
1598 | buffer_ptr(&b), buffer_len(&b)); | 1681 | sshbuf_ptr(b), sshbuf_len(b)); |
1599 | else | 1682 | else if ((r = sshkey_sign(private, &sig, &siglen, |
1600 | ok = key_sign(private, &signature, &slen, | 1683 | sshbuf_ptr(b), sshbuf_len(b), datafellows)) != 0) |
1601 | buffer_ptr(&b), buffer_len(&b)); | 1684 | debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); |
1602 | key_free(private); | 1685 | if (r != 0) { |
1603 | buffer_free(&b); | 1686 | error("sign using hostkey %s %s failed", |
1604 | if (ok != 0) { | 1687 | sshkey_ssh_name(private), fp); |
1605 | error("key_sign failed"); | 1688 | goto out; |
1606 | free(chost); | ||
1607 | free(pkalg); | ||
1608 | free(blob); | ||
1609 | return 0; | ||
1610 | } | 1689 | } |
1611 | packet_start(SSH2_MSG_USERAUTH_REQUEST); | 1690 | if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || |
1612 | packet_put_cstring(authctxt->server_user); | 1691 | (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || |
1613 | packet_put_cstring(authctxt->service); | 1692 | (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || |
1614 | packet_put_cstring(authctxt->method->name); | 1693 | (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || |
1615 | packet_put_cstring(pkalg); | 1694 | (r = sshpkt_put_cstring(ssh, key_ssh_name(private))) != 0 || |
1616 | packet_put_string(blob, blen); | 1695 | (r = sshpkt_put_string(ssh, keyblob, keylen)) != 0 || |
1617 | packet_put_cstring(chost); | 1696 | (r = sshpkt_put_cstring(ssh, chost)) != 0 || |
1618 | packet_put_cstring(authctxt->local_user); | 1697 | (r = sshpkt_put_cstring(ssh, authctxt->local_user)) != 0 || |
1619 | packet_put_string(signature, slen); | 1698 | (r = sshpkt_put_string(ssh, sig, siglen)) != 0 || |
1620 | explicit_bzero(signature, slen); | 1699 | (r = sshpkt_send(ssh)) != 0) { |
1621 | free(signature); | 1700 | error("%s: packet error: %s", __func__, ssh_err(r)); |
1701 | goto out; | ||
1702 | } | ||
1703 | success = 1; | ||
1704 | |||
1705 | out: | ||
1706 | if (sig != NULL) { | ||
1707 | explicit_bzero(sig, siglen); | ||
1708 | free(sig); | ||
1709 | } | ||
1710 | free(keyblob); | ||
1711 | free(lname); | ||
1712 | free(fp); | ||
1622 | free(chost); | 1713 | free(chost); |
1623 | free(pkalg); | 1714 | sshkey_free(private); |
1624 | free(blob); | 1715 | sshbuf_free(b); |
1625 | 1716 | ||
1626 | packet_send(); | 1717 | return success; |
1627 | return 1; | ||
1628 | } | 1718 | } |
1629 | 1719 | ||
1630 | /* find auth method */ | 1720 | /* find auth method */ |