diff options
| author | itojun <itojun@NetBSD.org> | 2002-04-22 07:35:39 +0000 |
|---|---|---|
| committer | itojun <itojun@NetBSD.org> | 2002-04-22 07:35:39 +0000 |
| commit | f597d4ec88eec42df98aafe9e243a1e2b341ea76 (patch) | |
| tree | c78b50466c1342e27e189b50b98eaf8e5d3b1af9 | |
| parent | e99aada22c711b59adb182fffe2304359e8a3929 (diff) | |
OpenSSH 3.2 as of 2002/4/22. fixes issues with AFS/kerberos auth
30 files changed, 3526 insertions, 280 deletions
diff --git a/crypto/dist/ssh/LICENCE b/crypto/dist/ssh/LICENCE index 1c98a1d621b..2824c09c6a9 100644 --- a/crypto/dist/ssh/LICENCE +++ b/crypto/dist/ssh/LICENCE @@ -190,6 +190,7 @@ OpenSSH contains no GPL code. Aaron Campbell Damien Miller Kevin Steves + Daniel Kouril * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/crypto/dist/ssh/README.smartcard b/crypto/dist/ssh/README.smartcard index 499dc8ed620..4112e12416d 100644 --- a/crypto/dist/ssh/README.smartcard +++ b/crypto/dist/ssh/README.smartcard @@ -4,52 +4,33 @@ OpenSSH contains experimental support for authentication using Cyberflex smartcards and TODOS card readers. To enable this you need to: -(1) install sectok - - $ cd /usr/src/lib/libsectok - $ make obj depend all install includes - $ cd /usr/src/usr.bin/sectok - $ make obj depend all install - -(2) enable SMARTCARD support in OpenSSH: +(1) enable SMARTCARD support in OpenSSH: $ vi /usr/src/usr.bin/ssh/Makefile.inc and uncomment CFLAGS+= -DSMARTCARD LDADD+= -lsectok -(3) load the Java Cardlet to the Cyberflex card: +(2) If you have used a previous version of ssh with your card, you + must remove the old applet and keys. $ sectok sectok> login -d - sectok> jload /usr/libdata/ssh/Ssh.bin + sectok> junload Ssh.bin + sectok> delete 0012 + sectok> delete sh sectok> quit -(4) load a RSA key to the card: - - please don't use your production RSA keys, since - with the current version of sectok/ssh-keygen - the private key file is still readable - - $ ssh-keygen -f /path/to/rsakey -U 1 - (where 1 is the reader number, you can also try 0) - - In spite of the name, this does not generate a key. - It just loads an already existing key on to the card. - -(5) optional: - - Change the card password so that only you can - read the private key: +(3) load the Java Cardlet to the Cyberflex card and set card passphrase: $ sectok sectok> login -d + sectok> jload /usr/libdata/ssh/Ssh.bin sectok> setpass + Enter new AUT0 passphrase: + Re-enter passphrase: sectok> quit - This prevents reading the key but not use of the - key by the card applet. - Do not forget the passphrase. There is no way to recover if you do. @@ -57,13 +38,36 @@ need to: wrong passphrase three times in a row, you will destroy your card. -(6) tell the ssh client to use the card reader: +(4) load a RSA key to the card: + + $ ssh-keygen -f /path/to/rsakey -U 1 + (where 1 is the reader number, you can also try 0) + + In spite of the name, this does not generate a key. + It just loads an already existing key on to the card. + +(5) tell the ssh client to use the card reader: $ ssh -I 1 otherhost -(7) or tell the agent (don't forget to restart) to use the smartcard: +(6) or tell the agent (don't forget to restart) to use the smartcard: $ ssh-add -s 1 +(7) Optional: If you don't want to use a card passphrase, change the + acl on the private key file: + + $ sectok + sectok> login -d + sectok> acl 0012 world: w + world: w + AUT0: w inval + sectok> quit + + If you do this, anyone who has access to your card + can assume your identity. This is not recommended. + -markus, Tue Jul 17 23:54:51 CEST 2001 + +$OpenBSD: README.smartcard,v 1.8 2002/03/26 18:56:23 rees Exp $ diff --git a/crypto/dist/ssh/auth-options.c b/crypto/dist/ssh/auth-options.c index 9cd17e2dbb3..56b540688ed 100644 --- a/crypto/dist/ssh/auth-options.c +++ b/crypto/dist/ssh/auth-options.c @@ -1,4 +1,4 @@ -/* $NetBSD: auth-options.c,v 1.1.1.9 2002/03/08 01:20:30 itojun Exp $ */ +/* $NetBSD: auth-options.c,v 1.1.1.10 2002/04/22 07:35:43 itojun Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -11,7 +11,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-options.c,v 1.21 2002/01/29 14:32:03 markus Exp $"); +RCSID("$OpenBSD: auth-options.c,v 1.23 2002/03/19 10:35:39 markus Exp $"); #include "packet.h" #include "xmalloc.h" @@ -21,7 +21,13 @@ RCSID("$OpenBSD: auth-options.c,v 1.21 2002/01/29 14:32:03 markus Exp $"); #include "channels.h" #include "auth-options.h" #include "servconf.h" +#include "bufaux.h" #include "misc.h" +#include "monitor_wrap.h" + +/* Debugging messages */ +Buffer auth_debug; +int auth_debug_init; /* Flags set authorized_keys flags */ int no_port_forwarding_flag = 0; @@ -37,9 +43,28 @@ struct envstring *custom_environment = NULL; extern ServerOptions options; +static void +auth_send_debug(Buffer *m) +{ + char *msg; + + while (buffer_len(m)) { + msg = buffer_get_string(m, NULL); + packet_send_debug("%s", msg); + xfree(msg); + } +} + void auth_clear_options(void) { + if (auth_debug_init) + buffer_clear(&auth_debug); + else { + buffer_init(&auth_debug); + auth_debug_init = 1; + } + no_agent_forwarding_flag = 0; no_port_forwarding_flag = 0; no_pty_flag = 0; @@ -64,6 +89,7 @@ auth_clear_options(void) int auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) { + char tmp[1024]; const char *cp; int i; @@ -76,28 +102,32 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) while (*opts && *opts != ' ' && *opts != '\t') { cp = "no-port-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { - packet_send_debug("Port forwarding disabled."); + snprintf(tmp, sizeof(tmp), "Port forwarding disabled."); + buffer_put_cstring(&auth_debug, tmp); no_port_forwarding_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-agent-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { - packet_send_debug("Agent forwarding disabled."); + snprintf(tmp, sizeof(tmp), "Agent forwarding disabled."); + buffer_put_cstring(&auth_debug, tmp); no_agent_forwarding_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-X11-forwarding"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { - packet_send_debug("X11 forwarding disabled."); + snprintf(tmp, sizeof(tmp), "X11 forwarding disabled."); + buffer_put_cstring(&auth_debug, tmp); no_x11_forwarding_flag = 1; opts += strlen(cp); goto next_option; } cp = "no-pty"; if (strncasecmp(opts, cp, strlen(cp)) == 0) { - packet_send_debug("Pty allocation disabled."); + snprintf(tmp, sizeof(tmp), "Pty allocation disabled."); + buffer_put_cstring(&auth_debug, tmp); no_pty_flag = 1; opts += strlen(cp); goto next_option; @@ -120,14 +150,16 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", + snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote", file, linenum); + buffer_put_cstring(&auth_debug, tmp); xfree(forced_command); forced_command = NULL; goto bad_option; } forced_command[i] = 0; - packet_send_debug("Forced command: %.900s", forced_command); + snprintf(tmp, sizeof(tmp), "Forced command: %.900s", forced_command); + buffer_put_cstring(&auth_debug, tmp); opts++; goto next_option; } @@ -152,13 +184,15 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", + snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote", file, linenum); + buffer_put_cstring(&auth_debug, tmp); xfree(s); goto bad_option; } s[i] = 0; - packet_send_debug("Adding to environment: %.900s", s); + snprintf(tmp, sizeof(tmp), "Adding to environment: %.900s", s); + buffer_put_cstring(&auth_debug, tmp); debug("Adding to environment: %.900s", s); opts++; new_envstring = xmalloc(sizeof(struct envstring)); @@ -189,8 +223,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", + snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote", file, linenum); + buffer_put_cstring(&auth_debug, tmp); xfree(patterns); goto bad_option; } @@ -203,9 +238,11 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) "correct key but not from a permitted " "host (host=%.200s, ip=%.200s).", pw->pw_name, remote_host, remote_ip); - packet_send_debug("Your host '%.200s' is not " + snprintf(tmp, sizeof(tmp), + "Your host '%.200s' is not " "permitted to use this key for login.", remote_host); + buffer_put_cstring(&auth_debug, tmp); /* deny access */ return 0; } @@ -234,8 +271,9 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) if (!*opts) { debug("%.100s, line %lu: missing end quote", file, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", + snprintf(tmp, sizeof(tmp), "%.100s, line %lu: missing end quote", file, linenum); + buffer_put_cstring(&auth_debug, tmp); xfree(patterns); goto bad_option; } @@ -245,16 +283,18 @@ auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) { debug("%.100s, line %lu: Bad permitopen specification " "<%.100s>", file, linenum, patterns); - packet_send_debug("%.100s, line %lu: " + snprintf(tmp, sizeof(tmp), "%.100s, line %lu: " "Bad permitopen specification", file, linenum); + buffer_put_cstring(&auth_debug, tmp); xfree(patterns); goto bad_option; } if ((port = a2port(sport)) == 0) { debug("%.100s, line %lu: Bad permitopen port <%.100s>", file, linenum, sport); - packet_send_debug("%.100s, line %lu: " + snprintf(tmp, sizeof(tmp), "%.100s, line %lu: " "Bad permitopen port", file, linenum); + buffer_put_cstring(&auth_debug, tmp); xfree(patterns); goto bad_option; } @@ -277,14 +317,24 @@ next_option: opts++; /* Process the next option. */ } + + if (!use_privsep) + auth_send_debug(&auth_debug); + /* grant access */ return 1; bad_option: log("Bad options in %.100s file, line %lu: %.50s", file, linenum, opts); - packet_send_debug("Bad options in %.100s file, line %lu: %.50s", + snprintf(tmp, sizeof(tmp), + "Bad options in %.100s file, line %lu: %.50s", file, linenum, opts); + buffer_put_cstring(&auth_debug, tmp); + + if (!use_privsep) + auth_send_debug(&auth_debug); + /* deny access */ return 0; } diff --git a/crypto/dist/ssh/auth-rh-rsa.c b/crypto/dist/ssh/auth-rh-rsa.c index 81c7dcfd29f..ac596d5ef24 100644 --- a/crypto/dist/ssh/auth-rh-rsa.c +++ b/crypto/dist/ssh/auth-rh-rsa.c @@ -1,4 +1,4 @@ -/* $NetBSD: auth-rh-rsa.c,v 1.1.1.7 2002/03/08 01:20:30 itojun Exp $ */ +/* $NetBSD: auth-rh-rsa.c,v 1.1.1.8 2002/04/22 07:35:43 itojun Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -14,7 +14,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rh-rsa.c,v 1.29 2002/03/04 12:43:06 markus Exp $"); +RCSID("$OpenBSD: auth-rh-rsa.c,v 1.34 2002/03/25 09:25:06 markus Exp $"); #include "packet.h" #include "uidswap.h" @@ -26,37 +26,48 @@ RCSID("$OpenBSD: auth-rh-rsa.c,v 1.29 2002/03/04 12:43:06 markus Exp $"); #include "auth.h" #include "canohost.h" -/* - * Tries to authenticate the user using the .rhosts file and the host using - * its host key. Returns true if authentication succeeds. - */ +#include "monitor_wrap.h" + +/* import */ +extern ServerOptions options; int -auth_rhosts_rsa(struct passwd *pw, const char *client_user, Key *client_host_key) +auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost, + Key *client_host_key) { - extern ServerOptions options; - const char *canonical_hostname; HostStatus host_status; - debug("Trying rhosts with RSA host authentication for client user %.100s", client_user); - - if (pw == NULL || client_host_key == NULL || client_host_key->rsa == NULL) - return 0; - /* Check if we would accept it using rhosts authentication. */ - if (!auth_rhosts(pw, client_user)) + if (!auth_rhosts(pw, cuser)) return 0; - canonical_hostname = get_canonical_hostname( - options.verify_reverse_mapping); - - debug("Rhosts RSA authentication: canonical host %.900s", canonical_hostname); - host_status = check_key_in_hostfiles(pw, client_host_key, - canonical_hostname, _PATH_SSH_SYSTEM_HOSTFILE, + chost, _PATH_SSH_SYSTEM_HOSTFILE, options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); - if (host_status != HOST_OK) { + return (host_status == HOST_OK); +} + +/* + * Tries to authenticate the user using the .rhosts file and the host using + * its host key. Returns true if authentication succeeds. + */ +int +auth_rhosts_rsa(struct passwd *pw, char *cuser, Key *client_host_key) +{ + char *chost; + + debug("Trying rhosts with RSA host authentication for client user %.100s", + cuser); + + if (pw == NULL || client_host_key == NULL || + client_host_key->rsa == NULL) + return 0; + + chost = (char *)get_canonical_hostname(options.verify_reverse_mapping); + debug("Rhosts RSA authentication: canonical host %.900s", chost); + + if (!PRIVSEP(auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key))) { debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); packet_send_debug("Your host key cannot be verified: unknown or invalid host key."); return 0; @@ -64,9 +75,9 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, Key *client_host_key /* A matching host key was found and is known. */ /* Perform the challenge-response dialog with the client for the host key. */ - if (!auth_rsa_challenge_dialog(client_host_key->rsa)) { + if (!auth_rsa_challenge_dialog(client_host_key)) { log("Client on %.800s failed to respond correctly to host authentication.", - canonical_hostname); + chost); return 0; } /* @@ -75,7 +86,7 @@ auth_rhosts_rsa(struct passwd *pw, const char *client_user, Key *client_host_key */ verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.", - pw->pw_name, client_user, canonical_hostname); + pw->pw_name, cuser, chost); packet_send_debug("Rhosts with RSA host authentication accepted."); return 1; } diff --git a/crypto/dist/ssh/auth-rsa.c b/crypto/dist/ssh/auth-rsa.c index 49ec47a8ecd..30c143c7e1c 100644 --- a/crypto/dist/ssh/auth-rsa.c +++ b/crypto/dist/ssh/auth-rsa.c @@ -1,4 +1,4 @@ -/* $NetBSD: auth-rsa.c,v 1.1.1.9 2002/03/08 01:20:30 itojun Exp $ */ +/* $NetBSD: auth-rsa.c,v 1.1.1.10 2002/04/22 07:35:43 itojun Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -15,7 +15,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth-rsa.c,v 1.50 2001/12/28 14:50:54 markus Exp $"); +RCSID("$OpenBSD: auth-rsa.c,v 1.55 2002/03/29 19:18:33 stevesk Exp $"); #include <openssl/rsa.h> #include <openssl/md5.h> @@ -33,6 +33,8 @@ RCSID("$OpenBSD: auth-rsa.c,v 1.50 2001/12/28 14:50:54 markus Exp $"); #include "servconf.h" #include "auth.h" #include "hostfile.h" +#include "monitor_wrap.h" +#include "ssh.h" /* import */ extern ServerOptions options; @@ -53,6 +55,58 @@ extern u_char session_id[16]; * description of the options. */ +BIGNUM * +auth_rsa_generate_challenge(Key *key) +{ + BIGNUM *challenge; + BN_CTX *ctx; + + if ((challenge = BN_new()) == NULL) + fatal("auth_rsa_generate_challenge: BN_new() failed"); + /* Generate a random challenge. */ + BN_rand(challenge, 256, 0, 0); + if ((ctx = BN_CTX_new()) == NULL) + fatal("auth_rsa_generate_challenge: BN_CTX_new() failed"); + BN_mod(challenge, challenge, key->rsa->n, ctx); + BN_CTX_free(ctx); + + return challenge; +} + +int +auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) +{ + u_char buf[32], mdbuf[16]; + MD5_CTX md; + int len; + + /* don't allow short keys */ + if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + error("auth_rsa_verify_response: n too small: %d bits", + BN_num_bits(key->rsa->n)); + return (0); + } + + /* The response is MD5 of decrypted challenge plus session id. */ + len = BN_num_bytes(challenge); + if (len <= 0 || len > 32) + fatal("auth_rsa_verify_response: bad challenge length %d", len); + memset(buf, 0, 32); + BN_bn2bin(challenge, buf + 32 - len); + MD5_Init(&md); + MD5_Update(&md, buf, 32); + MD5_Update(&md, session_id, 16); + MD5_Final(mdbuf, &md); + + /* Verify that the response is the original challenge. */ + if (memcmp(response, mdbuf, 16) != 0) { + /* Wrong answer. */ + return (0); + } + /* Correct answer. */ + return (1); +} + /* * Performs the RSA authentication challenge-response dialog with the client, * and returns true (non-zero) if the client gave the correct answer to @@ -60,29 +114,19 @@ extern u_char session_id[16]; */ int -auth_rsa_challenge_dialog(RSA *pk) +auth_rsa_challenge_dialog(Key *key) { BIGNUM *challenge, *encrypted_challenge; - BN_CTX *ctx; - u_char buf[32], mdbuf[16], response[16]; - MD5_CTX md; - u_int i; - int len; + u_char response[16]; + int i, success; if ((encrypted_challenge = BN_new()) == NULL) fatal("auth_rsa_challenge_dialog: BN_new() failed"); - if ((challenge = BN_new()) == NULL) - fatal("auth_rsa_challenge_dialog: BN_new() failed"); - /* Generate a random challenge. */ - BN_rand(challenge, 256, 0, 0); - if ((ctx = BN_CTX_new()) == NULL) - fatal("auth_rsa_challenge_dialog: BN_CTX_new() failed"); - BN_mod(challenge, challenge, pk->n, ctx); - BN_CTX_free(ctx); + challenge = PRIVSEP(auth_rsa_generate_challenge(key)); /* Encrypt the challenge with the public key. */ - rsa_public_encrypt(encrypted_challenge, challenge, pk); + rsa_public_encrypt(encrypted_challenge, challenge, key->rsa); /* Send the encrypted challenge to the client. */ packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); @@ -97,48 +141,26 @@ auth_rsa_challenge_dialog(RSA *pk) response[i] = packet_get_char(); packet_check_eom(); - /* The response is MD5 of decrypted challenge plus session id. */ - len = BN_num_bytes(challenge); - if (len <= 0 || len > 32) - fatal("auth_rsa_challenge_dialog: bad challenge length %d", len); - memset(buf, 0, 32); - BN_bn2bin(challenge, buf + 32 - len); - MD5_Init(&md); - MD5_Update(&md, buf, 32); - MD5_Update(&md, session_id, 16); - MD5_Final(mdbuf, &md); + success = PRIVSEP(auth_rsa_verify_response(key, challenge, response)); BN_clear_free(challenge); - - /* Verify that the response is the original challenge. */ - if (memcmp(response, mdbuf, 16) != 0) { - /* Wrong answer. */ - return 0; - } - /* Correct answer. */ - return 1; + return (success); } /* - * Performs the RSA authentication dialog with the client. This returns - * 0 if the client could not be authenticated, and 1 if authentication was - * successful. This may exit if there is a serious protocol violation. + * check if there's user key matching client_n, + * return key if login is allowed, NULL otherwise */ int -auth_rsa(struct passwd *pw, BIGNUM *client_n) +auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) { char line[8192], *file; - int authenticated; + int allowed = 0; u_int bits; FILE *f; u_long linenum = 0; struct stat st; Key *key; - char *fp; - - /* no user given */ - if (pw == NULL) - return 0; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); @@ -152,29 +174,27 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) /* Restore the privileged uid. */ restore_uid(); xfree(file); - return 0; + return (0); } /* Open the file containing the authorized keys. */ f = fopen(file, "r"); if (!f) { /* Restore the privileged uid. */ restore_uid(); - packet_send_debug("Could not open %.900s for reading.", file); - packet_send_debug("If your home is on an NFS volume, it may need to be world-readable."); xfree(file); - return 0; + return (0); } if (options.strict_modes && secure_filename(f, file, pw, line, sizeof(line)) != 0) { xfree(file); fclose(f); log("Authentication refused: %s", line); - packet_send_debug("Authentication refused: %s", line); restore_uid(); - return 0; + return (0); } - /* Flag indicating whether authentication has succeeded. */ - authenticated = 0; + + /* Flag indicating whether the key is allowed. */ + allowed = 0; key = key_new(KEY_RSA1); @@ -239,32 +259,8 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) if (!auth_parse_options(pw, options, file, linenum)) continue; - /* Perform the challenge-response dialog for this key. */ - if (!auth_rsa_challenge_dialog(key->rsa)) { - /* Wrong response. */ - verbose("Wrong response to RSA authentication challenge."); - packet_send_debug("Wrong response to RSA authentication challenge."); - /* - * Break out of the loop. Otherwise we might send - * another challenge and break the protocol. - */ - break; - } - /* - * Correct response. The client has been successfully - * authenticated. Note that we have not yet processed the - * options; this will be reset if the options cause the - * authentication to be rejected. - * Break out of the loop if authentication was successful; - * otherwise continue searching. - */ - authenticated = 1; - - fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); - verbose("Found matching %s key: %s", - key_type(key), fp); - xfree(fp); - + /* break out, this key is allowed */ + allowed = 1; break; } @@ -275,13 +271,58 @@ auth_rsa(struct passwd *pw, BIGNUM *client_n) xfree(file); fclose(f); - key_free(key); - - if (authenticated) - packet_send_debug("RSA authentication accepted."); + /* return key if allowed */ + if (allowed && rkey != NULL) + *rkey = key; else + key_free(key); + return (allowed); +} + +/* + * Performs the RSA authentication dialog with the client. This returns + * 0 if the client could not be authenticated, and 1 if authentication was + * successful. This may exit if there is a serious protocol violation. + */ +int +auth_rsa(struct passwd *pw, BIGNUM *client_n) +{ + Key *key; + char *fp; + + /* no user given */ + if (pw == NULL) + return 0; + + if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) { auth_clear_options(); + return (0); + } + + /* Perform the challenge-response dialog for this key. */ + if (!auth_rsa_challenge_dialog(key)) { + /* Wrong response. */ + verbose("Wrong response to RSA authentication challenge."); + packet_send_debug("Wrong response to RSA authentication challenge."); + /* + * Break out of the loop. Otherwise we might send + * another challenge and break the protocol. + */ + key_free(key); + return (0); + } + /* + * Correct response. The client has been successfully + * authenticated. Note that we have not yet processed the + * options; this will be reset if the options cause the + * authentication to be rejected. + */ + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + verbose("Found matching %s key: %s", + key_type(key), fp); + xfree(fp); + key_free(key); - /* Return authentication result. */ - return authenticated; + packet_send_debug("RSA authentication accepted."); + return (1); } diff --git a/crypto/dist/ssh/authfd.h b/crypto/dist/ssh/authfd.h index 6e3fe490cf4..ab920ee0ee8 100644 --- a/crypto/dist/ssh/authfd.h +++ b/crypto/dist/ssh/authfd.h @@ -1,5 +1,5 @@ -/* $NetBSD: authfd.h,v 1.1.1.6 2002/03/08 01:20:32 itojun Exp $ */ -/* $OpenBSD: authfd.h,v 1.23 2002/03/04 17:27:39 stevesk Exp $ */ +/* $NetBSD: authfd.h,v 1.1.1.7 2002/04/22 07:37:18 itojun Exp $ */ +/* $OpenBSD: authfd.h,v 1.24 2002/03/21 22:44:05 rees Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -68,7 +68,7 @@ Key *ssh_get_next_identity(AuthenticationConnection *, char **, int); int ssh_add_identity(AuthenticationConnection *, Key *, const char *); int ssh_remove_identity(AuthenticationConnection *, Key *); int ssh_remove_all_identities(AuthenticationConnection *, int); -int ssh_update_card(AuthenticationConnection *, int, const char *); +int ssh_update_card(AuthenticationConnection *, int, const char *, const char *); int ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16], diff --git a/crypto/dist/ssh/bufaux.c b/crypto/dist/ssh/bufaux.c index 30dbf0e44be..fcfeaf0e054 100644 --- a/crypto/dist/ssh/bufaux.c +++ b/crypto/dist/ssh/bufaux.c @@ -1,4 +1,4 @@ -/* $NetBSD: bufaux.c,v 1.1.1.6 2002/03/08 01:20:34 itojun Exp $ */ +/* $NetBSD: bufaux.c,v 1.1.1.7 2002/04/22 07:37:19 itojun Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -38,7 +38,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: bufaux.c,v 1.22 2002/01/18 18:14:17 stevesk Exp $"); +RCSID("$OpenBSD: bufaux.c,v 1.25 2002/04/20 09:14:58 markus Exp $"); #include <openssl/bn.h> #include "bufaux.h" @@ -138,10 +138,18 @@ buffer_get_bignum2(Buffer *buffer, BIGNUM *value) BN_bin2bn(bin, len, value); xfree(bin); } - /* - * Returns an integer from the buffer (4 bytes, msb first). + * Returns integers from the buffer (msb first). */ + +u_short +buffer_get_short(Buffer *buffer) +{ + u_char buf[2]; + buffer_get(buffer, (char *) buf, 2); + return GET_16BIT(buf); +} + u_int buffer_get_int(Buffer *buffer) { @@ -159,9 +167,17 @@ buffer_get_int64(Buffer *buffer) } /* - * Stores an integer in the buffer in 4 bytes, msb first. + * Stores integers in the buffer, msb first. */ void +buffer_put_short(Buffer *buffer, u_short value) +{ + char buf[2]; + PUT_16BIT(buf, value); + buffer_append(buffer, buf, 2); +} + +void buffer_put_int(Buffer *buffer, u_int value) { char buf[4]; @@ -193,7 +209,7 @@ buffer_get_string(Buffer *buffer, u_int *length_ptr) /* Get the length. */ len = buffer_get_int(buffer); if (len > 256 * 1024) - fatal("Received packet with bad string length %d", len); + fatal("buffer_get_string: bad string length %d", len); /* Allocate space for the string. Add one byte for a null character. */ value = xmalloc(len + 1); /* Get the string. */ @@ -218,6 +234,8 @@ buffer_put_string(Buffer *buffer, const void *buf, u_int len) void buffer_put_cstring(Buffer *buffer, const char *s) { + if (s == NULL) + fatal("buffer_put_cstring: s == NULL"); buffer_put_string(buffer, s, strlen(s)); } diff --git a/crypto/dist/ssh/bufaux.h b/crypto/dist/ssh/bufaux.h index 6a935d0b7a4..b00e28aef32 100644 --- a/crypto/dist/ssh/bufaux.h +++ b/crypto/dist/ssh/bufaux.h @@ -1,5 +1,5 @@ -/* $NetBSD: bufaux.h,v 1.1.1.6 2002/03/08 01:20:34 itojun Exp $ */ -/* $OpenBSD: bufaux.h,v 1.16 2002/03/04 17:27:39 stevesk Exp $ */ +/* $NetBSD: bufaux.h,v 1.1.1.7 2002/04/22 07:37:19 itojun Exp $ */ +/* $OpenBSD: bufaux.h,v 1.18 2002/04/20 09:14:58 markus Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -24,6 +24,9 @@ void buffer_put_bignum2(Buffer *, BIGNUM *); void buffer_get_bignum(Buffer *, BIGNUM *); void buffer_get_bignum2(Buffer *, BIGNUM *); +u_short buffer_get_short(Buffer *); +void buffer_put_short(Buffer *, u_short); + u_int buffer_get_int(Buffer *); void buffer_put_int(Buffer *, u_int); @@ -37,4 +40,7 @@ void *buffer_get_string(Buffer *, u_int *); void buffer_put_string(Buffer *, const void *, u_int); void buffer_put_cstring(Buffer *, const char *); +#define buffer_skip_string(b) \ + do { u_int l = buffer_get_int(b); buffer_consume(b, l); } while(0) + #endif /* BUFAUX_H */ diff --git a/crypto/dist/ssh/cipher.h b/crypto/dist/ssh/cipher.h index 429ed633e85..c9ba15195cf 100644 --- a/crypto/dist/ssh/cipher.h +++ b/crypto/dist/ssh/cipher.h @@ -1,5 +1,5 @@ -/* $NetBSD: cipher.h,v 1.1.1.7 2002/03/08 01:20:41 itojun Exp $ */ -/* $OpenBSD: cipher.h,v 1.32 2002/03/04 17:27:39 stevesk Exp $ */ +/* $NetBSD: cipher.h,v 1.1.1.8 2002/04/22 07:37:23 itojun Exp $ */ +/* $OpenBSD: cipher.h,v 1.33 2002/03/18 17:13:15 markus Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -82,4 +82,11 @@ void cipher_cleanup(CipherContext *); void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); u_int cipher_blocksize(Cipher *); u_int cipher_keylen(Cipher *); + +u_int cipher_get_number(Cipher *); +void cipher_get_keyiv(CipherContext *, u_char *, u_int); +void cipher_set_keyiv(CipherContext *, u_char *); +int cipher_get_keyiv_len(CipherContext *); +int cipher_get_keycontext(CipherContext *, u_char *); +void cipher_set_keycontext(CipherContext *, u_char *); #endif /* CIPHER_H */ diff --git a/crypto/dist/ssh/compat.c b/crypto/dist/ssh/compat.c index cd5698076b6..5058ed4cb5b 100644 --- a/crypto/dist/ssh/compat.c +++ b/crypto/dist/ssh/compat.c @@ -1,4 +1,4 @@ -/* $NetBSD: compat.c,v 1.1.1.10 2002/03/08 01:20:43 itojun Exp $ */ +/* $NetBSD: compat.c,v 1.1.1.11 2002/04/22 07:37:25 itojun Exp $ */ /* * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. * @@ -24,7 +24,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: compat.c,v 1.61 2002/03/06 00:24:39 markus Exp $"); +RCSID("$OpenBSD: compat.c,v 1.63 2002/04/10 08:21:47 markus Exp $"); #include "buffer.h" #include "packet.h" @@ -62,20 +62,26 @@ compat_datafellows(const char *version) "OpenSSH-2.1*," "OpenSSH_2.1*," "OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER| - SSH_OLD_DHGEX|SSH_BUG_NOREKEY }, + SSH_OLD_DHGEX|SSH_BUG_NOREKEY| + SSH_BUG_EXTEOF}, { "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES| - SSH_OLD_DHGEX|SSH_BUG_NOREKEY}, + SSH_OLD_DHGEX|SSH_BUG_NOREKEY| + SSH_BUG_EXTEOF}, { "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| - SSH_BUG_NOREKEY}, + SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, { "OpenSSH_2.5.0p1*," "OpenSSH_2.5.1p1*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| - SSH_BUG_NOREKEY }, + SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, { "OpenSSH_2.5.0*," "OpenSSH_2.5.1*," - "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY }, - { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY }, - { "Sun_SSH_1.0*", SSH_BUG_NOREKEY }, + "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY| + SSH_BUG_EXTEOF}, + { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, + { "OpenSSH_2.*," + "OpenSSH_3.0*," + "OpenSSH_3.1*", SSH_BUG_EXTEOF}, + { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, { "OpenSSH*", 0 }, { "*MindTerm*", 0 }, { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| @@ -122,8 +128,12 @@ compat_datafellows(const char *version) "1.2.19*," "1.2.20*," "1.2.21*," - "1.2.22*", SSH_BUG_IGNOREMSG }, - { "1.3.2*", SSH_BUG_IGNOREMSG }, /* f-secure */ + "1.2.22*", SSH_BUG_IGNOREMSG|SSH_BUG_K5USER }, + { "1.3.2*", /* F-Secure */ + SSH_BUG_IGNOREMSG|SSH_BUG_K5USER }, + { "1.2.1*," + "1.2.2*," + "1.2.3*", SSH_BUG_K5USER }, { "*SSH Compatible Server*", /* Netscreen */ SSH_BUG_PASSWORDPAD }, { "*OSU_0*," diff --git a/crypto/dist/ssh/compat.h b/crypto/dist/ssh/compat.h index 605e72b0746..64453b920a0 100644 --- a/crypto/dist/ssh/compat.h +++ b/crypto/dist/ssh/compat.h @@ -1,5 +1,5 @@ -/* $NetBSD: compat.h,v 1.1.1.9 2002/03/08 01:20:43 itojun Exp $ */ -/* $OpenBSD: compat.h,v 1.30 2002/03/04 17:27:39 stevesk Exp $ */ +/* $NetBSD: compat.h,v 1.1.1.10 2002/04/22 07:37:25 itojun Exp $ */ +/* $OpenBSD: compat.h,v 1.32 2002/04/10 08:21:47 markus Exp $ */ /* * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. @@ -53,6 +53,8 @@ #define SSH_BUG_OPENFAILURE 0x00020000 #define SSH_BUG_DERIVEKEY 0x00040000 #define SSH_BUG_DUMMYCHAN 0x00100000 +#define SSH_BUG_EXTEOF 0x00200000 +#define SSH_BUG_K5USER 0x00400000 void enable_compat13(void); void enable_compat20(void); diff --git a/crypto/dist/ssh/kex.h b/crypto/dist/ssh/kex.h index ca9cc08ceef..499e0640a75 100644 --- a/crypto/dist/ssh/kex.h +++ b/crypto/dist/ssh/kex.h @@ -1,5 +1,5 @@ -/* $NetBSD: kex.h,v 1.1.1.9 2002/03/08 01:20:45 itojun Exp $ */ -/* $OpenBSD: kex.h,v 1.29 2002/02/14 23:41:01 markus Exp $ */ +/* $NetBSD: kex.h,v 1.1.1.10 2002/04/22 07:37:28 itojun Exp $ */ +/* $OpenBSD: kex.h,v 1.30 2002/03/18 17:50:31 provos Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -112,6 +112,7 @@ struct Kex { char *server_version_string; int (*verify_host_key)(Key *); Key *(*load_host_key)(int); + int (*host_key_index)(Key *); }; Kex *kex_setup(char *[PROPOSAL_MAX]); diff --git a/crypto/dist/ssh/key.h b/crypto/dist/ssh/key.h index e4389afeff6..db3387a52f7 100644 --- a/crypto/dist/ssh/key.h +++ b/crypto/dist/ssh/key.h @@ -1,5 +1,5 @@ -/* $NetBSD: key.h,v 1.1.1.8 2002/03/08 01:20:46 itojun Exp $ */ -/* $OpenBSD: key.h,v 1.18 2002/02/24 19:14:59 markus Exp $ */ +/* $NetBSD: key.h,v 1.1.1.9 2002/04/22 07:37:29 itojun Exp $ */ +/* $OpenBSD: key.h,v 1.19 2002/03/18 17:23:31 markus Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -59,6 +59,7 @@ struct Key { Key *key_new(int); Key *key_new_private(int); void key_free(Key *); +Key *key_demote(Key *); int key_equal(Key *, Key *); char *key_fingerprint(Key *, enum fp_type, enum fp_rep); char *key_type(Key *); diff --git a/crypto/dist/ssh/monitor.c b/crypto/dist/ssh/monitor.c new file mode 100644 index 00000000000..a8b14524894 --- /dev/null +++ b/crypto/dist/ssh/monitor.c @@ -0,0 +1,1442 @@ +/* $NetBSD: monitor.c,v 1.1.1.1 2002/04/22 07:38:02 itojun Exp $ */ +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * Copyright 2002 Markus Friedl <markus@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: monitor.c,v 1.9 2002/03/30 18:51:15 markus Exp $"); + +#include <openssl/dh.h> + +#ifdef SKEY +#include <skey.h> +#endif + +#include "ssh.h" +#include "auth.h" +#include "kex.h" +#include "dh.h" +#include "zlib.h" +#include "packet.h" +#include "auth-options.h" +#include "sshpty.h" +#include "channels.h" +#include "session.h" +#include "sshlogin.h" +#include "canohost.h" +#include "log.h" +#include "servconf.h" +#include "monitor.h" +#include "monitor_mm.h" +#include "monitor_wrap.h" +#include "monitor_fdpass.h" +#include "xmalloc.h" +#include "misc.h" +#include "buffer.h" +#include "bufaux.h" +#include "compat.h" +#include "ssh2.h" +#include "mpaux.h" + +/* Imports */ +extern ServerOptions options; +extern u_int utmp_len; +extern Newkeys *current_keys[]; +extern z_stream incoming_stream; +extern z_stream outgoing_stream; +extern u_char session_id[]; +extern Buffer input, output; +extern Buffer auth_debug; +extern int auth_debug_init; + +/* State exported from the child */ + +struct { + z_stream incoming; + z_stream outgoing; + u_char *keyin; + u_int keyinlen; + u_char *keyout; + u_int keyoutlen; + u_char *ivin; + u_int ivinlen; + u_char *ivout; + u_int ivoutlen; + int ssh1cipher; + int ssh1protoflags; + u_char *input; + u_int ilen; + u_char *output; + u_int olen; +} child_state; + +/* Functions on the montior that answer unprivileged requests */ + +int mm_answer_moduli(int, Buffer *); +int mm_answer_sign(int, Buffer *); +int mm_answer_pwnamallow(int, Buffer *); +int mm_answer_authserv(int, Buffer *); +int mm_answer_authpassword(int, Buffer *); +int mm_answer_bsdauthquery(int, Buffer *); +int mm_answer_bsdauthrespond(int, Buffer *); +int mm_answer_skeyquery(int, Buffer *); +int mm_answer_skeyrespond(int, Buffer *); +int mm_answer_keyallowed(int, Buffer *); +int mm_answer_keyverify(int, Buffer *); +int mm_answer_pty(int, Buffer *); +int mm_answer_pty_cleanup(int, Buffer *); +int mm_answer_term(int, Buffer *); +int mm_answer_rsa_keyallowed(int, Buffer *); +int mm_answer_rsa_challenge(int, Buffer *); +int mm_answer_rsa_response(int, Buffer *); +int mm_answer_sesskey(int, Buffer *); +int mm_answer_sessid(int, Buffer *); + +static Authctxt *authctxt; +static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ + +/* local state for key verify */ +static u_char *key_blob = NULL; +static u_int key_bloblen = 0; +static int key_blobtype = MM_NOKEY; +static u_char *hostbased_cuser = NULL; +static u_char *hostbased_chost = NULL; +static char *auth_method = "unknown"; + +struct mon_table { + enum monitor_reqtype type; + int flags; + int (*f)(int, Buffer *); +}; + +#define MON_ISAUTH 0x0004 /* Required for Authentication */ +#define MON_AUTHDECIDE 0x0008 /* Decides Authentication */ +#define MON_ONCE 0x0010 /* Disable after calling */ + +#define MON_AUTH (MON_ISAUTH|MON_AUTHDECIDE) + +#define MON_PERMIT 0x1000 /* Request is permitted */ + +struct mon_table mon_dispatch_proto20[] = { + {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, + {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, + {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, +#ifdef BSD_AUTH + {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, + {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond}, +#endif +#ifdef SKEY + {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, + {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, +#endif + {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, + {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, + {0, 0, NULL} +}; + +struct mon_table mon_dispatch_postauth20[] = { + {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, + {MONITOR_REQ_SIGN, 0, mm_answer_sign}, + {MONITOR_REQ_PTY, 0, mm_answer_pty}, + {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup}, + {MONITOR_REQ_TERM, 0, mm_answer_term}, + {0, 0, NULL} +}; + +struct mon_table mon_dispatch_proto15[] = { + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, + {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, + {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, + {MONITOR_REQ_RSAKEYALLOWED, MON_ISAUTH, mm_answer_rsa_keyallowed}, + {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, + {MONITOR_REQ_RSACHALLENGE, MON_ONCE, mm_answer_rsa_challenge}, + {MONITOR_REQ_RSARESPONSE, MON_ONCE|MON_AUTHDECIDE, mm_answer_rsa_response}, +#ifdef BSD_AUTH + {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, + {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond}, +#endif +#ifdef SKEY + {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, + {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, +#endif + {0, 0, NULL} +}; + +struct mon_table mon_dispatch_postauth15[] = { + {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty}, + {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup}, + {MONITOR_REQ_TERM, 0, mm_answer_term}, + {0, 0, NULL} +}; + +struct mon_table *mon_dispatch; + +/* Specifies if a certain message is allowed at the moment */ + +static void +monitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit) +{ + while (ent->f != NULL) { + if (ent->type == type) { + ent->flags &= ~MON_PERMIT; + ent->flags |= permit ? MON_PERMIT : 0; + return; + } + ent++; + } +} + +static void +monitor_permit_authentications(int permit) +{ + struct mon_table *ent = mon_dispatch; + + while (ent->f != NULL) { + if (ent->flags & MON_AUTH) { + ent->flags &= ~MON_PERMIT; + ent->flags |= permit ? MON_PERMIT : 0; + } + ent++; + } +} + +Authctxt * +monitor_child_preauth(struct monitor *monitor) +{ + struct mon_table *ent; + int authenticated = 0; + + debug3("preauth child monitor started"); + + if (compat20) { + mon_dispatch = mon_dispatch_proto20; + + /* Permit requests for moduli and signatures */ + monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); + } else { + mon_dispatch = mon_dispatch_proto15; + + monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); + } + + authctxt = authctxt_new(); + + /* The first few requests do not require asynchronous access */ + while (!authenticated) { + authenticated = monitor_read(monitor, mon_dispatch, &ent); + if (authenticated) { + if (!(ent->flags & MON_AUTHDECIDE)) + fatal("%s: unexpected authentication from %d", + __FUNCTION__, ent->type); + if (authctxt->pw->pw_uid == 0 && + !auth_root_allowed(auth_method)) + authenticated = 0; + } + + if (ent->flags & MON_AUTHDECIDE) { + auth_log(authctxt, authenticated, auth_method, + compat20 ? " ssh2" : ""); + if (!authenticated) + authctxt->failures++; + } + } + + if (!authctxt->valid) + fatal("%s: authenticated invalid user", __FUNCTION__); + + debug("%s: %s has been authenticated by privileged process", + __FUNCTION__, authctxt->user); + + mm_get_keystate(monitor); + + return (authctxt); +} + +void +monitor_child_postauth(struct monitor *monitor) +{ + if (compat20) { + mon_dispatch = mon_dispatch_postauth20; + + /* Permit requests for moduli and signatures */ + monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); + + } else { + mon_dispatch = mon_dispatch_postauth15; + monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); + } + if (!no_pty_flag) { + monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); + } + + for (;;) + monitor_read(monitor, mon_dispatch, NULL); +} + +void +monitor_sync(struct monitor *monitor) +{ + /* The member allocation is not visible, so sync it */ + mm_share_sync(&monitor->m_zlib, &monitor->m_zback); +} + +int +monitor_read(struct monitor *monitor, struct mon_table *ent, + struct mon_table **pent) +{ + Buffer m; + int ret; + u_char type; + + buffer_init(&m); + + mm_request_receive(monitor->m_sendfd, &m); + type = buffer_get_char(&m); + + debug3("%s: checking request %d", __FUNCTION__, type); + + while (ent->f != NULL) { + if (ent->type == type) + break; + ent++; + } + + if (ent->f != NULL) { + if (!(ent->flags & MON_PERMIT)) + fatal("%s: unpermitted request %d", __FUNCTION__, + type); + ret = (*ent->f)(monitor->m_sendfd, &m); + buffer_free(&m); + + /* The child may use this request only once, disable it */ + if (ent->flags & MON_ONCE) { + debug2("%s: %d used once, disabling now", __FUNCTION__, + type); + ent->flags &= ~MON_PERMIT; + } + + if (pent != NULL) + *pent = ent; + + return ret; + } + + fatal("%s: unsupported request: %d", __FUNCTION__, type); + + /* NOTREACHED */ + return (-1); +} + +/* allowed key state */ +static int +monitor_allowed_key(u_char *blob, u_int bloblen) +{ + /* make sure key is allowed */ + if (key_blob == NULL || key_bloblen != bloblen || + memcmp(key_blob, blob, key_bloblen)) + return (0); + return (1); +} + +static void +monitor_reset_key_state(void) +{ + /* reset state */ + if (key_blob != NULL) + xfree(key_blob); + if (hostbased_cuser != NULL) + xfree(hostbased_cuser); + if (hostbased_chost != NULL) + xfree(hostbased_chost); + key_blob = NULL; + key_bloblen = 0; + key_blobtype = MM_NOKEY; + hostbased_cuser = NULL; + hostbased_chost = NULL; +} + +int +mm_answer_moduli(int socket, Buffer *m) +{ + DH *dh; + int min, want, max; + + min = buffer_get_int(m); + want = buffer_get_int(m); + max = buffer_get_int(m); + + debug3("%s: got parameters: %d %d %d", + __FUNCTION__, min, want, max); + /* We need to check here, too, in case the child got corrupted */ + if (max < min || want < min || max < want) + fatal("%s: bad parameters: %d %d %d", + __FUNCTION__, min, want, max); + + buffer_clear(m); + + dh = choose_dh(min, want, max); + if (dh == NULL) { + buffer_put_char(m, 0); + return (0); + } else { + /* Send first bignum */ + buffer_put_char(m, 1); + buffer_put_bignum2(m, dh->p); + buffer_put_bignum2(m, dh->g); + + DH_free(dh); + } + mm_request_send(socket, MONITOR_ANS_MODULI, m); + return (0); +} + +int +mm_answer_sign(int socket, Buffer *m) +{ + Key *key; + u_char *p; + u_char *signature; + u_int siglen, datlen; + int keyid; + + debug3("%s", __FUNCTION__); + + keyid = buffer_get_int(m); + p = buffer_get_string(m, &datlen); + + if (datlen != 20) + fatal("%s: data length incorrect: %d", __FUNCTION__, datlen); + + if ((key = get_hostkey_by_index(keyid)) == NULL) + fatal("%s: no hostkey from index %d", __FUNCTION__, keyid); + if (key_sign(key, &signature, &siglen, p, datlen) < 0) + fatal("%s: key_sign failed", __FUNCTION__); + + debug3("%s: signature %p(%d)", __FUNCTION__, signature, siglen); + + buffer_clear(m); + buffer_put_string(m, signature, siglen); + + xfree(p); + xfree(signature); + + mm_request_send(socket, MONITOR_ANS_SIGN, m); + + /* Turn on permissions for getpwnam */ + monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); + + return (0); +} + +/* Retrieves the password entry and also checks if the user is permitted */ + +int +mm_answer_pwnamallow(int socket, Buffer *m) +{ + char *login; + struct passwd *pwent; + int allowed = 0; + + debug3("%s", __FUNCTION__); + + if (authctxt->attempt++ != 0) + fatal("%s: multiple attempts for getpwnam", __FUNCTION__); + + login = buffer_get_string(m, NULL); + + pwent = getpwnamallow(login); + + authctxt->user = xstrdup(login); + setproctitle("%s [priv]", pwent ? login : "unknown"); + xfree(login); + + buffer_clear(m); + + if (pwent == NULL) { + buffer_put_char(m, 0); + goto out; + } + + allowed = 1; + authctxt->pw = pwent; + authctxt->valid = 1; + + buffer_put_char(m, 1); + buffer_put_string(m, pwent, sizeof(struct passwd)); + buffer_put_cstring(m, pwent->pw_name); + buffer_put_cstring(m, "*"); + buffer_put_cstring(m, pwent->pw_gecos); + buffer_put_cstring(m, pwent->pw_class); + buffer_put_cstring(m, pwent->pw_dir); + buffer_put_cstring(m, pwent->pw_shell); + + out: + debug3("%s: sending MONITOR_ANS_PWNAM: %d", __FUNCTION__, allowed); + mm_request_send(socket, MONITOR_ANS_PWNAM, m); + + /* For SSHv1 allow authentication now */ + if (!compat20) + monitor_permit_authentications(1); + else + /* Allow service/style information on the auth context */ + monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); + + + return (0); +} + +int +mm_answer_authserv(int socket, Buffer *m) +{ + monitor_permit_authentications(1); + + authctxt->service = buffer_get_string(m, NULL); + authctxt->style = buffer_get_string(m, NULL); + debug3("%s: service=%s, style=%s", + __FUNCTION__, authctxt->service, authctxt->style); + + if (strlen(authctxt->style) == 0) { + xfree(authctxt->style); + authctxt->style = NULL; + } + + return (0); +} + +int +mm_answer_authpassword(int socket, Buffer *m) +{ + static int call_count; + char *passwd; + int authenticated, plen; + + passwd = buffer_get_string(m, &plen); + /* Only authenticate if the context is valid */ + authenticated = authctxt->valid && auth_password(authctxt, passwd); + memset(passwd, 0, strlen(passwd)); + xfree(passwd); + + buffer_clear(m); + buffer_put_int(m, authenticated); + + debug3("%s: sending result %d", __FUNCTION__, authenticated); + mm_request_send(socket, MONITOR_ANS_AUTHPASSWORD, m); + + call_count++; + if (plen == 0 && call_count == 1) + auth_method = "none"; + else + auth_method = "password"; + + /* Causes monitor loop to terminate if authenticated */ + return (authenticated); +} + +#ifdef BSD_AUTH +int +mm_answer_bsdauthquery(int socket, Buffer *m) +{ + char *name, *infotxt; + u_int numprompts; + u_int *echo_on; + char **prompts; + int res; + + res = bsdauth_query(authctxt, &name, &infotxt, &numprompts, + &prompts, &echo_on); + + buffer_clear(m); + buffer_put_int(m, res); + if (res != -1) + buffer_put_cstring(m, prompts[0]); + + debug3("%s: sending challenge res: %d", __FUNCTION__, res); + mm_request_send(socket, MONITOR_ANS_BSDAUTHQUERY, m); + + if (res != -1) { + xfree(name); + xfree(infotxt); + xfree(prompts); + xfree(echo_on); + } + + return (0); +} + +int +mm_answer_bsdauthrespond(int socket, Buffer *m) +{ + char *response; + int authok; + + if (authctxt->as == 0) + fatal("%s: no bsd auth session", __FUNCTION__); + + response = buffer_get_string(m, NULL); + authok = auth_userresponse(authctxt->as, response, 0); + authctxt->as = NULL; + debug3("%s: <%s> = <%d>", __FUNCTION__, response, authok); + xfree(response); + + buffer_clear(m); + buffer_put_int(m, authok); + + debug3("%s: sending authenticated: %d", __FUNCTION__, authok); + mm_request_send(socket, MONITOR_ANS_BSDAUTHRESPOND, m); + + auth_method = "bsdauth"; + + return (authok != 0); +} +#endif + +#ifdef SKEY +int +mm_answer_skeyquery(int socket, Buffer *m) +{ + struct skey skey; + char challenge[1024]; + int res; + + res = skeychallenge(&skey, authctxt->user, challenge); + + buffer_clear(m); + buffer_put_int(m, res); + if (res != -1) + buffer_put_cstring(m, challenge); + + debug3("%s: sending challenge res: %d", __FUNCTION__, res); + mm_request_send(socket, MONITOR_ANS_SKEYQUERY, m); + + return (0); +} + +int +mm_answer_skeyrespond(int socket, Buffer *m) +{ + char *response; + int authok; + + response = buffer_get_string(m, NULL); + + authok = (authctxt->valid && + skey_haskey(authctxt->pw->pw_name) == 0 && + skey_passcheck(authctxt->pw->pw_name, response) != -1); + + xfree(response); + + buffer_clear(m); + buffer_put_int(m, authok); + + debug3("%s: sending authenticated: %d", __FUNCTION__, authok); + mm_request_send(socket, MONITOR_ANS_SKEYRESPOND, m); + + auth_method = "skey"; + + return (authok != 0); +} +#endif + +static void +mm_append_debug(Buffer *m) +{ + if (auth_debug_init && buffer_len(&auth_debug)) { + debug3("%s: Appending debug messages for child", __FUNCTION__); + buffer_append(m, buffer_ptr(&auth_debug), + buffer_len(&auth_debug)); + buffer_clear(&auth_debug); + } +} + +int +mm_answer_keyallowed(int socket, Buffer *m) +{ + Key *key; + u_char *cuser, *chost, *blob; + u_int bloblen; + enum mm_keytype type = 0; + int allowed = 0; + + debug3("%s entering", __FUNCTION__); + + type = buffer_get_int(m); + cuser = buffer_get_string(m, NULL); + chost = buffer_get_string(m, NULL); + blob = buffer_get_string(m, &bloblen); + + key = key_from_blob(blob, bloblen); + + if ((compat20 && type == MM_RSAHOSTKEY) || + (!compat20 && type != MM_RSAHOSTKEY)) + fatal("%s: key type and protocol mismatch", __FUNCTION__); + + debug3("%s: key_from_blob: %p", __FUNCTION__, key); + + if (key != NULL && authctxt->pw != NULL) { + switch(type) { + case MM_USERKEY: + allowed = user_key_allowed(authctxt->pw, key); + break; + case MM_HOSTKEY: + allowed = hostbased_key_allowed(authctxt->pw, + cuser, chost, key); + break; + case MM_RSAHOSTKEY: + key->type = KEY_RSA1; /* XXX */ + allowed = auth_rhosts_rsa_key_allowed(authctxt->pw, + cuser, chost, key); + break; + default: + fatal("%s: unknown key type %d", __FUNCTION__, type); + break; + } + key_free(key); + } + + /* clear temporarily storage (used by verify) */ + monitor_reset_key_state(); + + if (allowed) { + /* Save temporarily for comparison in verify */ + key_blob = blob; + key_bloblen = bloblen; + key_blobtype = type; + hostbased_cuser = cuser; + hostbased_chost = chost; + } + + debug3("%s: key %p is %s", + __FUNCTION__, key, allowed ? "allowed" : "disallowed"); + + buffer_clear(m); + buffer_put_int(m, allowed); + + mm_append_debug(m); + + mm_request_send(socket, MONITOR_ANS_KEYALLOWED, m); + + if (type == MM_RSAHOSTKEY) + monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); + + return (0); +} + +static int +monitor_valid_userblob(u_char *data, u_int datalen) +{ + Buffer b; + u_char *p; + u_int len; + int fail = 0; + int session_id2_len = 20 /*XXX should get from [net] */; + + buffer_init(&b); + buffer_append(&b, data, datalen); + + if (datafellows & SSH_OLD_SESSIONID) { + buffer_consume(&b, session_id2_len); + } else { + xfree(buffer_get_string(&b, &len)); + if (len != session_id2_len) + fail++; + } + if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) + fail++; + p = buffer_get_string(&b, NULL); + if (strcmp(authctxt->user, p) != 0) { + log("wrong user name passed to monitor: expected %s != %.100s", + authctxt->user, p); + fail++; + } + xfree(p); + buffer_skip_string(&b); + if (datafellows & SSH_BUG_PKAUTH) { + if (!buffer_get_char(&b)) + fail++; + } else { + p = buffer_get_string(&b, NULL); + if (strcmp("publickey", p) != 0) + fail++; + xfree(p); + if (!buffer_get_char(&b)) + fail++; + buffer_skip_string(&b); + } + buffer_skip_string(&b); + if (buffer_len(&b) != 0) + fail++; + buffer_free(&b); + return (fail == 0); +} + +static int +monitor_valid_hostbasedblob(u_char *data, u_int datalen, u_char *cuser, + u_char *chost) +{ + Buffer b; + u_char *p; + u_int len; + int fail = 0; + int session_id2_len = 20 /*XXX should get from [net] */; + + buffer_init(&b); + buffer_append(&b, data, datalen); + + xfree(buffer_get_string(&b, &len)); + if (len != session_id2_len) + fail++; + if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) + fail++; + p = buffer_get_string(&b, NULL); + if (strcmp(authctxt->user, p) != 0) { + log("wrong user name passed to monitor: expected %s != %.100s", + authctxt->user, p); + fail++; + } + xfree(p); + buffer_skip_string(&b); /* service */ + p = buffer_get_string(&b, NULL); + if (strcmp(p, "hostbased") != 0) + fail++; + xfree(p); + buffer_skip_string(&b); /* pkalg */ + buffer_skip_string(&b); /* pkblob */ + + /* verify client host, strip trailing dot if necessary */ + p = buffer_get_string(&b, NULL); + if (((len = strlen(p)) > 0) && p[len - 1] == '.') + p[len - 1] = '\0'; + if (strcmp(p, chost) != 0) + fail++; + xfree(p); + + /* verify client user */ + p = buffer_get_string(&b, NULL); + if (strcmp(p, cuser) != 0) + fail++; + xfree(p); + + if (buffer_len(&b) != 0) + fail++; + buffer_free(&b); + return (fail == 0); +} + +int +mm_answer_keyverify(int socket, Buffer *m) +{ + Key *key; + u_char *signature, *data, *blob; + u_int signaturelen, datalen, bloblen; + int verified = 0; + int valid_data = 0; + + blob = buffer_get_string(m, &bloblen); + signature = buffer_get_string(m, &signaturelen); + data = buffer_get_string(m, &datalen); + + if (hostbased_cuser == NULL || hostbased_chost == NULL || + !monitor_allowed_key(blob, bloblen)) + fatal("%s: bad key, not previously allowed", __FUNCTION__); + + key = key_from_blob(blob, bloblen); + if (key == NULL) + fatal("%s: bad public key blob", __FUNCTION__); + + switch (key_blobtype) { + case MM_USERKEY: + valid_data = monitor_valid_userblob(data, datalen); + break; + case MM_HOSTKEY: + valid_data = monitor_valid_hostbasedblob(data, datalen, + hostbased_cuser, hostbased_chost); + break; + default: + valid_data = 0; + break; + } + if (!valid_data) + fatal("%s: bad signature data blob", __FUNCTION__); + + verified = key_verify(key, signature, signaturelen, data, datalen); + debug3("%s: key %p signature %s", + __FUNCTION__, key, verified ? "verified" : "unverified"); + + key_free(key); + xfree(blob); + xfree(signature); + xfree(data); + + monitor_reset_key_state(); + + buffer_clear(m); + buffer_put_int(m, verified); + mm_request_send(socket, MONITOR_ANS_KEYVERIFY, m); + + auth_method = "publickey"; + + return (verified); +} + +static void +mm_record_login(Session *s, struct passwd *pw) +{ + socklen_t fromlen; + struct sockaddr_storage from; + + /* + * Get IP address of client. If the connection is not a socket, let + * the address be 0.0.0.0. + */ + memset(&from, 0, sizeof(from)); + if (packet_connection_is_on_socket()) { + fromlen = sizeof(from); + if (getpeername(packet_get_connection_in(), + (struct sockaddr *) & from, &fromlen) < 0) { + debug("getpeername: %.100s", strerror(errno)); + fatal_cleanup(); + } + } + /* Record that there was a login on that tty from the remote host. */ + record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid, + get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping), + (struct sockaddr *)&from); +} + +static void +mm_session_close(Session *s) +{ + debug3("%s: session %d pid %d", __FUNCTION__, s->self, s->pid); + if (s->ttyfd != -1) { + debug3("%s: tty %s ptyfd %d", __FUNCTION__, s->tty, s->ptyfd); + fatal_remove_cleanup(session_pty_cleanup2, (void *)s); + session_pty_cleanup2(s); + } + s->used = 0; +} + +int +mm_answer_pty(int socket, Buffer *m) +{ + extern struct monitor *monitor; + Session *s; + int res, fd0; + + debug3("%s entering", __FUNCTION__); + + buffer_clear(m); + s = session_new(); + if (s == NULL) + goto error; + s->authctxt = authctxt; + s->pw = authctxt->pw; + s->pid = monitor->m_pid; + res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); + if (res == 0) + goto error; + fatal_add_cleanup(session_pty_cleanup2, (void *)s); + pty_setowner(authctxt->pw, s->tty); + + buffer_put_int(m, 1); + buffer_put_cstring(m, s->tty); + mm_request_send(socket, MONITOR_ANS_PTY, m); + + mm_send_fd(socket, s->ptyfd); + mm_send_fd(socket, s->ttyfd); + + /* We need to trick ttyslot */ + if (dup2(s->ttyfd, 0) == -1) + fatal("%s: dup2", __FUNCTION__); + + mm_record_login(s, authctxt->pw); + + /* Now we can close the file descriptor again */ + close(0); + + /* make sure nothing uses fd 0 */ + if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0) + fatal("%s: open(/dev/null): %s", __FUNCTION__, strerror(errno)); + if (fd0 != 0) + error("%s: fd0 %d != 0", __FUNCTION__, fd0); + + /* slave is not needed */ + close(s->ttyfd); + s->ttyfd = s->ptyfd; + /* no need to dup() because nobody closes ptyfd */ + s->ptymaster = s->ptyfd; + + debug3("%s: tty %s ptyfd %d", __FUNCTION__, s->tty, s->ttyfd); + + return (0); + + error: + if (s != NULL) + mm_session_close(s); + buffer_put_int(m, 0); + mm_request_send(socket, MONITOR_ANS_PTY, m); + return (0); +} + +int +mm_answer_pty_cleanup(int socket, Buffer *m) +{ + Session *s; + char *tty; + + debug3("%s entering", __FUNCTION__); + + tty = buffer_get_string(m, NULL); + if ((s = session_by_tty(tty)) != NULL) + mm_session_close(s); + buffer_clear(m); + xfree(tty); + return (0); +} + +int +mm_answer_sesskey(int socket, Buffer *m) +{ + BIGNUM *p; + int rsafail; + + /* Turn off permissions */ + monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); + + if ((p = BN_new()) == NULL) + fatal("%s: BN_new", __FUNCTION__); + + buffer_get_bignum2(m, p); + + rsafail = ssh1_session_key(p); + + buffer_clear(m); + buffer_put_int(m, rsafail); + buffer_put_bignum2(m, p); + + BN_clear_free(p); + + mm_request_send(socket, MONITOR_ANS_SESSKEY, m); + + /* Turn on permissions for sessid passing */ + monitor_permit(mon_dispatch, MONITOR_REQ_SESSID, 1); + + return (0); +} + +int +mm_answer_sessid(int socket, Buffer *m) +{ + int i; + + debug3("%s entering", __FUNCTION__); + + if (buffer_len(m) != 16) + fatal("%s: bad ssh1 session id", __FUNCTION__); + for (i = 0; i < 16; i++) + session_id[i] = buffer_get_char(m); + + /* Turn on permissions for getpwnam */ + monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); + + return (0); +} + +int +mm_answer_rsa_keyallowed(int socket, Buffer *m) +{ + BIGNUM *client_n; + Key *key = NULL; + u_char *blob = NULL; + u_int blen = 0; + int allowed = 0; + + debug3("%s entering", __FUNCTION__); + + if (authctxt->valid) { + if ((client_n = BN_new()) == NULL) + fatal("%s: BN_new", __FUNCTION__); + buffer_get_bignum2(m, client_n); + allowed = auth_rsa_key_allowed(authctxt->pw, client_n, &key); + BN_clear_free(client_n); + } + buffer_clear(m); + buffer_put_int(m, allowed); + + /* clear temporarily storage (used by generate challenge) */ + monitor_reset_key_state(); + + if (allowed && key != NULL) { + key->type = KEY_RSA; /* cheat for key_to_blob */ + if (key_to_blob(key, &blob, &blen) == 0) + fatal("%s: key_to_blob failed", __FUNCTION__); + buffer_put_string(m, blob, blen); + + /* Save temporarily for comparison in verify */ + key_blob = blob; + key_bloblen = blen; + key_blobtype = MM_RSAUSERKEY; + key_free(key); + } + + mm_append_debug(m); + + mm_request_send(socket, MONITOR_ANS_RSAKEYALLOWED, m); + + monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); + monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 0); + return (0); +} + +int +mm_answer_rsa_challenge(int socket, Buffer *m) +{ + Key *key = NULL; + u_char *blob; + u_int blen; + + debug3("%s entering", __FUNCTION__); + + if (!authctxt->valid) + fatal("%s: authctxt not valid", __FUNCTION__); + blob = buffer_get_string(m, &blen); + if (!monitor_allowed_key(blob, blen)) + fatal("%s: bad key, not previously allowed", __FUNCTION__); + if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) + fatal("%s: key type mismatch", __FUNCTION__); + if ((key = key_from_blob(blob, blen)) == NULL) + fatal("%s: received bad key", __FUNCTION__); + + if (ssh1_challenge) + BN_clear_free(ssh1_challenge); + ssh1_challenge = auth_rsa_generate_challenge(key); + + buffer_clear(m); + buffer_put_bignum2(m, ssh1_challenge); + + debug3("%s sending reply", __FUNCTION__); + mm_request_send(socket, MONITOR_ANS_RSACHALLENGE, m); + + monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 1); + return (0); +} + +int +mm_answer_rsa_response(int socket, Buffer *m) +{ + Key *key = NULL; + u_char *blob, *response; + u_int blen, len; + int success; + + debug3("%s entering", __FUNCTION__); + + if (!authctxt->valid) + fatal("%s: authctxt not valid", __FUNCTION__); + if (ssh1_challenge == NULL) + fatal("%s: no ssh1_challenge", __FUNCTION__); + + blob = buffer_get_string(m, &blen); + if (!monitor_allowed_key(blob, blen)) + fatal("%s: bad key, not previously allowed", __FUNCTION__); + if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) + fatal("%s: key type mismatch: %d", __FUNCTION__, key_blobtype); + if ((key = key_from_blob(blob, blen)) == NULL) + fatal("%s: received bad key", __FUNCTION__); + response = buffer_get_string(m, &len); + if (len != 16) + fatal("%s: received bad response to challenge", __FUNCTION__); + success = auth_rsa_verify_response(key, ssh1_challenge, response); + + key_free(key); + xfree(response); + + auth_method = key_blobtype == MM_RSAUSERKEY ? "rsa" : "rhosts-rsa"; + + /* reset state */ + BN_clear_free(ssh1_challenge); + ssh1_challenge = NULL; + monitor_reset_key_state(); + + buffer_clear(m); + buffer_put_int(m, success); + mm_request_send(socket, MONITOR_ANS_RSARESPONSE, m); + + return (success); +} + +int +mm_answer_term(int socket, Buffer *req) +{ + extern struct monitor *monitor; + int res, status; + + debug3("%s: tearing down sessions", __FUNCTION__); + + /* The child is terminating */ + session_destroy_all(&mm_session_close); + + while (waitpid(monitor->m_pid, &status, 0) == -1) + if (errno != EINTR) + exit(1); + + res = WIFEXITED(status) ? WEXITSTATUS(status) : 1; + + /* Terminate process */ + exit (res); +} + +void +monitor_apply_keystate(struct monitor *monitor) +{ + if (compat20) { + set_newkeys(MODE_IN); + set_newkeys(MODE_OUT); + } else { + u_char key[SSH_SESSION_KEY_LENGTH]; + + memset(key, 'a', sizeof(key)); + packet_set_protocol_flags(child_state.ssh1protoflags); + packet_set_encryption_key(key, SSH_SESSION_KEY_LENGTH, + child_state.ssh1cipher); + } + + packet_set_keycontext(MODE_OUT, child_state.keyout); + xfree(child_state.keyout); + packet_set_keycontext(MODE_IN, child_state.keyin); + xfree(child_state.keyin); + + if (!compat20) { + packet_set_iv(MODE_OUT, child_state.ivout); + xfree(child_state.ivout); + packet_set_iv(MODE_IN, child_state.ivin); + xfree(child_state.ivin); + } + + memcpy(&incoming_stream, &child_state.incoming, + sizeof(incoming_stream)); + memcpy(&outgoing_stream, &child_state.outgoing, + sizeof(outgoing_stream)); + + /* Update with new address */ + mm_init_compression(monitor->m_zlib); + + /* Network I/O buffers */ + /* XXX inefficient for large buffers, need: buffer_init_from_string */ + buffer_clear(&input); + buffer_append(&input, child_state.input, child_state.ilen); + memset(child_state.input, 0, child_state.ilen); + xfree(child_state.input); + + buffer_clear(&output); + buffer_append(&output, child_state.output, child_state.olen); + memset(child_state.output, 0, child_state.olen); + xfree(child_state.output); +} + +static Kex * +mm_get_kex(Buffer *m) +{ + Kex *kex; + void *blob; + u_int bloblen; + + kex = xmalloc(sizeof(*kex)); + memset(kex, 0, sizeof(*kex)); + kex->session_id = buffer_get_string(m, &kex->session_id_len); + kex->we_need = buffer_get_int(m); + kex->server = 1; + kex->hostkey_type = buffer_get_int(m); + kex->kex_type = buffer_get_int(m); + blob = buffer_get_string(m, &bloblen); + buffer_init(&kex->my); + buffer_append(&kex->my, blob, bloblen); + xfree(blob); + blob = buffer_get_string(m, &bloblen); + buffer_init(&kex->peer); + buffer_append(&kex->peer, blob, bloblen); + xfree(blob); + kex->done = 1; + kex->flags = buffer_get_int(m); + kex->client_version_string = buffer_get_string(m, NULL); + kex->server_version_string = buffer_get_string(m, NULL); + kex->load_host_key=&get_hostkey_by_type; + kex->host_key_index=&get_hostkey_index; + + return (kex); +} + +/* This function requries careful sanity checking */ + +void +mm_get_keystate(struct monitor *monitor) +{ + Buffer m; + u_char *blob, *p; + u_int bloblen, plen; + + debug3("%s: Waiting for new keys", __FUNCTION__); + + buffer_init(&m); + mm_request_receive_expect(monitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m); + if (!compat20) { + child_state.ssh1protoflags = buffer_get_int(&m); + child_state.ssh1cipher = buffer_get_int(&m); + child_state.ivout = buffer_get_string(&m, + &child_state.ivoutlen); + child_state.ivin = buffer_get_string(&m, &child_state.ivinlen); + goto skip; + } else { + /* Get the Kex for rekeying */ + *monitor->m_pkex = mm_get_kex(&m); + } + + blob = buffer_get_string(&m, &bloblen); + current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen); + xfree(blob); + + debug3("%s: Waiting for second key", __FUNCTION__); + blob = buffer_get_string(&m, &bloblen); + current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen); + xfree(blob); + + /* Now get sequence numbers for the packets */ + packet_set_seqnr(MODE_OUT, buffer_get_int(&m)); + packet_set_seqnr(MODE_IN, buffer_get_int(&m)); + + skip: + /* Get the key context */ + child_state.keyout = buffer_get_string(&m, &child_state.keyoutlen); + child_state.keyin = buffer_get_string(&m, &child_state.keyinlen); + + debug3("%s: Getting compression state", __FUNCTION__); + /* Get compression state */ + p = buffer_get_string(&m, &plen); + if (plen != sizeof(child_state.outgoing)) + fatal("%s: bad request size", __FUNCTION__); + memcpy(&child_state.outgoing, p, sizeof(child_state.outgoing)); + xfree(p); + + p = buffer_get_string(&m, &plen); + if (plen != sizeof(child_state.incoming)) + fatal("%s: bad request size", __FUNCTION__); + memcpy(&child_state.incoming, p, sizeof(child_state.incoming)); + xfree(p); + + /* Network I/O buffers */ + debug3("%s: Getting Network I/O buffers", __FUNCTION__); + child_state.input = buffer_get_string(&m, &child_state.ilen); + child_state.output = buffer_get_string(&m, &child_state.olen); + + buffer_free(&m); +} + + +/* Allocation functions for zlib */ +void * +mm_zalloc(struct mm_master *mm, u_int ncount, u_int size) +{ + void *address; + + address = mm_malloc(mm, size * ncount); + + return (address); +} + +void +mm_zfree(struct mm_master *mm, void *address) +{ + mm_free(mm, address); +} + +void +mm_init_compression(struct mm_master *mm) +{ + outgoing_stream.zalloc = (alloc_func)mm_zalloc; + outgoing_stream.zfree = (free_func)mm_zfree; + outgoing_stream.opaque = mm; + + incoming_stream.zalloc = (alloc_func)mm_zalloc; + incoming_stream.zfree = (free_func)mm_zfree; + incoming_stream.opaque = mm; +} + +/* XXX */ + +#define FD_CLOSEONEXEC(x) do { \ + if (fcntl(x, F_SETFD, 1) == -1) \ + fatal("fcntl(%d, F_SETFD)", x); \ +} while (0) + +static void +monitor_socketpair(int *pair) +{ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) + fatal("%s: socketpair", __FUNCTION__); + FD_CLOSEONEXEC(pair[0]); + FD_CLOSEONEXEC(pair[1]); +} + +#define MM_MEMSIZE 65536 + +struct monitor * +monitor_init(void) +{ + struct monitor *mon; + int pair[2]; + + mon = xmalloc(sizeof(*mon)); + + monitor_socketpair(pair); + + mon->m_recvfd = pair[0]; + mon->m_sendfd = pair[1]; + + /* Used to share zlib space across processes */ + mon->m_zback = mm_create(NULL, MM_MEMSIZE); + mon->m_zlib = mm_create(mon->m_zback, 20 * MM_MEMSIZE); + + /* Compression needs to share state across borders */ + mm_init_compression(mon->m_zlib); + + return mon; +} + +void +monitor_reinit(struct monitor *mon) +{ + int pair[2]; + + monitor_socketpair(pair); + + mon->m_recvfd = pair[0]; + mon->m_sendfd = pair[1]; +} diff --git a/crypto/dist/ssh/monitor.h b/crypto/dist/ssh/monitor.h new file mode 100644 index 00000000000..34eccf17cb0 --- /dev/null +++ b/crypto/dist/ssh/monitor.h @@ -0,0 +1,81 @@ +/* $NetBSD: monitor.h,v 1.1.1.1 2002/04/22 07:38:02 itojun Exp $ */ +/* $OpenBSD: monitor.h,v 1.3 2002/03/26 03:24:01 stevesk Exp $ */ + +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MONITOR_H_ +#define _MONITOR_H_ + +enum monitor_reqtype { + MONITOR_REQ_MODULI, MONITOR_ANS_MODULI, + MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV, + MONITOR_REQ_SIGN, MONITOR_ANS_SIGN, + MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM, + MONITOR_REQ_AUTHPASSWORD, MONITOR_ANS_AUTHPASSWORD, + MONITOR_REQ_BSDAUTHQUERY, MONITOR_ANS_BSDAUTHQUERY, + MONITOR_REQ_BSDAUTHRESPOND, MONITOR_ANS_BSDAUTHRESPOND, + MONITOR_REQ_SKEYQUERY, MONITOR_ANS_SKEYQUERY, + MONITOR_REQ_SKEYRESPOND, MONITOR_ANS_SKEYRESPOND, + MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED, + MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY, + MONITOR_REQ_KEYEXPORT, + MONITOR_REQ_PTY, MONITOR_ANS_PTY, + MONITOR_REQ_PTYCLEANUP, + MONITOR_REQ_SESSKEY, MONITOR_ANS_SESSKEY, + MONITOR_REQ_SESSID, + MONITOR_REQ_RSAKEYALLOWED, MONITOR_ANS_RSAKEYALLOWED, + MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE, + MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE, + MONITOR_REQ_TERM, +}; + +struct mm_master; +struct monitor { + int m_recvfd; + int m_sendfd; + struct mm_master *m_zback; + struct mm_master *m_zlib; + struct Kex **m_pkex; + int m_pid; +}; + +struct monitor *monitor_init(void); +void monitor_reinit(struct monitor *); +void monitor_sync(struct monitor *); + +struct Authctxt; +struct Authctxt *monitor_child_preauth(struct monitor *); +void monitor_child_postauth(struct monitor *); + +struct mon_table; +int monitor_read(struct monitor*, struct mon_table *, struct mon_table **); + +/* Prototypes for request sending and receiving */ +void mm_request_send(int, enum monitor_reqtype, Buffer *); +void mm_request_receive(int, Buffer *); +void mm_request_receive_expect(int, enum monitor_reqtype, Buffer *); + +#endif /* _MONITOR_H_ */ diff --git a/crypto/dist/ssh/monitor_fdpass.c b/crypto/dist/ssh/monitor_fdpass.c new file mode 100644 index 00000000000..676c6578dac --- /dev/null +++ b/crypto/dist/ssh/monitor_fdpass.c @@ -0,0 +1,97 @@ +/* $NetBSD: monitor_fdpass.c,v 1.1.1.1 2002/04/22 07:38:02 itojun Exp $ */ +/* + * Copyright 2001 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: monitor_fdpass.c,v 1.2 2002/03/24 17:53:16 stevesk Exp $"); + +#include <sys/uio.h> + +#include "log.h" +#include "monitor_fdpass.h" + +void +mm_send_fd(int socket, int fd) +{ + struct msghdr msg; + char tmp[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg; + struct iovec vec; + char ch = '\0'; + int n; + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = (caddr_t)tmp; + msg.msg_controllen = CMSG_LEN(sizeof(int)); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = fd; + + vec.iov_base = &ch; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + + if ((n = sendmsg(socket, &msg, 0)) == -1) + fatal("%s: sendmsg(%d): %s", __FUNCTION__, fd, + strerror(errno)); + if (n != 1) + fatal("%s: sendmsg: expected sent 1 got %d", + __FUNCTION__, n); +} + +int +mm_receive_fd(int socket) +{ + struct msghdr msg; + char tmp[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg; + struct iovec vec; + char ch; + int fd, n; + + memset(&msg, 0, sizeof(msg)); + vec.iov_base = &ch; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = tmp; + msg.msg_controllen = sizeof(tmp); + + if ((n = recvmsg(socket, &msg, 0)) == -1) + fatal("%s: recvmsg: %s", __FUNCTION__, strerror(errno)); + if (n != 1) + fatal("%s: recvmsg: expected received 1 got %d", + __FUNCTION__, n); + + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg->cmsg_type != SCM_RIGHTS) + fatal("%s: expected type %d got %d", __FUNCTION__, + SCM_RIGHTS, cmsg->cmsg_type); + fd = (*(int *)CMSG_DATA(cmsg)); + return fd; +} diff --git a/crypto/dist/ssh/monitor_fdpass.h b/crypto/dist/ssh/monitor_fdpass.h new file mode 100644 index 00000000000..b92482a6197 --- /dev/null +++ b/crypto/dist/ssh/monitor_fdpass.h @@ -0,0 +1,35 @@ +/* $NetBSD: monitor_fdpass.h,v 1.1.1.1 2002/04/22 07:38:02 itojun Exp $ */ +/* $OpenBSD: monitor_fdpass.h,v 1.2 2002/03/26 03:24:01 stevesk Exp $ */ + +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MM_FDPASS_H_ +#define _MM_FDPASS_H_ + +void mm_send_fd(int, int); +int mm_receive_fd(int); + +#endif /* _MM_FDPASS_H_ */ diff --git a/crypto/dist/ssh/monitor_mm.c b/crypto/dist/ssh/monitor_mm.c new file mode 100644 index 00000000000..35c5c499098 --- /dev/null +++ b/crypto/dist/ssh/monitor_mm.c @@ -0,0 +1,330 @@ +/* $NetBSD: monitor_mm.c,v 1.1.1.1 2002/04/22 07:38:03 itojun Exp $ */ +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: monitor_mm.c,v 1.4 2002/03/25 20:12:10 stevesk Exp $"); + +#include <sys/mman.h> + +#include "ssh.h" +#include "xmalloc.h" +#include "log.h" +#include "monitor_mm.h" + +static int +mm_compare(struct mm_share *a, struct mm_share *b) +{ + return ((char *)a->address - (char *)b->address); +} + +RB_GENERATE(mmtree, mm_share, next, mm_compare) + +static struct mm_share * +mm_make_entry(struct mm_master *mm, struct mmtree *head, + void *address, size_t size) +{ + struct mm_share *tmp, *tmp2; + + if (mm->mmalloc == NULL) + tmp = xmalloc(sizeof(struct mm_share)); + else + tmp = mm_xmalloc(mm->mmalloc, sizeof(struct mm_share)); + tmp->address = address; + tmp->size = size; + + tmp2 = RB_INSERT(mmtree, head, tmp); + if (tmp2 != NULL) + fatal("mm_make_entry(%p): double address %p->%p(%lu)", + mm, tmp2, address, (u_long)size); + + return (tmp); +} + +/* Creates a shared memory area of a certain size */ + +struct mm_master * +mm_create(struct mm_master *mmalloc, size_t size) +{ + void *address; + struct mm_master *mm; + + if (mmalloc == NULL) + mm = xmalloc(sizeof(struct mm_master)); + else + mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); + + /* + * If the memory map has a mm_master it can be completely + * shared including authentication between the child + * and the client. + */ + mm->mmalloc = mmalloc; + + address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED, + -1, 0); + if (address == MAP_FAILED) + fatal("mmap(%lu)", (u_long)size); + + mm->address = address; + mm->size = size; + + RB_INIT(&mm->rb_free); + RB_INIT(&mm->rb_allocated); + + mm_make_entry(mm, &mm->rb_free, address, size); + + return (mm); +} + +/* Frees either the allocated or the free list */ + +static void +mm_freelist(struct mm_master *mmalloc, struct mmtree *head) +{ + struct mm_share *mms, *next; + + for (mms = RB_ROOT(head); mms; mms = next) { + next = RB_NEXT(mmtree, head, mms); + RB_REMOVE(mmtree, head, mms); + if (mmalloc == NULL) + xfree(mms); + else + mm_free(mmalloc, mms); + } +} + +/* Destroys a memory mapped area */ + +void +mm_destroy(struct mm_master *mm) +{ + mm_freelist(mm->mmalloc, &mm->rb_free); + mm_freelist(mm->mmalloc, &mm->rb_allocated); + + if (munmap(mm->address, mm->size) == -1) + fatal("munmap(%p, %lu)", mm->address, (u_long)mm->size); + if (mm->mmalloc == NULL) + xfree(mm); + else + mm_free(mm->mmalloc, mm); +} + +void * +mm_xmalloc(struct mm_master *mm, size_t size) +{ + void *address; + + address = mm_malloc(mm, size); + if (address == NULL) + fatal("%s: mm_malloc(%lu)", __FUNCTION__, (u_long)size); + return (address); +} + + +/* Allocates data from a memory mapped area */ + +void * +mm_malloc(struct mm_master *mm, size_t size) +{ + struct mm_share *mms, *tmp; + + if (size == 0) + fatal("mm_malloc: try to allocate 0 space"); + + size = ((size + MM_MINSIZE - 1) / MM_MINSIZE) * MM_MINSIZE; + + RB_FOREACH(mms, mmtree, &mm->rb_free) { + if (mms->size >= size) + break; + } + + if (mms == NULL) + return (NULL); + + /* Debug */ + memset(mms->address, 0xd0, size); + + tmp = mm_make_entry(mm, &mm->rb_allocated, mms->address, size); + + /* Does not change order in RB tree */ + mms->size -= size; + mms->address = (u_char *)mms->address + size; + + if (mms->size == 0) { + RB_REMOVE(mmtree, &mm->rb_free, mms); + if (mm->mmalloc == NULL) + xfree(mms); + else + mm_free(mm->mmalloc, mms); + } + + return (tmp->address); +} + +/* Frees memory in a memory mapped area */ + +void +mm_free(struct mm_master *mm, void *address) +{ + struct mm_share *mms, *prev, tmp; + + tmp.address = address; + mms = RB_FIND(mmtree, &mm->rb_allocated, &tmp); + if (mms == NULL) + fatal("mm_free(%p): can not find %p", mm, address); + + /* Debug */ + memset(mms->address, 0xd0, mms->size); + + /* Remove from allocated list and insert in free list */ + RB_REMOVE(mmtree, &mm->rb_allocated, mms); + if (RB_INSERT(mmtree, &mm->rb_free, mms) != NULL) + fatal("mm_free(%p): double address %p", mm, address); + + /* Find previous entry */ + prev = mms; + if (RB_LEFT(prev, next)) { + prev = RB_LEFT(prev, next); + while (RB_RIGHT(prev, next)) + prev = RB_RIGHT(prev, next); + } else { + if (RB_PARENT(prev, next) && + (prev == RB_RIGHT(RB_PARENT(prev, next), next))) + prev = RB_PARENT(prev, next); + else { + while (RB_PARENT(prev, next) && + (prev == RB_LEFT(RB_PARENT(prev, next), next))) + prev = RB_PARENT(prev, next); + prev = RB_PARENT(prev, next); + } + } + + /* Check if range does not overlap */ + if (prev != NULL && MM_ADDRESS_END(prev) > address) + fatal("mm_free: memory corruption: %p(%lu) > %p", + prev->address, (u_long)prev->size, address); + + /* See if we can merge backwards */ + if (prev != NULL && MM_ADDRESS_END(prev) == address) { + prev->size += mms->size; + RB_REMOVE(mmtree, &mm->rb_free, mms); + if (mm->mmalloc == NULL) + xfree(mms); + else + mm_free(mm->mmalloc, mms); + } else + prev = mms; + + if (prev == NULL) + return; + + /* Check if we can merge forwards */ + mms = RB_NEXT(mmtree, &mm->rb_free, prev); + if (mms == NULL) + return; + + if (MM_ADDRESS_END(prev) > mms->address) + fatal("mm_free: memory corruption: %p < %p(%lu)", + mms->address, prev->address, (u_long)prev->size); + if (MM_ADDRESS_END(prev) != mms->address) + return; + + prev->size += mms->size; + RB_REMOVE(mmtree, &mm->rb_free, mms); + + if (mm->mmalloc == NULL) + xfree(mms); + else + mm_free(mm->mmalloc, mms); +} + +static void +mm_sync_list(struct mmtree *oldtree, struct mmtree *newtree, + struct mm_master *mm, struct mm_master *mmold) +{ + struct mm_master *mmalloc = mm->mmalloc; + struct mm_share *mms, *new; + + /* Sync free list */ + RB_FOREACH(mms, mmtree, oldtree) { + /* Check the values */ + mm_memvalid(mmold, mms, sizeof(struct mm_share)); + mm_memvalid(mm, mms->address, mms->size); + + new = mm_xmalloc(mmalloc, sizeof(struct mm_share)); + memcpy(new, mms, sizeof(struct mm_share)); + RB_INSERT(mmtree, newtree, new); + } +} + +void +mm_share_sync(struct mm_master **pmm, struct mm_master **pmmalloc) +{ + struct mm_master *mm; + struct mm_master *mmalloc; + struct mm_master *mmold; + struct mmtree rb_free, rb_allocated; + + debug3("%s: Share sync", __FUNCTION__); + + mm = *pmm; + mmold = mm->mmalloc; + mm_memvalid(mmold, mm, sizeof(*mm)); + + mmalloc = mm_create(NULL, mm->size); + mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); + memcpy(mm, *pmm, sizeof(struct mm_master)); + mm->mmalloc = mmalloc; + + rb_free = mm->rb_free; + rb_allocated = mm->rb_allocated; + + RB_INIT(&mm->rb_free); + RB_INIT(&mm->rb_allocated); + + mm_sync_list(&rb_free, &mm->rb_free, mm, mmold); + mm_sync_list(&rb_allocated, &mm->rb_allocated, mm, mmold); + + mm_destroy(mmold); + + *pmm = mm; + *pmmalloc = mmalloc; + + debug3("%s: Share sync end", __FUNCTION__); +} + +void +mm_memvalid(struct mm_master *mm, void *address, size_t size) +{ + void *end = (u_char *)address + size; + + if (address < mm->address) + fatal("mm_memvalid: address too small: %p", address); + if (end < address) + fatal("mm_memvalid: end < address: %p < %p", end, address); + if (end > (void *)((u_char *)mm->address + mm->size)) + fatal("mm_memvalid: address too large: %p", address); +} diff --git a/crypto/dist/ssh/monitor_mm.h b/crypto/dist/ssh/monitor_mm.h new file mode 100644 index 00000000000..076665468d6 --- /dev/null +++ b/crypto/dist/ssh/monitor_mm.h @@ -0,0 +1,67 @@ +/* $NetBSD: monitor_mm.h,v 1.1.1.1 2002/04/22 07:38:03 itojun Exp $ */ +/* $OpenBSD: monitor_mm.h,v 1.2 2002/03/26 03:24:01 stevesk Exp $ */ + +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MM_H_ +#define _MM_H_ +#include <sys/tree.h> + +struct mm_share { + RB_ENTRY(mm_share) next; + void *address; + size_t size; +}; + +struct mm_master { + RB_HEAD(mmtree, mm_share) rb_free; + struct mmtree rb_allocated; + void *address; + size_t size; + + struct mm_master *mmalloc; /* Used to completely share */ + + int write; /* used to writing to other party */ + int read; /* used for reading from other party */ +}; + +RB_PROTOTYPE(mmtree, mm_share, next, mm_compare) + +#define MM_MINSIZE 128 + +#define MM_ADDRESS_END(x) (void *)((u_char *)(x)->address + (x)->size) + +struct mm_master *mm_create(struct mm_master *, size_t); +void mm_destroy(struct mm_master *); + +void mm_share_sync(struct mm_master **, struct mm_master **); + +void *mm_malloc(struct mm_master *, size_t); +void *mm_xmalloc(struct mm_master *, size_t); +void mm_free(struct mm_master *, void *); + +void mm_memvalid(struct mm_master *, void *, size_t); +#endif /* _MM_H_ */ diff --git a/crypto/dist/ssh/monitor_wrap.c b/crypto/dist/ssh/monitor_wrap.c new file mode 100644 index 00000000000..cd07445a5af --- /dev/null +++ b/crypto/dist/ssh/monitor_wrap.c @@ -0,0 +1,895 @@ +/* $NetBSD: monitor_wrap.c,v 1.1.1.1 2002/04/22 07:38:03 itojun Exp $ */ +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * Copyright 2002 Markus Friedl <markus@openbsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: monitor_wrap.c,v 1.5 2002/03/25 20:12:10 stevesk Exp $"); + +#include <openssl/bn.h> +#include <openssl/dh.h> + +#include "ssh.h" +#include "dh.h" +#include "kex.h" +#include "auth.h" +#include "buffer.h" +#include "bufaux.h" +#include "packet.h" +#include "mac.h" +#include "log.h" +#include "zlib.h" +#include "monitor.h" +#include "monitor_wrap.h" +#include "xmalloc.h" +#include "atomicio.h" +#include "monitor_fdpass.h" +#include "getput.h" + +#include "auth.h" +#include "channels.h" +#include "session.h" + +/* Imports */ +extern int compat20; +extern Newkeys *newkeys[]; +extern z_stream incoming_stream; +extern z_stream outgoing_stream; +extern struct monitor *monitor; +extern Buffer input, output; + +void +mm_request_send(int socket, enum monitor_reqtype type, Buffer *m) +{ + u_char buf[5]; + u_int mlen = buffer_len(m); + + debug3("%s entering: type %d", __FUNCTION__, type); + + PUT_32BIT(buf, mlen + 1); + buf[4] = (u_char) type; /* 1st byte of payload is mesg-type */ + if (atomicio(write, socket, buf, sizeof(buf)) != sizeof(buf)) + fatal("%s: write", __FUNCTION__); + if (atomicio(write, socket, buffer_ptr(m), mlen) != mlen) + fatal("%s: write", __FUNCTION__); +} + +void +mm_request_receive(int socket, Buffer *m) +{ + u_char buf[4]; + ssize_t res; + u_int msg_len; + + debug3("%s entering", __FUNCTION__); + + res = atomicio(read, socket, buf, sizeof(buf)); + if (res != sizeof(buf)) { + if (res == 0) + fatal_cleanup(); + fatal("%s: read: %ld", __FUNCTION__, (long)res); + } + msg_len = GET_32BIT(buf); + if (msg_len > 256 * 1024) + fatal("%s: read: bad msg_len %d", __FUNCTION__, msg_len); + buffer_clear(m); + buffer_append_space(m, msg_len); + res = atomicio(read, socket, buffer_ptr(m), msg_len); + if (res != msg_len) + fatal("%s: read: %ld != msg_len", __FUNCTION__, (long)res); +} + +void +mm_request_receive_expect(int socket, enum monitor_reqtype type, Buffer *m) +{ + u_char rtype; + + debug3("%s entering: type %d", __FUNCTION__, type); + + mm_request_receive(socket, m); + rtype = buffer_get_char(m); + if (rtype != type) + fatal("%s: read: rtype %d != type %d", __FUNCTION__, + rtype, type); +} + +DH * +mm_choose_dh(int min, int nbits, int max) +{ + BIGNUM *p, *g; + int success = 0; + Buffer m; + + buffer_init(&m); + buffer_put_int(&m, min); + buffer_put_int(&m, nbits); + buffer_put_int(&m, max); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_MODULI, &m); + + debug3("%s: waiting for MONITOR_ANS_MODULI", __FUNCTION__); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_MODULI, &m); + + success = buffer_get_char(&m); + if (success == 0) + fatal("%s: MONITOR_ANS_MODULI failed", __FUNCTION__); + + if ((p = BN_new()) == NULL) + fatal("%s: BN_new failed", __FUNCTION__); + if ((g = BN_new()) == NULL) + fatal("%s: BN_new failed", __FUNCTION__); + buffer_get_bignum2(&m, p); + buffer_get_bignum2(&m, g); + + debug3("%s: remaining %d", __FUNCTION__, buffer_len(&m)); + buffer_free(&m); + + return (dh_new_group(g, p)); +} + +int +mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen) +{ + Kex *kex = *monitor->m_pkex; + Buffer m; + + debug3("%s entering", __FUNCTION__); + + buffer_init(&m); + buffer_put_int(&m, kex->host_key_index(key)); + buffer_put_string(&m, data, datalen); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_SIGN, &m); + + debug3("%s: waiting for MONITOR_ANS_SIGN", __FUNCTION__); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_SIGN, &m); + *sigp = buffer_get_string(&m, lenp); + buffer_free(&m); + + return (0); +} + +struct passwd * +mm_getpwnamallow(const char *login) +{ + Buffer m; + struct passwd *pw; + u_int pwlen; + + debug3("%s entering", __FUNCTION__); + + buffer_init(&m); + buffer_put_cstring(&m, login); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_PWNAM, &m); + + debug3("%s: waiting for MONITOR_ANS_PWNAM", __FUNCTION__); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_PWNAM, &m); + + if (buffer_get_char(&m) == 0) { + buffer_free(&m); + return (NULL); + } + pw = buffer_get_string(&m, &pwlen); + if (pwlen != sizeof(struct passwd)) + fatal("%s: struct passwd size mismatch", __FUNCTION__); + pw->pw_name = buffer_get_string(&m, NULL); + pw->pw_passwd = buffer_get_string(&m, NULL); + pw->pw_gecos = buffer_get_string(&m, NULL); + pw->pw_class = buffer_get_string(&m, NULL); + pw->pw_dir = buffer_get_string(&m, NULL); + pw->pw_shell = buffer_get_string(&m, NULL); + buffer_free(&m); + + return (pw); +} + +/* Inform the privileged process about service and style */ + +void +mm_inform_authserv(char *service, char *style) +{ + Buffer m; + + debug3("%s entering", __FUNCTION__); + + buffer_init(&m); + buffer_put_cstring(&m, service); + buffer_put_cstring(&m, style ? style : ""); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_AUTHSERV, &m); + + buffer_free(&m); +} + +/* Do the password authentication */ +int +mm_auth_password(Authctxt *authctxt, char *password) +{ + Buffer m; + int authenticated = 0; + + debug3("%s entering", __FUNCTION__); + + buffer_init(&m); + buffer_put_cstring(&m, password); + mm_request_send(monitor->m_recvfd, MONITOR_REQ_AUTHPASSWORD, &m); + + debug3("%s: waiting for MONITOR_ANS_AUTHPASSWORD", __FUNCTION__); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_AUTHPASSWORD, &m); + + authenticated = buffer_get_int(&m); + + buffer_free(&m); + + debug3("%s: user %sauthenticated", + __FUNCTION__, authenticated ? "" : "not "); + return (authenticated); +} + +int +mm_user_key_allowed(struct passwd *pw, Key *key) +{ + return (mm_key_allowed(MM_USERKEY, NULL, NULL, key)); +} + +int +mm_hostbased_key_allowed(struct passwd *pw, char *user, char *host, + Key *key) +{ + return (mm_key_allowed(MM_HOSTKEY, user, host, key)); +} + +int +mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user, + char *host, Key *key) +{ + int ret; + + key->type = KEY_RSA; /* XXX hack for key_to_blob */ + ret = mm_key_allowed(MM_RSAHOSTKEY, user, host, key); + key->type = KEY_RSA1; + return (ret); +} + +static void +mm_send_debug(Buffer *m) +{ + char *msg; + + while (buffer_len(m)) { + msg = buffer_get_string(m, NULL); + debug3("%s: Sending debug: %s", __FUNCTION__, msg); + packet_send_debug("%s", msg); + xfree(msg); + } +} + +int +mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) +{ + Buffer m; + u_char *blob; + u_int len; + int allowed = 0; + + debug3("%s entering", __FUNCTION__); + + /* Convert the key to a blob and the pass it over */ + if (!key_to_blob(key, &blob, &len)) + return (0); + + buffer_init(&m); + buffer_put_int(&m, type); + buffer_put_cstring(&m, user ? user : ""); + buffer_put_cstring(&m, host ? host : ""); + buffer_put_string(&m, blob, len); + xfree(blob); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYALLOWED, &m); + + debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __FUNCTION__); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_KEYALLOWED, &m); + + allowed = buffer_get_int(&m); + + /* Send potential debug messages */ + mm_send_debug(&m); + + buffer_free(&m); + + return (allowed); +} + +/* + * This key verify needs to send the key type along, because the + * privileged parent makes the decision if the key is allowed + * for authentication. + */ + +int +mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) +{ + Buffer m; + u_char *blob; + u_int len; + int verified = 0; + + debug3("%s entering", __FUNCTION__); + + /* Convert the key to a blob and the pass it over */ + if (!key_to_blob(key, &blob, &len)) + return (0); + + buffer_init(&m); + buffer_put_string(&m, blob, len); + buffer_put_string(&m, sig, siglen); + buffer_put_string(&m, data, datalen); + xfree(blob); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m); + + debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __FUNCTION__); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_KEYVERIFY, &m); + + verified = buffer_get_int(&m); + + buffer_free(&m); + + return (verified); +} + +/* Export key state after authentication */ +Newkeys * +mm_newkeys_from_blob(u_char *blob, int blen) +{ + Buffer b; + u_int len; + Newkeys *newkey = NULL; + Enc *enc; + Mac *mac; + Comp *comp; + + debug3("%s: %p(%d)", __FUNCTION__, blob, blen); +#ifdef DEBUG_PK + dump_base64(stderr, blob, blen); +#endif + buffer_init(&b); + buffer_append(&b, blob, blen); + + newkey = xmalloc(sizeof(*newkey)); + enc = &newkey->enc; + mac = &newkey->mac; + comp = &newkey->comp; + + /* Enc structure */ + enc->name = buffer_get_string(&b, NULL); + buffer_get(&b, &enc->cipher, sizeof(enc->cipher)); + enc->enabled = buffer_get_int(&b); + enc->block_size = buffer_get_int(&b); + enc->key = buffer_get_string(&b, &enc->key_len); + enc->iv = buffer_get_string(&b, &len); + if (len != enc->block_size) + fatal("%s: bad ivlen: expected %d != %d", __FUNCTION__, + enc->block_size, len); + + if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher) + fatal("%s: bad cipher name %s or pointer %p", __FUNCTION__, + enc->name, enc->cipher); + + /* Mac structure */ + mac->name = buffer_get_string(&b, NULL); + if (mac->name == NULL || mac_init(mac, mac->name) == -1) + fatal("%s: can not init mac %s", __FUNCTION__, mac->name); + mac->enabled = buffer_get_int(&b); + mac->key = buffer_get_string(&b, &len); + if (len > mac->key_len) + fatal("%s: bad mac key lenght: %d > %d", __FUNCTION__, len, + mac->key_len); + mac->key_len = len; + + /* Comp structure */ + comp->type = buffer_get_int(&b); + comp->enabled = buffer_get_int(&b); + comp->name = buffer_get_string(&b, NULL); + + len = buffer_len(&b); + if (len != 0) + error("newkeys_from_blob: remaining bytes in blob %d", len); + buffer_free(&b); + return (newkey); +} + +int +mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp) +{ + Buffer b; + int len; + u_char *buf; + Enc *enc; + Mac *mac; + Comp *comp; + Newkeys *newkey = newkeys[mode]; + + debug3("%s: converting %p", __FUNCTION__, newkey); + + if (newkey == NULL) { + error("%s: newkey == NULL", __FUNCTION__); + return 0; + } + enc = &newkey->enc; + mac = &newkey->mac; + comp = &newkey->comp; + + buffer_init(&b); + /* Enc structure */ + buffer_put_cstring(&b, enc->name); + /* The cipher struct is constant and shared, you export pointer */ + buffer_append(&b, &enc->cipher, sizeof(enc->cipher)); + buffer_put_int(&b, enc->enabled); + buffer_put_int(&b, enc->block_size); + buffer_put_string(&b, enc->key, enc->key_len); + packet_get_keyiv(mode, enc->iv, enc->block_size); + buffer_put_string(&b, enc->iv, enc->block_size); + + /* Mac structure */ + buffer_put_cstring(&b, mac->name); + buffer_put_int(&b, mac->enabled); + buffer_put_string(&b, mac->key, mac->key_len); + + /* Comp structure */ + buffer_put_int(&b, comp->type); + buffer_put_int(&b, comp->enabled); + buffer_put_cstring(&b, comp->name); + + len = buffer_len(&b); + buf = xmalloc(len); + memcpy(buf, buffer_ptr(&b), len); + memset(buffer_ptr(&b), 0, len); + buffer_free(&b); + if (lenp != NULL) + *lenp = len; + if (blobp != NULL) + *blobp = buf; + return len; +} + +static void +mm_send_kex(Buffer *m, Kex *kex) +{ + buffer_put_string(m, kex->session_id, kex->session_id_len); + buffer_put_int(m, kex->we_need); + buffer_put_int(m, kex->hostkey_type); + buffer_put_int(m, kex->kex_type); + buffer_put_string(m, buffer_ptr(&kex->my), buffer_len(&kex->my)); + buffer_put_string(m, buffer_ptr(&kex->peer), buffer_len(&kex->peer)); + buffer_put_int(m, kex->flags); + buffer_put_cstring(m, kex->client_version_string); + buffer_put_cstring(m, kex->server_version_string); +} + +void +mm_send_keystate(struct monitor *monitor) +{ + Buffer m; + u_char *blob, *p; + u_int bloblen, plen; + + buffer_init(&m); + + if (!compat20) { + u_char iv[24]; + int ivlen; + + buffer_put_int(&m, packet_get_protocol_flags()); + + buffer_put_int(&m, packet_get_ssh1_cipher()); + + debug3("%s: Sending ssh1 IV", __FUNCTION__); + ivlen = packet_get_keyiv_len(MODE_OUT); + packet_get_keyiv(MODE_OUT, iv, ivlen); + buffer_put_string(&m, iv, ivlen); + ivlen = packet_get_keyiv_len(MODE_OUT); + packet_get_keyiv(MODE_IN, iv, ivlen); + buffer_put_string(&m, iv, ivlen); + goto skip; + } else { + /* Kex for rekeying */ + mm_send_kex(&m, *monitor->m_pkex); + } + + debug3("%s: Sending new keys: %p %p", + __FUNCTION__, newkeys[MODE_OUT], newkeys[MODE_IN]); + + /* Keys from Kex */ + if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen)) + fatal("%s: conversion of newkeys failed", __FUNCTION__); + + buffer_put_string(&m, blob, bloblen); + xfree(blob); + + if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen)) + fatal("%s: conversion of newkeys failed", __FUNCTION__); + + buffer_put_string(&m, blob, bloblen); + xfree(blob); + + buffer_put_int(&m, packet_get_seqnr(MODE_OUT)); + buffer_put_int(&m, packet_get_seqnr(MODE_IN)); + + debug3("%s: New keys have been sent", __FUNCTION__); + skip: + /* More key context */ + plen = packet_get_keycontext(MODE_OUT, NULL); + p = xmalloc(plen+1); + packet_get_keycontext(MODE_OUT, p); + buffer_put_string(&m, p, plen); + xfree(p); + + plen = packet_get_keycontext(MODE_IN, NULL); + p = xmalloc(plen+1); + packet_get_keycontext(MODE_IN, p); + buffer_put_string(&m, p, plen); + xfree(p); + + /* Compression state */ + debug3("%s: Sending compression state", __FUNCTION__); + buffer_put_string(&m, &outgoing_stream, sizeof(outgoing_stream)); + buffer_put_string(&m, &incoming_stream, sizeof(incoming_stream)); + + /* Network I/O buffers */ + buffer_put_string(&m, buffer_ptr(&input), buffer_len(&input)); + buffer_put_string(&m, buffer_ptr(&output), buffer_len(&output)); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, &m); + debug3("%s: Finished sending state", __FUNCTION__); + + buffer_free(&m); +} + +int +mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen) +{ + Buffer m; + u_char *p; + int success = 0; + + buffer_init(&m); + mm_request_send(monitor->m_recvfd, MONITOR_REQ_PTY, &m); + + debug3("%s: waiting for MONITOR_ANS_PTY", __FUNCTION__); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_PTY, &m); + + success = buffer_get_int(&m); + if (success == 0) { + debug3("%s: pty alloc failed", __FUNCTION__); + buffer_free(&m); + return (0); + } + p = buffer_get_string(&m, NULL); + buffer_free(&m); + + strlcpy(namebuf, p, namebuflen); /* Possible truncation */ + xfree(p); + + *ptyfd = mm_receive_fd(monitor->m_recvfd); + *ttyfd = mm_receive_fd(monitor->m_recvfd); + + /* Success */ + return (1); +} + +void +mm_session_pty_cleanup2(void *session) +{ + Session *s = session; + Buffer m; + + if (s->ttyfd == -1) + return; + buffer_init(&m); + buffer_put_cstring(&m, s->tty); + mm_request_send(monitor->m_recvfd, MONITOR_REQ_PTYCLEANUP, &m); + buffer_free(&m); + + /* closed dup'ed master */ + if (close(s->ptymaster) < 0) + error("close(s->ptymaster): %s", strerror(errno)); + + /* unlink pty from session */ + s->ttyfd = -1; +} + +/* Request process termination */ + +void +mm_terminate(void) +{ + Buffer m; + + buffer_init(&m); + mm_request_send(monitor->m_recvfd, MONITOR_REQ_TERM, &m); + buffer_free(&m); +} + +int +mm_ssh1_session_key(BIGNUM *num) +{ + int rsafail; + Buffer m; + + buffer_init(&m); + buffer_put_bignum2(&m, num); + mm_request_send(monitor->m_recvfd, MONITOR_REQ_SESSKEY, &m); + + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_SESSKEY, &m); + + rsafail = buffer_get_int(&m); + buffer_get_bignum2(&m, num); + + buffer_free(&m); + + return (rsafail); +} + +static void +mm_chall_setup(char **name, char **infotxt, u_int *numprompts, + char ***prompts, u_int **echo_on) +{ + *name = xstrdup(""); + *infotxt = xstrdup(""); + *numprompts = 1; + *prompts = xmalloc(*numprompts * sizeof(char*)); + *echo_on = xmalloc(*numprompts * sizeof(u_int)); + (*echo_on)[0] = 0; +} + +int +mm_bsdauth_query(void *ctx, char **name, char **infotxt, + u_int *numprompts, char ***prompts, u_int **echo_on) +{ + Buffer m; + int res; + char *challenge; + + debug3("%s: entering", __FUNCTION__); + + buffer_init(&m); + mm_request_send(monitor->m_recvfd, MONITOR_REQ_BSDAUTHQUERY, &m); + + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_BSDAUTHQUERY, + &m); + res = buffer_get_int(&m); + if (res == -1) { + debug3("%s: no challenge", __FUNCTION__); + buffer_free(&m); + return (-1); + } + + /* Get the challenge, and format the response */ + challenge = buffer_get_string(&m, NULL); + buffer_free(&m); + + mm_chall_setup(name, infotxt, numprompts, prompts, echo_on); + (*prompts)[0] = challenge; + + debug3("%s: received challenge: %s", __FUNCTION__, challenge); + + return (0); +} + +int +mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses) +{ + Buffer m; + int authok; + + debug3("%s: entering", __FUNCTION__); + if (numresponses != 1) + return (-1); + + buffer_init(&m); + buffer_put_cstring(&m, responses[0]); + mm_request_send(monitor->m_recvfd, MONITOR_REQ_BSDAUTHRESPOND, &m); + + mm_request_receive_expect(monitor->m_recvfd, + MONITOR_ANS_BSDAUTHRESPOND, &m); + + authok = buffer_get_int(&m); + buffer_free(&m); + + return ((authok == 0) ? -1 : 0); +} + +int +mm_skey_query(void *ctx, char **name, char **infotxt, + u_int *numprompts, char ***prompts, u_int **echo_on) +{ + Buffer m; + int len, res; + char *p, *challenge; + + debug3("%s: entering", __FUNCTION__); + + buffer_init(&m); + mm_request_send(monitor->m_recvfd, MONITOR_REQ_SKEYQUERY, &m); + + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_SKEYQUERY, + &m); + res = buffer_get_int(&m); + if (res == -1) { + debug3("%s: no challenge", __FUNCTION__); + buffer_free(&m); + return (-1); + } + + /* Get the challenge, and format the response */ + challenge = buffer_get_string(&m, NULL); + buffer_free(&m); + + debug3("%s: received challenge: %s", __FUNCTION__, challenge); + + mm_chall_setup(name, infotxt, numprompts, prompts, echo_on); + + len = strlen(challenge) + strlen(SKEY_PROMPT) + 1; + p = xmalloc(len); + strlcpy(p, challenge, len); + strlcat(p, SKEY_PROMPT, len); + (*prompts)[0] = p; + xfree(challenge); + + return (0); +} + +int +mm_skey_respond(void *ctx, u_int numresponses, char **responses) +{ + Buffer m; + int authok; + + debug3("%s: entering", __FUNCTION__); + if (numresponses != 1) + return (-1); + + buffer_init(&m); + buffer_put_cstring(&m, responses[0]); + mm_request_send(monitor->m_recvfd, MONITOR_REQ_SKEYRESPOND, &m); + + mm_request_receive_expect(monitor->m_recvfd, + MONITOR_ANS_SKEYRESPOND, &m); + + authok = buffer_get_int(&m); + buffer_free(&m); + + return ((authok == 0) ? -1 : 0); +} + +void +mm_ssh1_session_id(u_char session_id[16]) +{ + Buffer m; + int i; + + debug3("%s entering", __FUNCTION__); + + buffer_init(&m); + for (i = 0; i < 16; i++) + buffer_put_char(&m, session_id[i]); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_SESSID, &m); + buffer_free(&m); +} + +int +mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) +{ + Buffer m; + Key *key; + u_char *blob; + u_int blen; + int allowed = 0; + + debug3("%s entering", __FUNCTION__); + + buffer_init(&m); + buffer_put_bignum2(&m, client_n); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_RSAKEYALLOWED, &m); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_RSAKEYALLOWED, &m); + + allowed = buffer_get_int(&m); + + if (allowed && rkey != NULL) { + blob = buffer_get_string(&m, &blen); + if ((key = key_from_blob(blob, blen)) == NULL) + fatal("%s: key_from_blob failed", __FUNCTION__); + *rkey = key; + xfree(blob); + } + mm_send_debug(&m); + buffer_free(&m); + + return (allowed); +} + +BIGNUM * +mm_auth_rsa_generate_challenge(Key *key) +{ + Buffer m; + BIGNUM *challenge; + u_char *blob; + u_int blen; + + debug3("%s entering", __FUNCTION__); + + if ((challenge = BN_new()) == NULL) + fatal("%s: BN_new failed", __FUNCTION__); + + key->type = KEY_RSA; /* XXX cheat for key_to_blob */ + if (key_to_blob(key, &blob, &blen) == 0) + fatal("%s: key_to_blob failed", __FUNCTION__); + key->type = KEY_RSA1; + + buffer_init(&m); + buffer_put_string(&m, blob, blen); + xfree(blob); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_RSACHALLENGE, &m); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_RSACHALLENGE, &m); + + buffer_get_bignum2(&m, challenge); + buffer_free(&m); + + return (challenge); +} + +int +mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16]) +{ + Buffer m; + u_char *blob; + u_int blen; + int success = 0; + + debug3("%s entering", __FUNCTION__); + + key->type = KEY_RSA; /* XXX cheat for key_to_blob */ + if (key_to_blob(key, &blob, &blen) == 0) + fatal("%s: key_to_blob failed", __FUNCTION__); + key->type = KEY_RSA1; + + buffer_init(&m); + buffer_put_string(&m, blob, blen); + buffer_put_string(&m, response, 16); + xfree(blob); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_RSARESPONSE, &m); + mm_request_receive_expect(monitor->m_recvfd, MONITOR_ANS_RSARESPONSE, &m); + + success = buffer_get_int(&m); + buffer_free(&m); + + return (success); +} diff --git a/crypto/dist/ssh/monitor_wrap.h b/crypto/dist/ssh/monitor_wrap.h new file mode 100644 index 00000000000..fa8570af1d7 --- /dev/null +++ b/crypto/dist/ssh/monitor_wrap.h @@ -0,0 +1,88 @@ +/* $NetBSD: monitor_wrap.h,v 1.1.1.1 2002/04/22 07:38:03 itojun Exp $ */ +/* $OpenBSD: monitor_wrap.h,v 1.4 2002/03/26 03:24:01 stevesk Exp $ */ + +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MM_WRAP_H_ +#define _MM_WRAP_H_ +#include "key.h" +#include "buffer.h" + +extern int use_privsep; +#define PRIVSEP(x) (use_privsep ? mm_##x : x) + +enum mm_keytype {MM_NOKEY, MM_HOSTKEY, MM_USERKEY, MM_RSAHOSTKEY, MM_RSAUSERKEY}; + +struct monitor; +struct mm_master; +struct passwd; +struct Authctxt; + +DH *mm_choose_dh(int, int, int); +int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int); +void mm_inform_authserv(char *, char *); +struct passwd *mm_getpwnamallow(const char *); +int mm_auth_password(struct Authctxt *, char *); +int mm_key_allowed(enum mm_keytype, char *, char *, Key *); +int mm_user_key_allowed(struct passwd *, Key *); +int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); +int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); +int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); +int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); +int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); +BIGNUM *mm_auth_rsa_generate_challenge(Key *); + +void mm_terminate(void); +int mm_pty_allocate(int *, int *, char *, int); +void mm_session_pty_cleanup2(void *); + +/* SSHv1 interfaces */ +void mm_ssh1_session_id(u_char *); +int mm_ssh1_session_key(BIGNUM *); + +/* Key export functions */ +struct Newkeys *mm_newkeys_from_blob(u_char *, int); +int mm_newkeys_to_blob(int, u_char **, u_int *); + +void monitor_apply_keystate(struct monitor *); +void mm_get_keystate(struct monitor *); +void mm_send_keystate(struct monitor*); + +/* bsdauth */ +int mm_bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **); +int mm_bsdauth_respond(void *, u_int, char **); + +/* skey */ +int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **); +int mm_skey_respond(void *, u_int, char **); + +/* zlib allocation hooks */ + +void *mm_zalloc(struct mm_master *, u_int, u_int); +void mm_zfree(struct mm_master *, void *); +void mm_init_compression(struct mm_master *); + +#endif /* _MM_H_ */ diff --git a/crypto/dist/ssh/myproposal.h b/crypto/dist/ssh/myproposal.h index 3dcdd0a6d33..9b6db731583 100644 --- a/crypto/dist/ssh/myproposal.h +++ b/crypto/dist/ssh/myproposal.h @@ -1,5 +1,5 @@ -/* $NetBSD: myproposal.h,v 1.1.1.7 2002/03/08 01:20:47 itojun Exp $ */ -/* $OpenBSD: myproposal.h,v 1.13 2002/01/21 22:30:12 markus Exp $ */ +/* $NetBSD: myproposal.h,v 1.1.1.8 2002/04/22 07:37:30 itojun Exp $ */ +/* $OpenBSD: myproposal.h,v 1.14 2002/04/03 09:26:11 markus Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -28,7 +28,7 @@ #define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss" #define KEX_DEFAULT_ENCRYPT \ "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \ - "aes192-cbc,aes256-cbc" + "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se" #define KEX_DEFAULT_MAC \ "hmac-md5,hmac-sha1,hmac-ripemd160," \ "hmac-ripemd160@openssh.com," \ diff --git a/crypto/dist/ssh/nchan.c b/crypto/dist/ssh/nchan.c index 41f2a9c9a1e..1a44681331c 100644 --- a/crypto/dist/ssh/nchan.c +++ b/crypto/dist/ssh/nchan.c @@ -1,4 +1,4 @@ -/* $NetBSD: nchan.c,v 1.1.1.10 2002/03/08 01:20:49 itojun Exp $ */ +/* $NetBSD: nchan.c,v 1.1.1.11 2002/04/22 07:37:31 itojun Exp $ */ /* * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. * @@ -24,7 +24,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: nchan.c,v 1.44 2002/01/21 23:27:10 markus Exp $"); +RCSID("$OpenBSD: nchan.c,v 1.45 2002/03/25 21:13:51 markus Exp $"); #include "ssh1.h" #include "ssh2.h" @@ -303,6 +303,7 @@ static void chan_rcvd_eof2(Channel *c) { debug("channel %d: rcvd eof", c->self); + c->flags |= CHAN_EOF_RCVD; if (c->ostate == CHAN_OUTPUT_OPEN) chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); } @@ -331,6 +332,7 @@ chan_send_eof2(Channel *c) packet_start(SSH2_MSG_CHANNEL_EOF); packet_put_int(c->remote_id); packet_send(); + c->flags |= CHAN_EOF_SENT; break; default: error("channel %d: cannot send eof for istate %d", @@ -366,7 +368,8 @@ chan_rcvd_ieof(Channel *c) else chan_rcvd_ieof1(c); if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && - buffer_len(&c->output) == 0) + buffer_len(&c->output) == 0 && + !CHANNEL_EFD_OUTPUT_ACTIVE(c)) chan_obuf_empty(c); } void @@ -405,39 +408,30 @@ chan_is_dead(Channel *c, int send) debug("channel %d: is dead", c->self); return 1; } - /* - * we have to delay the close message if the efd (for stderr) is - * still active - */ - if (((c->extended_usage != CHAN_EXTENDED_IGNORE) && - buffer_len(&c->extended) > 0) -#if 0 - || ((c->extended_usage == CHAN_EXTENDED_READ) && - c->efd != -1) -#endif - ) { - debug2("channel %d: active efd: %d len %d type %s", - c->self, c->efd, buffer_len(&c->extended), - c->extended_usage==CHAN_EXTENDED_READ ? - "read": "write"); - } else { - if (!(c->flags & CHAN_CLOSE_SENT)) { - if (send) { - chan_send_close2(c); - } else { - /* channel would be dead if we sent a close */ - if (c->flags & CHAN_CLOSE_RCVD) { - debug("channel %d: almost dead", - c->self); - return 1; - } + if ((datafellows & SSH_BUG_EXTEOF) && + c->extended_usage == CHAN_EXTENDED_WRITE && + c->efd != -1 && + buffer_len(&c->extended) > 0) { + debug2("channel %d: active efd: %d len %d", + c->self, c->efd, buffer_len(&c->extended)); + return 0; + } + if (!(c->flags & CHAN_CLOSE_SENT)) { + if (send) { + chan_send_close2(c); + } else { + /* channel would be dead if we sent a close */ + if (c->flags & CHAN_CLOSE_RCVD) { + debug("channel %d: almost dead", + c->self); + return 1; } } - if ((c->flags & CHAN_CLOSE_SENT) && - (c->flags & CHAN_CLOSE_RCVD)) { - debug("channel %d: is dead", c->self); - return 1; - } + } + if ((c->flags & CHAN_CLOSE_SENT) && + (c->flags & CHAN_CLOSE_RCVD)) { + debug("channel %d: is dead", c->self); + return 1; } return 0; } diff --git a/crypto/dist/ssh/packet.h b/crypto/dist/ssh/packet.h index 9bbe4fa0f91..58e3893fffe 100644 --- a/crypto/dist/ssh/packet.h +++ b/crypto/dist/ssh/packet.h @@ -1,5 +1,5 @@ -/* $NetBSD: packet.h,v 1.1.1.10 2002/03/08 01:20:53 itojun Exp $ */ -/* $OpenBSD: packet.h,v 1.33 2002/03/04 17:27:39 stevesk Exp $ */ +/* $NetBSD: packet.h,v 1.1.1.11 2002/04/22 07:37:33 itojun Exp $ */ +/* $OpenBSD: packet.h,v 1.34 2002/03/18 17:16:38 markus Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -57,6 +57,16 @@ void *packet_get_string(u_int *length_ptr); void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2))); void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void set_newkeys(int mode); +int packet_get_keyiv_len(int); +void packet_get_keyiv(int, u_char *, u_int); +int packet_get_keycontext(int, u_char *); +void packet_set_keycontext(int, u_char *); +u_int32_t packet_get_seqnr(int); +void packet_set_seqnr(int, u_int32_t); +int packet_get_ssh1_cipher(void); +void packet_set_iv(int, u_char *); + void packet_write_poll(void); void packet_write_wait(void); int packet_have_data_to_write(void); diff --git a/crypto/dist/ssh/scard.h b/crypto/dist/ssh/scard.h index 929f5d16f47..e90848f5404 100644 --- a/crypto/dist/ssh/scard.h +++ b/crypto/dist/ssh/scard.h @@ -1,5 +1,5 @@ -/* $NetBSD: scard.h,v 1.1.1.2 2002/03/08 01:21:47 itojun Exp $ */ -/* $OpenBSD: scard.h,v 1.7 2002/03/04 17:27:39 stevesk Exp $ */ +/* $NetBSD: scard.h,v 1.1.1.3 2002/04/22 07:38:00 itojun Exp $ */ +/* $OpenBSD: scard.h,v 1.10 2002/03/25 17:34:27 markus Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -25,17 +25,17 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <openssl/engine.h> - #ifndef SCARD_H #define SCARD_H +#include "key.h" + #define SCARD_ERROR_FAIL -1 #define SCARD_ERROR_NOCARD -2 #define SCARD_ERROR_APPLET -3 -Key *sc_get_key(const char*); -ENGINE *sc_get_engine(void); +Key **sc_get_keys(const char*, const char*); void sc_close(void); +int sc_put_key(Key *, const char*); #endif diff --git a/crypto/dist/ssh/scard/Ssh.bin.uu b/crypto/dist/ssh/scard/Ssh.bin.uu index 1062e21d68c..ea3986a694a 100644 --- a/crypto/dist/ssh/scard/Ssh.bin.uu +++ b/crypto/dist/ssh/scard/Ssh.bin.uu @@ -1,16 +1,17 @@ begin 644 Ssh.bin -M`P)!%P`501P`;``!`C@"`/Y@\`4`_J'P!0!!%T$;`?Z@\`4`01=!&@'^>/,! -M`4$701P!_G#S%P'^0],1`?Y@\!0`_G/S'0#^<]4``D$7L`4`_F'3``!!%T$9 -M`?YATP4`_G/5"P7^8=,'`OZAT`$!_J#0$@1!%T$8`0```$$7!`$&`/Y@`;@` -M`$$8\`H(`$$9\`H``$$:\@\``$$;\B$``$$<\A```/`&__(```0(`!8```9C -M""T#"<(H+00$*"T%""A;`&19``#P$/_R`P(&`0#(```38`!!70!&$UP`1@09 -M":1+``D*D`!@`"@37`!&!!E6`````*(````$____P````*$````0````*@`` -M`"````"-````,````&H37`!&`QD(2@`)"FX`8``H$UP`1@<9"@#_/2!@`$L1 -M2@`)"F<`8``H$UP`'A-<`$8($1-<`$8(7@!0"!%@`%59"C\`8`!:*PIS:&`` -M6BL37`!&`P,*`(!@`%\K`PH`@&``55D37`!&`P<H$UP`1@0#*`,%8`!565D* -M;0!@`"A9`/`"__(!`0$)``@```J0`&``*%D`\!/_\@$!`@D`#```8D$7+5\` -M/"M9````\!+_]@$!`P$`&```$UP`'EX`,D4`#Q-<`!X*`,@)$%X`-P17L`7_ -M\@$!!`(`/```$U\``!-B_J$M7P`%70`*$V+^H"U?``]=`!038OYX+0H$`%\` -<&5T`'@H$`&``(T4`"0IG`&``*!->`"U9```````` +M`P)!&P`801X`>``!`E@"`/Y@\`4`_J'P!0!!&T$=`?Z@\`4`01M!'`'^>/,! +M`4$;01X!_G#S%P'^0],1`?Y@\!0`_G/S'0#^<]4``D$;L`4`_F'3``#^8=,% +M`/ZAT`$!_J#0)P'^H],*`?ZCTPD`_G/5"P7^8=,'`OZAT`H`_J#0$@3^:-,@ +M`T$;`P`%`/Y@`<P``$$<\@\``$$=\B$``$$>\A```/`0__(%`@8!`0H``&`` +M0205!!D)I$L`"0J0`&``*!4$&58``````.P````%____P````.D````0```` +M,P```"````#'````,````(T````R````V!4#&0A*``D*;@!@`"@5!QD*`/\] +M(6``1A)*``D*9P!@`"@*/P!@`$LK"1)@`$LK!6``4!P$#00#2@`.#01@`%5@ +M`%I@`"@37``>%0@2%0A>`%\($F``9%(`:`H_`&``2RL*<VA@`$LK8`!I"1`U +M(14#`Q)@`&X<!`T$`TL`"P,28`!D4@`.#01@`%5@`%I@`"A2`"X5`PH$`&`` +M<RL#!6``9%(`'14#"@$"8`!S*P,%8`!D4@`,4@`)"FT`8``H60``\`+_\@$! +M`0D`"```"I``8``H60#P$__R`0$""0`,``!B01LM7P`\*UD```#P$O_V`0$# +M`0`8```37``>7@`R10`/$UP`'@H`R`D07@`W!%>P!?_R`0$$`@`\```37P`` +M$V+^H2U?``5=``H38OZ@+5\`#UT`%!-B_G@M"@0`7P`970`>"@0`8``C10`) +/"F<`8``H$UX`+5D````` ` end diff --git a/crypto/dist/ssh/scard/Ssh.java b/crypto/dist/ssh/scard/Ssh.java index 99208f14f99..9a47aca25d0 100644 --- a/crypto/dist/ssh/scard/Ssh.java +++ b/crypto/dist/ssh/scard/Ssh.java @@ -1,4 +1,4 @@ -// $Id: Ssh.java,v 1.1.1.1 2001/09/27 02:01:05 itojun Exp $ +// $Id: Ssh.java,v 1.1.1.2 2002/04/22 07:38:04 itojun Exp $ // // Ssh.java // SSH / smartcard integration project, smartcard side @@ -42,6 +42,9 @@ import javacardx.crypto.*; public class Ssh extends javacard.framework.Applet { + // Change this when the applet changes; hi byte is major, low byte is minor + static final short applet_version = (short)0x0102; + /* constants declaration */ // code of CLA byte in the command APDU header static final byte Ssh_CLA =(byte)0x05; @@ -50,20 +53,19 @@ public class Ssh extends javacard.framework.Applet static final byte DECRYPT = (byte) 0x10; static final byte GET_KEYLENGTH = (byte) 0x20; static final byte GET_PUBKEY = (byte) 0x30; + static final byte GET_VERSION = (byte) 0x32; static final byte GET_RESPONSE = (byte) 0xc0; - /* instance variables declaration */ static final short keysize = 1024; + static final short root_fid = (short)0x3f00; + static final short privkey_fid = (short)0x0012; + static final short pubkey_fid = (short)(('s'<<8)|'h'); - //RSA_CRT_PrivateKey rsakey; + /* instance variables declaration */ AsymKey rsakey; CyberflexFile file; CyberflexOS os; - byte buffer[]; - - static byte[] keyHdr = {(byte)0xC2, (byte)0x01, (byte)0x05}; - private Ssh() { file = new CyberflexFile(); @@ -98,7 +100,8 @@ public class Ssh extends javacard.framework.Applet // APDU object carries a byte array (buffer) to // transfer incoming and outgoing APDU header // and data bytes between card and CAD - buffer = apdu.getBuffer(); + byte buffer[] = apdu.getBuffer(); + short size, st; // verify that if the applet can accept this // APDU message @@ -111,29 +114,47 @@ public class Ssh extends javacard.framework.Applet if (buffer[ISO.OFFSET_CLA] != Ssh_CLA) ISOException.throwIt(ISO.SW_CLA_NOT_SUPPORTED); //decrypt (apdu); - short size = (short) (buffer[ISO.OFFSET_LC] & 0x00FF); + size = (short) (buffer[ISO.OFFSET_LC] & 0x00FF); if (apdu.setIncomingAndReceive() != size) ISOException.throwIt (ISO.SW_WRONG_LENGTH); + // check access; depends on bit 2 (x/a) + file.selectFile(root_fid); + file.selectFile(privkey_fid); + st = os.checkAccess(ACL.EXECUTE); + if (st != ST.ACCESS_CLEARED) { + CyberflexAPDU.prepareSW1SW2(st); + ISOException.throwIt(CyberflexAPDU.getSW1SW2()); + } + rsakey.cryptoUpdate (buffer, (short) ISO.OFFSET_CDATA, size, buffer, (short) ISO.OFFSET_CDATA); apdu.setOutgoingAndSend ((short) ISO.OFFSET_CDATA, size); - return; + break; case GET_PUBKEY: - file.selectFile((short)(0x3f<<8)); // select root - file.selectFile((short)(('s'<<8)|'h')); // select public key file - os.readBinaryFile (buffer, (short)0, (short)0, (short)(keysize/8)); - apdu.setOutgoingAndSend((short)0, (short)(keysize/8)); - return; + file.selectFile(root_fid); // select root + file.selectFile(pubkey_fid); // select public key file + size = (short)(file.getFileSize() - 16); + st = os.readBinaryFile(buffer, (short)0, (short)0, size); + if (st == ST.SUCCESS) + apdu.setOutgoingAndSend((short)0, size); + else { + CyberflexAPDU.prepareSW1SW2(st); + ISOException.throwIt(CyberflexAPDU.getSW1SW2()); + } + break; case GET_KEYLENGTH: - buffer[0] = (byte)((keysize >> 8) & 0xff); - buffer[1] = (byte)(keysize & 0xff); + Util.setShort(buffer, (short)0, keysize); + apdu.setOutgoingAndSend ((short)0, (short)2); + break; + case GET_VERSION: + Util.setShort(buffer, (short)0, applet_version); apdu.setOutgoingAndSend ((short)0, (short)2); - return; + break; case GET_RESPONSE: - return; + break; default: ISOException.throwIt (ISO.SW_INS_NOT_SUPPORTED); } diff --git a/crypto/dist/ssh/session.h b/crypto/dist/ssh/session.h index 3f504323246..cec8a2873f8 100644 --- a/crypto/dist/ssh/session.h +++ b/crypto/dist/ssh/session.h @@ -1,5 +1,5 @@ -/* $NetBSD: session.h,v 1.1.1.6 2002/03/08 01:21:18 itojun Exp $ */ -/* $OpenBSD: session.h,v 1.14 2002/02/03 17:53:25 markus Exp $ */ +/* $NetBSD: session.h,v 1.1.1.7 2002/04/22 07:37:42 itojun Exp $ */ +/* $OpenBSD: session.h,v 1.17 2002/03/29 18:59:32 markus Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -27,12 +27,46 @@ #ifndef SESSION_H #define SESSION_H +#define TTYSZ 64 +typedef struct Session Session; +struct Session { + int used; + int self; + struct passwd *pw; + Authctxt *authctxt; + pid_t pid; + /* tty */ + char *term; + int ptyfd, ttyfd, ptymaster; + int row, col, xpixel, ypixel; + char tty[TTYSZ]; + /* last login */ + char hostname[MAXHOSTNAMELEN]; + time_t last_login_time; + /* X11 */ + int display_number; + char *display; + int screen; + char *auth_display; + char *auth_proto; + char *auth_data; + int single_connection; + /* proto 2 */ + int chanid; + int is_subsystem; +}; + void do_authenticated(Authctxt *); int session_open(Authctxt*, int); int session_input_channel_req(Channel *, const char *); void session_close_by_pid(pid_t, int); void session_close_by_channel(int, void *); -void session_destroy_all(void); +void session_destroy_all(void (*)(Session *)); +void session_pty_cleanup2(void *); +Session *session_new(void); +Session *session_by_tty(char *); +void session_close(Session *); +void do_setusercontext(struct passwd *); #endif diff --git a/crypto/dist/ssh/ttymodes.c b/crypto/dist/ssh/ttymodes.c index 5bef46498be..b6924858819 100644 --- a/crypto/dist/ssh/ttymodes.c +++ b/crypto/dist/ssh/ttymodes.c @@ -1,4 +1,4 @@ -/* $NetBSD: ttymodes.c,v 1.1.1.7 2002/03/08 01:21:46 itojun Exp $ */ +/* $NetBSD: ttymodes.c,v 1.1.1.8 2002/04/22 07:37:59 itojun Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -44,7 +44,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: ttymodes.c,v 1.16 2001/12/27 20:39:58 markus Exp $"); +RCSID("$OpenBSD: ttymodes.c,v 1.17 2002/03/19 10:49:35 markus Exp $"); #include "packet.h" #include "log.h" @@ -403,17 +403,17 @@ tty_parse_modes(int fd, int *n_bytes_ptr) * SSH1: * Opcodes 1 to 127 are defined to have * a one-byte argument. - * Opcodes 128 to 159 are defined to have - * an integer argument. - */ + * Opcodes 128 to 159 are defined to have + * an integer argument. + */ if (opcode > 0 && opcode < 128) { n_bytes += 1; (void) packet_get_char(); break; } else if (opcode >= 128 && opcode < 160) { - n_bytes += 4; - (void) packet_get_int(); - break; + n_bytes += 4; + (void) packet_get_int(); + break; } else { /* * It is a truly undefined opcode (160 to 255). @@ -424,7 +424,7 @@ tty_parse_modes(int fd, int *n_bytes_ptr) */ log("parse_tty_modes: unknown opcode %d", opcode); goto set; - } + } } else { /* * SSH2: @@ -441,7 +441,7 @@ tty_parse_modes(int fd, int *n_bytes_ptr) log("parse_tty_modes: unknown opcode %d", opcode); goto set; } - } + } } } diff --git a/crypto/dist/ssh/uidswap.c b/crypto/dist/ssh/uidswap.c index 58b5435009b..09b38805e86 100644 --- a/crypto/dist/ssh/uidswap.c +++ b/crypto/dist/ssh/uidswap.c @@ -1,4 +1,4 @@ -/* $NetBSD: uidswap.c,v 1.1.1.7 2002/03/08 01:21:46 itojun Exp $ */ +/* $NetBSD: uidswap.c,v 1.1.1.8 2002/04/22 07:38:00 itojun Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -13,7 +13,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: uidswap.c,v 1.19 2001/12/19 07:18:56 deraadt Exp $"); +RCSID("$OpenBSD: uidswap.c,v 1.20 2002/04/01 21:50:51 stevesk Exp $"); #include "log.h" #include "uidswap.h" @@ -72,7 +72,6 @@ temporarily_use_uid(struct passwd *pw) /* Set the effective uid to the given (unprivileged) uid. */ if (setgroups(user_groupslen, user_groups) < 0) fatal("setgroups: %.100s", strerror(errno)); - pw->pw_gid = pw->pw_gid; if (setegid(pw->pw_gid) < 0) fatal("setegid %u: %.100s", (u_int) pw->pw_gid, strerror(errno)); |
