This is version 4 of the ssh jumbo patch. Apply by doing: cd /usr/src mkdir usr.bin/ssh/lib patch -p0 < 005_sshjumbo.patch cd usr.bin/ssh make obj make make install update your /etc/sshd_config and /etc/ssh_config files, as needed. Index: usr.bin/ssh/ChangeLog =================================================================== RCS file: ChangeLog diff -N ChangeLog --- /tmp/cvsyHrqq31367 Wed Dec 8 12:42:01 1999 +++ /dev/null Wed Dec 8 12:40:35 1999 @@ -1,578 +0,0 @@ -Fri Nov 17 16:19:20 1995 Tatu Ylonen - - * Released 1.2.12. - - * channels.c: Commented out debugging messages about output draining. - - * Added file OVERVIEW to give some idea about the structure of the - ssh software. - -Thu Nov 16 16:40:17 1995 Tatu Ylonen - - * canohost.c (get_remote_hostname): Don't ever return NULL (causes - segmentation violation). - - * sshconnect.c: Host ip address printed incorrectly with -v. - - * Implemented SSH_TTY environment variable. - -Wed Nov 15 01:47:40 1995 Tatu Ylonen - - * Implemented server and client option KeepAlive to specify - whether to set SO_KEEPALIVE. Both default to "yes"; to disable - keepalives, set the value to "no" in both the server and the - client configuration files. Updated manual pages. - - * sshd.c: Fixed Solaris utmp problem: wrong pid stored in utmp - (patch from Petri Virkkula ). - - * login.c (record_logout): Fixed removing user from utmp on BSD - (with HAVE_LIBUTIL_LOGIN). - - * Added cleanup functions to be called from fatal(). Arranged for - utmp to be cleaned if sshd terminates by calling fatal (e.g., - after dropping connection). Eliminated separate client-side - fatal() functions and moved fatal() to log-client.c. Made all - cleanups, including channel_stop_listening() and packet_close() - be called using this mechanism. - -Thu Nov 9 09:58:05 1995 Tatu Ylonen - - * sshd.c: Permit immediate login with empty password only if - password authentication is allowed. - -Wed Nov 8 00:43:55 1995 Tatu Ylonen - - * Eliminated unix-domain X11 forwarding. Inet-domain forwarding is - now the only supported form. Renamed server option - X11InetForwarding to X11Forwarding, and eliminated - X11UnixForwarding. Updated documentation. Updated RFC (marked - the SSH_CMSG_X11_REQUEST_FORWARDING message (code 26) as - obsolete, and removed all references to it). Increased protocol - version number to 1.3. - - * scp.c (main): Added -B (BatchMode). Updated manual page. - - * Cleaned up and updated all manual pages. - - * clientloop.c: Added new escape sequences ~# (lists forwarded - connections), ~& (background ssh when waiting for forwarded - connections to terminate), ~? (list available escapes). - Polished the output of the connection listing. Updated - documentation. - - * uidswap.c: If _POSIX_SAVED_IDS is defined, don't change the real - uid. Assume that _POSIX_SAVED_IDS also applies to seteuid. - This may solve problems with tcp_wrappers (libwrap) showing - connections as coming from root. - -Tue Nov 7 20:28:57 1995 Tatu Ylonen - - * Added RandomSeed server configuration option. The argument - specifies the location of the random seed file. Updated - documentation. - - * Locate perl5 in configure. Generate make-ssh-known-hosts (with - the correct path for perl5) in Makefile.in, and install it with - the other programs. Updated manual page. - - * sshd.c (main): Added a call to umask to set the umask to a - reasonable value. - - * compress.c (buffer_compress): Fixed to follow the zlib - documentation (which is slightly confusing). - - * INSTALL: Added information about Linux libc.so.4 problem. - -Mon Nov 6 15:42:36 1995 Tatu Ylonen - - * (Actually autoconf fix) Installed patch to AC_ARG_PROGRAM. - - * sshd.c, sshd.8.in: Renamed $HOME/.environment -> - $HOME/.ssh/environment. - - * configure.in: Disable shadow password checking on convex. - Convex has /etc/shadow, but sets pw_passwd automatically if - running as root. - - * Eliminated HAVE_ETC_MASTER_PASSWD (NetBSD, FreeBSD); the - pw_passwd field is automatically filled if running as root. - Put explicit code in configure.in to prevent shadow password - checking on FreeBSD and NetBSD. - - * serverloop.c (signchld_handler): Don't print error if wait - returns -1. - - * Makefile.in (install): Fixed modes of data files. - - * Makefile.in (install): Make links for slogin.1. - - * make-ssh-known-hosts: Merged a patch from melo@ci.uminho.pt to - fix the ping command. - -Fri Nov 3 16:25:28 1995 Tatu Ylonen - - * ssh.1.in: Added more information about X11 forwarding. - -Thu Nov 2 18:42:13 1995 Tatu Ylonen - - * Changes to use O_NONBLOCK_BROKEN consistently. - - * pty.c (pty_make_controlling_tty): Use setpgid instead of - setsid() on Ultrix. - - * includes.h: Removed redundant #undefs for Ultrix and Sony News; - these are already handled in configure.in. - -Tue Oct 31 13:31:28 1995 Tatu Ylonen - - * configure.in: Define SSH_WTMP to /var/adm/wtmp is wtmp not found. - - * configure.in: Disable vhangup on Ultrix. I am told this fixes - the server problems. - -Sat Oct 28 14:22:05 1995 Tatu Ylonen - - * sshconnect.c: Fixed a bug in connecting to a multi-homed host. - Restructured the connecting code to never try to use the same - socket a second time after a failed connection. - - * Makefile.in: Added explicit -m option to install, and umask 022 - when creating directories and the host key. - -Fri Oct 27 01:05:10 1995 Tatu Ylonen - - * Makefile.in: Added cleaning of $(ZLIBDIR) to clean and distclean. - - * login.c (get_last_login_time): Fixed a typo (define -> defined). - -Thu Oct 26 01:28:07 1995 Tatu Ylonen - - * configure.in: Moved testing for ANSI C compiler after the host - specific code (problems on HPUX). - - * Minor fixes to /etc/default/login stuff from Bryan O'Sullivan. - - * Fixed .SH NAME sections in manual pages. - - * compress.c: Trying to fix a mysterious bug in the compression - glue. - - * ssh-1.2.11. - - * scp.c: disable agent forwarding when running ssh from scp. - - * Added compression of plaintext packets using the gzip library - (zlib). Client configuration options Compression and - CompressionLevel (1-9 as in gzip). New ssh and scp option -C - (to enable compression). Updated RFC. - -Wed Oct 25 05:11:55 1995 Tatu Ylonen - - * Implemented ProxyCommand stuff based on patches from Bryan - O'Sullivan . - - * Merged BSD login/logout/lastlog patches from Mark Treacy - . - - * sshd.c: Added chdir("/"). - -Tue Oct 24 00:29:01 1995 Tatu Ylonen - - * Merged RSA environment= patches from Felix Leitner - with some changes. - - * sshd.c: Made the packet code use two separate descriptors for - the connection (one for input, the other for output). This will - make future extensions easier (e.g., non-socket transports, etc.). - sshd -i now uses both stdin and stdout separately. - -Mon Oct 23 21:29:28 1995 Tatu Ylonen - - * sshd.c: Merged execle -> execve patches from Mark Martinec - . This may help with execle bugs on - Convex (environment not getting passed properly). This might - also solve similar problems on Sonys; please test! - - * Removed all compatibility code for protocol version 1.0. - THIS MEANS THAT WE ARE NO LONGER COMPATIBLE WITH SSH VERSIONS - PRIOR TO 1.1.0. - - * randoms.c (random_acquire_light_environmental_noise): If - /dev/random is available, read up to 32 bytes (256 bits) from - there in non-blocking mode, and mix the new random bytes into - the pool. - - * Added client configuration option StrictHostKeyChecking - (disabled by default). If this is enabled, the client will not - automatically add new host keys to $HOME/.ssh/known_hosts; - instead the connection will be refused if the host key is not - known. Similarly, if the host key has changed, the connection - will be refused instead if just issuing a warning. This - provides additional security against man-in-the-middle/trojan - horse attacks (especially in scripts where there is no-one to - see the warnings), but may be quite inconvenient in everyday - interactive use unless /etc/ssh_known_hosts is very complete, - because new host keys must now be added manually. - - * sshconnect.c (ssh_connect): Use the user's uid when creating the - socket and connecting it. I am hoping that this might help with - tcp_wrappers showing the remote user as root. - - * ssh.c: Try inet-domain X11 forwarding regardless of whether we - can get local authorization information. If we don't, we just - come up with fake information; the forwarding code will anyway - generate its own fake information and validate that the client - knows that information. It will then substitute our fake - information for that, but that info should get ignored by the - server if it doesn't support it. - - * Added option BatchMode to disable password/passphrase querying - in scripts. - - * auth-rh-rsa.c: Changed to use uid-swapping when reading - .ssh/known_hosts. - - * sshd.8.in (command): Improved documentation of file permissions - on the manual pages. - -Thu Oct 19 21:05:51 1995 Tatu Ylonen - - * ssh-add.c (add_file): Fixed a bug causing ssh to sometimes refer - to freed memory (comment -> saved_comment). - - * log-server.c: Added a prefix to debug/warning/error/fatal - messages describing message types. Syslog does not include that - information automatically. - -Sun Oct 8 01:56:01 1995 Tatu Ylonen - - * Merged /etc/default/login and MAIL environment variable changes - from Bryan O'Sullivan . - - mail spool file location - - process /etc/default/login - - add HAVE_ETC_DEFAULT_LOGIN - - new function child_get_env and read_etc_default_login (sshd.c) - - * ssh-add.c (add_file): Fixed asking for passphrase. - - * Makefile.in: Fixed installing configure-generated man pages when - compiling in a separate object directory. - - * sshd.c (main): Moved RSA key generation until after allocating - the port number. (Actually, the code got duplicated because we - never listen when run from inetd.) - - * ssh.c: Fixed a problem that caused scp to hang when called with - stdin closed. - -Sat Oct 7 03:08:06 1995 Tatu Ylonen - - * Added server config option StrictModes. It specifies whether to - check ownership and modes of home directory and .rhosts files. - - * ssh.c: If ssh is renamed/linked to a host name, connect to that - host. - - * serverloop.c, clientloop.c: Ignore EAGAIN reported on read from - connection. Solaris has a kernel bug which causes select() to - sometimes wake up even though there is no data available. - - * Display all open connections when printing the "Waiting for - forwarded connections to terminate" message. - - * sshd.c, readconf.c: Added X11InetForwarding and - X11UnixForwarding server config options. - -Thu Oct 5 17:41:16 1995 Tatu Ylonen - - * Some more SCO fixes. - -Tue Oct 3 01:04:34 1995 Tatu Ylonen - - * Fixes and cleanups in README, INSTALL, COPYING. - -Mon Oct 2 03:36:08 1995 Tatu Ylonen - - * ssh-add.c (add_file): Fixed a bug in ssh-add (xfree: NULL ...). - - * Removed .BR from ".SH NAME" in man pages. - -Sun Oct 1 04:16:07 1995 Tatu Ylonen - - * ssh-1.2.10. - - * configure.in: When checking that the compiler works, check that - it understands ANSI C prototypes. - - * Made uidswap error message a debug() to avoid confusing errors - on AIX (AIX geteuid is brain-damaged and fails even for root). - - * Fixed an error in sshd.8 (FacistLogging -> FascistLogging). - - * Fixed distribution in Makefile.in (missing manual page .in files). - -Sat Sep 30 17:38:46 1995 Tatu Ylonen - - * auth-rhosts.c: Fixed serious security problem in - /etc/hosts.equiv authentication. - -Fri Sep 29 00:41:02 1995 Tatu Ylonen - - * Include machine/endian.h on Paragon. - - * ssh-add.c (add_file): Made ssh-add keep asking for the - passphrase until the user just types return or cancels. - Make the dialog display the comment of the key. - - * Read use shosts.equiv in addition to /etc/hosts.equiv. - - * sshd.8 is now sshd.8.in and is processed by configure to - substitute the proper paths for various files. Ditto for ssh.1. - Ditto for make-ssh-known-hosts.1. - - * configure.in: Moved /etc/sshd_pid to PIDDIR/sshd.pid. PIDDIR - will be /var/run if it exists, and ETCDIR otherwise. - -Thu Sep 28 21:52:42 1995 Tatu Ylonen - - * On Ultrix, check if sys/syslog.h needs to be included in - addition to syslog.h. - - * make-ssh-known-hosts.pl: Merged Kivinen's fixes for HPUX. - - * configure.in: Put -lwrap, -lsocks, etc. at the head of LIBS. - - * Fixed case-insensitivity in auth-rhosts.c. - - * Added missing socketpair.c to EXTRA_SRCS (needed on SCO), plus - other SCO fixes. - - * Makefile.in: Fixed missing install_prefixes. - -Wed Sep 27 03:57:00 1995 Tatu Ylonen - - * ssh-1.2.9. - - * Added SOCKS support. - - * Fixed default setting of IgnoreRhosts option. - - * Pass the magic cookie to xauth in stdin instead of command line; - the command line is visible in ps. - - * Added processing $HOME/.ssh/rc and /etc/sshrc. - - * Added a section to sshd.8 on what happens at login time. - -Tue Sep 26 01:27:40 1995 Tatu Ylonen - - * Don't define speed_t on SunOS 4.1.1; it conflicts with system - headers. - - * Added support for .hushlogin. - - * Added --with-etcdir. - - * Read $HOME/.environment after /etc/environment. - -Mon Sep 25 03:26:06 1995 Tatu Ylonen - - * Merged patches for SCO Unix (from Michael Henits). - -Sun Sep 24 22:28:02 1995 Tatu Ylonen - - * Added ssh option ConnectionAttempts. - -Sat Sep 23 12:30:15 1995 Tatu Ylonen - - * sshd.c: Don't print last login time and /etc/motd if a command - has been specified (with ssh -t host command). - - * Added support for passing the screen number in X11 forwarding. - It is implemented as a compatible protocol extension, signalled - by SSH_PROTOFLAG_SCREEN_NUMBER by the child. - - * clientloop.c: Fixed bugs in the order in which things were - processed. This may solve problems with some data not getting - sent to the server as soon as possible (probably solves the TCP - forwarding delayed close problem). Also, it looked like window - changes might not get transmitted as early as possible in some - cases. - - * clientloop.c: Changed to detect window size change that - happened while ssh was suspended. - - * ssh.c: Moved the do_session function (client main loop) to - clientloop.c. Divided it into smaller functions. General cleanup. - - * ssh-1.2.8 - -Fri Sep 22 22:07:46 1995 Tatu Ylonen - - * sshconnect.c (ssh_login): Made ssh_login take the options - structure as argument, instead of the individual arguments. - - * auth-rhosts.c (check_rhosts_file): Added support for netgroups. - - * auth-rhosts.c (check_rhosts_file): Added support for negated - entries. - -Thu Sep 21 00:07:56 1995 Tatu Ylonen - - * auth-rhosts.c: Restructured rhosts authentication code. - Hosts.equiv now has same format as .rhosts: user names are allowed. - - * Added support for the Intel Paragon. - - * sshd.c: Don't use X11 forwarding with spoofing if no xauth - program. Changed configure.in to not define XAUTH_PATH if - there is no xauth program. - - * ssh-1.2.7 - - * sshd.c: Rewrote the code to build the environment. Now also reads - /etc/environment. - - * sshd.c: Fixed problems in libwrap code. --with-libwrap now - takes optional library name/path. - - * ssh-1.2.6 - - * Define USE_PIPES by default. - - * Added support for Univel Unixware and MachTen. - - * Added IgnoreRhosts server option. - - * Added USE_STRLEN_FOR_AF_UNIX; it is needed at least on MachTen. - -Wed Sep 20 02:41:02 1995 Tatu Ylonen - - * sshd.c (do_child): don't call packet_close when /etc/nologin, - because packet_close does shutdown, and the message does not get - sent. - - * pty.c (pty_allocate): Push ttcompat streams module. - - * randoms.c (random_acquire_light_environmental_noise): Don't use - the second argument to gettimeofday as it is not supported on - all systems. - - * login.c (record_login): Added NULL second argument to gettimeofday. - -Tue Sep 19 13:25:48 1995 Tatu Ylonen - - * fixed pclose wait() in sshd key regeneration (now only collects - easily available noise). - - * configure.in: test for bsdi before bsd*. - - * ssh.c: Don't print "Connection closed" if -q. - -Wed Sep 13 04:19:52 1995 Tatu Ylonen - - * Released ssh-1.2.5. - - * Hopefully fixed "Waiting for forwarded connections to terminate" - message. - - * randoms.c, md5.c: Large modifications to make these work on Cray - (which has no 32 bit integer type). - - * Fixed a problem with forwarded connection closes not being - reported immediately. - - * ssh.c: fixed rhosts authentication (broken by uid-swapping). - - * scp.c: Don't use -l if server user not specified (it made - setting User in the configuration file not work). - - * configure.in: don't use -pipe on BSDI. - - * randoms.c: Major modifications to make it work without 32 bit - integers (e.g. Cray). - - * md5.c: Major modifications to make it work without 32 bit - integers (e.g. Cray). - - * Eliminated HPSUX_BROKEN_PTYS. The code is now enabled by - default on all systems. - -Mon Sep 11 00:53:12 1995 Tatu Ylonen - - * sshd.c: don't include sshd pathname in log messages. - - * Added libwrap stuff (includes support for identd). - - * Added OSF/1 C2 extended security stuff. - - * Fixed interactions between getuid() and uid-swap stuff. - -Sun Sep 10 00:29:27 1995 Tatu Ylonen - - * serverloop.c: Don't send stdout data to client until after a few - milliseconds if there is very little data. This is because some - systems give data from pty one character at a time, which would - multiply data size by about 16. - - * serverloop.c: Moved server do_session to a separate file and - renamed it server_loop. Split it into several functions and - partially rewrote it. Fixed "cat /etc/termcap | ssh foo cat" hangup. - - * Screwed up something while checking stuff in under cvs. No harm, - but bogus log entries... - -Sat Sep 9 02:24:51 1995 Tatu Ylonen - - * minfd.c (_get_permanent_fd): Use SHELL environment variable. - - * channels.c (x11_create_display_inet): Created - HPSUX_NONSTANDARD_X11_KLUDGE; it causes DISPLAY to contain the - IP address of the host instead of the name, because HPSUX uses - some magic shared memory communication for local connections. - - * Changed SIGHUP processing in server; it should now work multiple - times. - - * Added length limits in many debug/log/error/fatal calls just in - case. - - * login.c (get_last_login_time): Fixed location of lastlog. - - * Rewrote all uid-swapping code. New files uidswap.h, uidswap.c. - - * Fixed several security problems involving chmod and chgrp (race - conditions). Added warnings about dubious modes for /tmp/.X11-unix. - -Fri Sep 8 20:03:36 1995 Tatu Ylonen - - * Changed readconf.c to never display anything from the config - file. This should now be prevented otherwise, but let's play safe. - - * log-server.c: Use %.500s in syslog() just to be sure (they - should already be shorter than 1024 though). - - * sshd.c: Moved setuid in child a little earlier (just to be - conservative, there was no security problem that I could detect). - - * README, INSTALL: Added info about mailing list and WWW page. - - * sshd.c: Added code to use SIGCHLD and wait zombies immediately. - - * Merged patch to set ut_addr in utmp. - - * Created ChangeLog and added it to Makefile.in. - - * Use read_passphrase instead of getpass(). - - * Added SSH_FALLBACK_CIPHER. Fixed a bug in default cipher - selection (IDEA used to be selected even if not supported by the - server). - - * Use no encryption for key files if empty passphrase. - - * Added section about --without-idea in INSTALL. - - * Version 1.2.0 was released a couple of days ago. - Index: usr.bin/ssh/INSTALL =================================================================== RCS file: INSTALL diff -N INSTALL --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsbLdgr31367 Wed Dec 8 12:42:01 1999 @@ -0,0 +1,409 @@ +This is a hacked-up version of ssh-1.2.12. + +The GMP and DES sources are now external to the distribution. To build +this software it is necessary to first have GMP and a DES +implementation installed somewhere. Some systems comes with GMP and +DES preinstalled. If your system doesn't; pick up the GMP sources from +your favorite GNU ftp site (ftp://prep.ai.mit.edu/pub/gnu/). There is +a free DES implementation made by Eric Young that can be found under +the name libdes-x.x.x.tar.gz, for example at +ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/. + +The distribution optionally supports Kerberos version 4 authentication +and AFS. If you want to build with Kerberos support and your system +comes with Kerberos preinstalled add the switch --with-krb4=/usr to +configure. Otherwise, first build and install Kerberos and then use +--with-krb4=/usr/whatever-directory. If you don't want Kerberos +support use --without-krb4 (the default). Kerberos can be found at +ftp://ftp.pdc.kth.se/pub/krb/src/. + +Compression support is now optional. If you don't have zlib installed +configure using --without-zlib or first install zlib. We have +succesfully used zlib-1.0.4.tar.gz + +For more detailed installation instructions read the rest of this file +and README.AFS-KERBEROS. + +---------------------------------------------------------------------------- +This file describes how to install the Secure Shell (ssh). Secure Shell is +a replacement for rlogin and rsh. It seamlessly encrypts all communications, +provides improved security, and has useful new features. + + +INSTALLATION + +For most machines and configurations, the following is all you need. + + ./configure + make + make install + +Then check (and edit if needed) the following files: + /etc/sshd_config (server configuration file) + /etc/ssh_config (client configuration file - defaults for users) + +You may also want to create the /etc/ssh_known_hosts for your site and update +it periodically. See the manual page for make-ssh-known-hosts on how to +do this easily. The file format is documented on the sshd manual page. + +The source is written in ANSI C, and requires an ANSI C compiler or GCC. +A copy of GCC is available on all major FTP sites (e.g., in +ftp:/prep.ai.mit.edu/pub/gnu). + + +CONFIGURATION OPTIONS + +The package comes with an Autoconf-generated configure script. The +script accepts several options + All standard options, including: + --prefix=PREFIX where to install files (default: subdirs of /usr/local) + --exec_prefix=PREFIX where to install executables (default: same as prefix) + --srcdir=DIR find sources in DIR (default: where configure is) + Specific options: + --with-rsh=PATH Use rsh specified by PATH when needed + --with-etcdir=PATH Store system files in the given dir (default: /etc) + --with-path=PATH Default path to pass to user shell. + --with-rsaref Use rsaref2 from rsaref2 subdirectory (see below). + --with-libwrap[=PATH] Use libwrap (tcp_wrappers) and identd (see below). + --with-socks[=PATH] Include SOCKS (firewall traversal) support. + --without-idea Don't include IDEA (see below). + --with-securid[=PATH] Support for the SecurID card (see README.SECURID). + --enable-warnings Adds -Wall to CFLAGS if using gcc. + +You may also want to configure the following variables: + CC=compiler specify name of the C compiler (default: gcc or cc) + CFLAGS=flags specify flags to C compiler (default: -O -g or just -O) + LDFLAGS=flags specify flags to linker (default: none) + +Alternate values can be given to configure in the environment, e.g.: + CC=xcc CFLAGS="-O2" LDFLAGS="-L/lib/zzz" ./configure +(Note that if you have already configured, and later decide to give +some values on the command line, you may need to say "make distclean" +before reconfiguring.) + + +CONFIGURATION FILES + +The server has a configuration file /etc/sshd_config, which specifies the +permitted authentication methods, hosts, port number, etc. The defaults are +acceptable for most sites, but you may want to check this file. Its format +is documented on the sshd manual page. + +The client reads a configuration file /etc/ssh_config, which gives +site-wide defaults for various options. Options in this file can be +overridden by per-user configuration files. The file is documented on +the ssh manual page. + + +MAKEFILE + +The Makefile is generated from Makefile.in by running configure. It supports +the following targets: + all: compile everything + install: install in $exec_prefix/bin and $prefix/man/man1. + uninstall: remove installed files + clean: remove object files and executables + distclean: remove anything not in the distribution + + +PORTABILITY + +This software has been used at least in the following environments. + + 386BSD 0.1; i386 + AIX 3.2.5, 4.1; RS6000, PowerPC + BSD 4.4; several platforms + BSD/OS 1.1, 2.0.1; i486 + BSD/386 1.1; i386 + ConvexOS 10.1; Convex + DGUX 5.4R2.10; DGUX + FreeBSD 1.x, 2.x; Pentium + HPUX 9.0x, 10.0; HPPA + IRIX 5.2, 5.3; SGI Indy + IRIX 6.0.1; Mips-R8000 + Linux 1.2.8 Slackware 2.1.0; i486 + Mach3; Mips + Mach3/Lites; i386 + Machten 2.2 + NetBSD 1.0A; Pentium, Sparc + OSF/1 3.0, 3.2, 3.2a; Alpha + Sequent Dynix/ptx 3.2.0 V2.1.0; i386 + SCO Unix; i386 (client only) + SINIX 5.42; Mips R4000 + Solaris 2.3, 2.4; Sparc + Sony NEWS-OS 3.3 (BSD 4.3); m68k + SunOS 4.1.2, 4.1.3, 4.1.4; Sparc + SysV 4.x; several platforms + Ultrix x.x; Mips + Unicos 8.0.3; Cray C90 + +Please report back any other environments where you have used ssh, +and send back any patches you had to do so that they can be integrated +to the distribution. The proper address is ossh-bugs@sics.se. +Always remember to mention the ssh version number and machine type in +your bug reports. Please include also the output of the -v option +from the client side, and the output of the -d option from the server, +if applicable. + +Not all compilers work in all environments. If you have problems, try +compiling with gcc-2.7. *** SPARC NOTE: gcc-2.7.0 appears to generate +bad code on Sparc (Solaris 2.3) when compiling without -O. Try +gcc-2.6.3 or compile with -O. *** + +Solaris 2.4 note: you need to install "kernel jumbo patch number +101945-32" (dated August 31, 1995) for ssh to work. The symptom is +that ssh dies with a "Resource temporarily unavailable" error. + +Linux note: Some linux systems have a bug which causes an error about +libc.so.4 when compiling ssh. This can be solved by any of the +following ways: + - Do "ln -s libc.sa /usr/lib/libg.sa" as root. + - Install gcc-2.7.0. + - Configure ssh with "CFLAGS=-O ./configure" (i.e., without debug info). +More information on this problem is available in +ftp://ftp.netcom.com/pub/ze/zenon/linux. + +BSDI BSD/OS note: Apparently the gcc that comes with BSD/OS is +broken. Use "CC=cc ./configure" or "setenv CC cc; ./configure" when +configuring to force it to use cc instead of gcc. + +ConvexOS note: Convex "make" is broken. Install GNU make first if you +have trouble compiling ssh. + + +COMPILING WITH RSAREF2 + +If you are using ssh in the United States, you may want to use the +RSAREF2 library from RSADSI. This may make it legal to use ssh +without a separate license for non-commercial purposes. RSAREF2 is +not included in the distribution; however, it is available on any +major ftp site around the world (e.g., +ftp://ftp.funet.fi/pub/crypt/cryptography/asymmetric/rsa/rsaref2.tar.gz). +The RSAREF2 distribution should be unpacked into "rsaref2" +subdirectory in the ssh distribution directory (a symbolic link to +rsaref2 is not sufficient). Configure should be given the +--with-rsaref option. (Note that there is no need to *compile* +rsaref2 manually; the ssh Makefile will compile those files it needs.) + +Using RSAREF outside the United States is not recommended and only +causes legal complications. + +RSAREF2 does not work for large key sizes (> 1024). This may be the +problem if you get "RSAPrivateDecrypt failed". + +On alpha, one should edit rsaref2/source/global.h, and make UINT4 +"unsigned int" instead of "unsigned long int". + + +LIBWRAP AND IDENTD + +Ssh does not normally use identd or tcp-wrappers. However, it can be +compiled to use these by adding --with-libwrap on the command line. +This requires that the tcp_wrappers libwrap.a library and the +associated tcpd.h have been installed somewhere where the compiler can +find them. With libwrap support, ssh will process the +/etc/hosts.allow and /etc/hosts.deny files, and use identd if required +by them. The name of the user on the client side (as returned by +identd) will be logged if requested by the configuration files. See +tcp_wrappers documentation for more information. + + +COMPILING WITHOUT IDEA + +The IDEA cipher can be freely used for non-commercial use. However, +commercial use may require a license in a number of countries. + +Ssh can be compiled without IDEA by using the --without-idea configure +option. This disables IDEA, and causes 3DES to be used for encrypting +key/identity files and as the default session cipher. (The default +session cipher can be changed by editing SSH_FALLBACK_CIPHER in +ssh.h.) + +If one disables IDEA after having used it for some time, it is +possible that there are key files around that were encrypted with IDEA. + +Key files can be converted to use 3DES by creating a special version +of ssh-keygen that includes IDEA (was compiled without +--without-idea), but that generates key files encrypted with 3DES +(edit SSH_AUTHFILE_CIPHER to be SSH_CIPHER_3DES even when WITHOUT_IDEA +is not defined). Any operation with re-encrypts the key file can be +used, such as changing the comment or changing the passphrase. + + +STARTING THE SERVER + +The server should be started at boot from /etc/rc or equivalent. It +need not be given any arguments; however, an optional "-b bits" flag +may be used to specify RSA key size (default is 768). Key sizes less +than 512 can be broken; larger key sizes generally mean more security +but require more time to generate and use. 1024 bits is secure for +any practical time with current technology. + +The server is not started using inetd, because it needs to generate +the RSA key before serving the connection, and this can take about a +minute on slower machines. On a fast machine, and small (breakable) +key size (< 512 bits) it may be feasible to start the server from +inetd on every connection. The server must be given "-i" flag if +started from inetd. + + +REPLACING RLOGIN AND RSH + +This software has been designed so that it can be installed with the +names rlogin, rsh, and rcp, and it will use the Secure Shell +protocol whenever the remote machine supports it, and will +automatically execute rlogin/rsh (after displaying a warning that +there is no encryption) if the remote host does not support Secure +Shell. + +Rlogin/rsh replacement is done as follows: + ./configure --with-rsh=RSH-PATH --program-transform-name='s/^s/r/' + make install + +where RSH-PATH is the complete pathname of the real rsh program. (You +may want to copy the old rsh program to a suitable location). + +This will create links for rlogin, rsh, and rcp. If you are +installing them in the same directory where rlogin etc. normally are +(e.g., /usr/bin), you must first move the original programs to some +other directory (e.g., /usr/lib/rsh). + +When doing this, you should also build a file containing the host keys of all +machines in your organization, and copy this file to /etc/ssh_known_hosts +on every machine. This will make .rhosts and /etc/hosts.equiv authentication +work for users without any changes to the user configuration, but will be +much more secure than conventional .rhosts and /etc/hosts.equiv authentication. +This will also protect the users against router attacks where someone (perhaps +remotely) reconfigures the routers to direct connections to a certain host +to a different machine, which can then grab any passwords which the user +types thinking he/she is connected to the real machine. + + +CLIENT SUID ROOT, SERVER RUN AS ROOT + +This package installs two programs that need special privileges. Ssh +is the client program, and it is by default installed as suid root, +because it needs to create a privileged port in order to use .rhosts +files for authentication. If it is not installed as suid root, it will +still be usable, but .rhosts authentication will not be available. Also, the +private host key file is readable by root only. + +Sshd is the daemon that listens for connections. It should preferably +be run as root, because it is by normally listening on a privileged +port, and it needs to be able to do setuid(), update utmp, chown ptys +etc. when a user logs in. If it is not run as root, explicit "-p +port" option must be given to specify an alternate port (same port +must also be specified for clients), "-h host_key_file_path" must be +given to specify an alternate host key file, and it cannot be used to +log in as any other user than the user running it (because it cannot +call setuid()). Also, if your system uses shadow passwords, password +authentication will not work when running as someone else than root. + +Both the server and the client have been carefully screened for +possible security problems, and are believed to be secure. However, +there can be no guarantee. If you find any problems, please report +them immediately. + + +COMMON PROBLEMS + +This section lists some common installation problems. + +Shadow passwords + + There are many different shadow password schemes. Ssh currently recognizes + and supports many of them; however, there are probably still many that + it does not understand. This may not be visible at compile time. + If your system uses shadow passwords, and password authentication does not + work even if sshd is running as root, this is probably your problem. + Please contact the author if this happens. Code to recognize (configure.in) + and use (auth-passwd.c) the shadow password mechanism on new systems + is highly welcome. + +login.c does not compile, or logging of logins does not work properly + + Mechanisms for updating wtmp, utmp, lastlog, and similar mechanisms + are not standardized. Ssh substitutes many of the functions of the + conventional login program. These functions are implemented in login.c. + You may need to modify this file to make it work on exotic systems. + Please send any modifications and bug fixes back to the author for inclusion + in the distribution. If you just want to try ssh, and cannot get this file + to compile, if is safe to define all of the functions as empty; however, + in that case logins will not be logged. + +Sshd does not start or dies immediately + + The easiest thing to do is to give the -d option to sshd. It will + then send debugging output to stderr (and syslog). The -d option + also has other side effects, e.g. the daemon will not fork and will + only serve a single connection before exiting. However, it is very + useful for debugging problems. + + Sshd sends debugging output to the system log. Check your system + log (and syslogd configuration) to see why it dies. One possible + reason is that your system does not have a proper host key in + /etc/ssh_host_key. You can either generate a key with ssh-keygen + (it is automatically generated by "make install"), or specify an + alternative key with the -h option to the server. Another reason + could be that the port which the server tries to listen is already + reserved by some other program. + +Rhosts authentication does not work + + By default, the server does not accept normal .rhosts or /etc/hosts.equiv + authentication, because they are fundamentally insecure and can be spoofed + by anyone with access to the local network. Rhosts authentication can be + enabled at compile time by giving the --with-rhosts option to configure. + + The preferred alternative is to collect the public host keys of the entire + site to a file, and copy this to /etc/ssh_known_hosts on every machine in + the organization running sshd. This will prevent all IP spoofing attacks + and provides improved security (provided rshd, rlogind, and rexecd are + disabled). + +Opening connections is too slow + + On very slow machines, encrypting and decrypting the session key may + be too slow. For example, on a heavily loaded sun3 it took + several minutes to log in with the default key sizes. When we changed it + to use shorter host key (512 bits) and server key (384 bits), + login time dropped to about a second. A symptom of this problem is + that "ssh -v hostname" waits for a long time after printing "Sent + encrypted session key". + + Shorter host keys can be generated with "ssh-keygen -b 512", giving + /etc/ssh_host_key as the file in which to save the key (with empty + passphrase). The server key size can be specified with the -b + option on sshd command line (typically, in /etc/rc.local). The + server must be restarted for changes to take effect. + +The program complains "Could not set controlling tty" or something similar + + There are many different styles of pseudo ttys. Ssh currently + supports about five different styles (plus variations of them). It + is quite possible that there are more variations, some of which are + not supported by existing code. Fixing the problem may require + adding new code in pty.c and configure.in. You are encouraged to + write the needed code and send a patch to the author, or at least + report the problem. + +General problem solving + + The client has -v option, which sends verbose output to stdout. It + is very helpful in solving problems. + + The server has -d option, which causes it to send verbose debugging + output to system log and stderr. This option also causes the server + to only serve a single connection and not fork, which helps debugging. + + +REPORTING PROBLEMS AND OTHER CONTACTS + +Please report any bugs, problems, and enhancements to +ossh-bugs@sics.se. + +There is a mailing list for ossh. It is ossh@sics.se. If you would +like to join, send a message to majordomo@sics.se with "subscribe +ossh" in body. + +Copyright (c) 1995 Tatu Ylonen , Espoo, Finland. Index: usr.bin/ssh/Makefile =================================================================== RCS file: /cvs/src/usr.bin/ssh/Makefile,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- usr.bin/ssh/Makefile 1999/09/27 23:47:43 1.4 +++ usr.bin/ssh/Makefile 1999/10/25 20:27:26 1.5 @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.4 1999/09/27 23:47:43 deraadt Exp $ +# $OpenBSD: Makefile,v 1.5 1999/10/25 20:27:26 markus Exp $ .include -SUBDIR= ssh sshd ssh-add ssh-keygen ssh-agent scp +SUBDIR= lib ssh sshd ssh-add ssh-keygen ssh-agent scp distribution: install -C -o root -g wheel -m 0644 ${.CURDIR}/ssh_config \ Index: usr.bin/ssh/Makefile.in =================================================================== RCS file: Makefile.in diff -N Makefile.in --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsLSrVi31367 Wed Dec 8 12:42:01 1999 @@ -0,0 +1,344 @@ +# +# Makefile.in +# +# Author: Tatu Ylonen +# +# Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +# All rights reserved +# +# Created: Wed Mar 22 17:37:49 1995 ylo +# +# $Id: Makefile.in,v 1.2 1999/09/26 21:47:52 deraadt dead $ +# + +srcdir = @srcdir@ + +VPATH = $(srcdir) + +install_prefix = +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin +sbindir = $(exec_prefix)/sbin +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man8dir = $(mandir)/man8 +etcdir = @ETCDIR@ +piddir = @PIDDIR@ + +CC = @CC@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +DEFS = @DEFS@ +LIBS = @LIBS@ +LIBOBJS = @LIBOBJS@ +CONFOBJS = @CONFOBJS@ + +MAKEDEP = @MAKEDEP@ +LN_S = @LN_S@ +RANLIB = @RANLIB@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +WISH = @WISH@ + +GMPLIBS = @GMPLIBS@ +GMPINCS = @GMPINCS@ + +KRB4_AUTH = @KRB4_AUTH@ +KRB4_ROOT = @KRB4_ROOT@ +KRB4_INCS = @KRB4_INCS@ +KRB4_LIBS = @KRB4_LIBS@ +RADIX = @RADIX@ + +RSAREFDEP = @RSAREFDEP@ + +transform = @program_transform_name@ + +HOST_KEY_FILE = $(etcdir)/ssh_host_key +HOST_CONFIG_FILE = $(etcdir)/ssh_config +SERVER_CONFIG_FILE = $(etcdir)/sshd_config + +SHELL = /bin/sh + +#ZLIBLIBS = -L$(ZLIBDIR) -lz +#ZINCS = + +RSAREFDIR = rsaref2 +RSAREFSRCDIR = $(RSAREFDIR)/source + +CIPHER_OBJS = cipher.o $(CONFOBJS) +COMMON_OBJS = $(LIBOBJS) \ + rsa.o randoms.o ssh_md5.o buffer.o packet.o \ + xmalloc.o ttymodes.o channels.o bufaux.o authfd.o authfile.o crc32.o \ + rsaglue.o match.o mpaux.o minfd.o $(CIPHER_OBJS) +SSHD_OBJS = sshd.o $(KRB4_AUTH) auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o pty.o \ + log-server.o login.o hostfile.o canohost.o servconf.o tildexpand.o \ + uidswap.o serverloop.o $(RADIX) $(COMMON_OBJS) +SSH_OBJS = ssh.o sshconnect.o log-client.o readconf.o hostfile.o readpass.o \ + tildexpand.o uidswap.o clientloop.o canohost.o $(RADIX) $(COMMON_OBJS) +KEYGEN_OBJS = ssh-keygen.o log-client.o readpass.o rsa.o randoms.o ssh_md5.o \ + buffer.o xmalloc.o authfile.o $(CIPHER_OBJS) mpaux.o \ + bufaux.o $(LIBOBJS) +AGENT_OBJS = ssh-agent.o log-client.o rsa.o randoms.o ssh_md5.o buffer.o \ + xmalloc.o bufaux.o authfd.o authfile.o rsaglue.o $(CIPHER_OBJS) \ + mpaux.o minfd.o $(LIBOBJS) +ADD_OBJS = ssh-add.o log-client.o readpass.o rsa.o randoms.o ssh_md5.o buffer.o \ + xmalloc.o bufaux.o authfd.o authfile.o $(CIPHER_OBJS) \ + mpaux.o minfd.o $(LIBOBJS) +SCP_OBJS = scp.o xmalloc.o +GEN_MINFD_OBJS = gen_minfd.o $(LIBOBJS) + +USER_SHELLS = sh jsh ksh csh tcsh bash zsh ash + +SRCS = $(SSHD_OBJS:.o=.c) $(SSH_OBJS:.o=.c) $(KEYGEN_OBJS:.o=.c) \ + $(AGENT_OBJS:.o=.c) $(ADD_OBJS:.o=.c) \ + $(SCP_OBJS:.o=.c) \ + $(GEN_MINFD_OBJS:.o=.c) +EXTRA_SRCS = memmove.c strerror.c remove.c random.c putenv.c osfc2.c \ + socketpair.c +MAN1PAGES = ssh-keygen.1 ssh-agent.1 ssh-add.1 scp.1 +MAN1GENERATED = ssh.1 +MAN1SOURCES = ssh.1.in ssh-keygen.1 ssh-agent.1 ssh-add.1 scp.1 +MAN8GENERATED = sshd.8 +MAN8SOURCES = sshd.8.in + +DISTFILES = COPYING.Ylonen README.AFS-KERBEROS README README.SECURID \ + INSTALL TODO OVERVIEW \ + configure configure.in config.guess config.sub Makefile.in \ + ssh-askpass.wish host_config.sample config.sample \ + acconfig.h config.h.in server_config.sample \ + $(MAN1SOURCES) $(MAN8SOURCES) *.c *.h install-sh \ + RFC.nroff RFC \ + ChangeLog + +DISTNAME = `sed 's/.*"\(.*\)".*/\1/' version.h` + +NORMAL_PROGRAMS = ssh-keygen ssh-askpass ssh-agent ssh-add scp + +SBIN_PROGRAMS = sshd +PROGRAMS = ssh $(SBIN_PROGRAMS) $(NORMAL_PROGRAMS) +SSH_PROGRAM = $(bindir)/ssh + +all: $(PROGRAMS) + +RFC: RFC.nroff rfc-pg + tbl RFC.nroff | nroff -ms | sed 's/FORMFEED\[Page/ [Page/' | ./rfc-pg -n5 >RFC + +rfc-pg: rfc-pg.c + $(CC) -o rfc-pg rfc-pg.c + +.c.o: + $(CC) -c -I. $(KRB4_INCS) $(GMPINCS) $(ZINCS) $(DEFS) -DHOST_KEY_FILE=\"$(HOST_KEY_FILE)\" -DHOST_CONFIG_FILE=\"$(HOST_CONFIG_FILE)\" -DSERVER_CONFIG_FILE=\"$(SERVER_CONFIG_FILE)\" -DSSH_PROGRAM=\"$(SSH_PROGRAM)\" -DETCDIR=\"$(etcdir)\" -DPIDDIR=\"$(piddir)\" $(CFLAGS) $< + +sshd: $(SSHD_OBJS) $(RSAREFDEP) + -rm -f sshd + $(CC) $(LDFLAGS) -o sshd $(SSHD_OBJS) $(GMPLIBS) $(ZLIBLIBS) $(KRB4_LIBS) $(LIBS) + +ssh: $(SSH_OBJS) $(RSAREFDEP) + -rm -f ssh + $(CC) $(LDFLAGS) -o ssh $(SSH_OBJS) $(GMPLIBS) $(ZLIBLIBS) $(KRB4_LIBS) $(LIBS) + +ssh-keygen: $(KEYGEN_OBJS) $(RSAREFDEP) + -rm -f ssh-keygen + $(CC) $(LDFLAGS) -o ssh-keygen $(KEYGEN_OBJS) $(GMPLIBS) $(KRB4_LIBS) $(LIBS) + +ssh-agent: $(AGENT_OBJS) $(RSAREFDEP) + -rm -f ssh-agent + $(CC) $(LDFLAGS) -o ssh-agent $(AGENT_OBJS) $(GMPLIBS) $(KRB4_LIBS) $(LIBS) + +ssh-add: $(ADD_OBJS) $(RSAREFDEP) + -rm -f ssh-add + $(CC) $(LDFLAGS) -o ssh-add $(ADD_OBJS) $(GMPLIBS) $(KRB4_LIBS) $(LIBS) + +scp: $(SCP_OBJS) $(LIBOBJS) + -rm -f scp + $(CC) $(LDFLAGS) -o scp $(SCP_OBJS) $(LIBOBJS) $(KRB4_LIBS) $(LIBS) + +ssh-askpass: ssh-askpass.wish + -rm -f ssh-askpass + echo "#! $(WISH) -f" >ssh-askpass + cat $(srcdir)/ssh-askpass.wish >>ssh-askpass + chmod +x ssh-askpass + +gen_minfd: $(GEN_MINFD_OBJS) + $(CC) $(LDFLAGS) -o gen_minfd $(GEN_MINFD_OBJS) $(LIBS) + +minfd.o: minfd.h +minfd.h: gen_minfd + rm -f minfd.h minfd.h~ + ./gen_minfd $(USER_SHELLS) > minfd.h~ + mv -f minfd.h~ minfd.h + +$(RSAREFSRCDIR)/librsaref.a: + -if test '!' -d $(RSAREFDIR); then \ + (cd $(srcdir); tar cf - $(RSAREFSRCDIR)) | tar xf -; fi + cd $(RSAREFSRCDIR); $(MAKE) -f ../../Makefile librsaref.a + +RSAREFSRCS = desc.c digit.c md2c.c md5c.c nn.c prime.c r_dh.c r_encode.c \ + r_enhanc.c r_keygen.c r_random.c r_stdlib.c rsa.c + +# Note: this target is used in a recursive make, with VPATH pointing to source +librsaref.a: + for i in $(RSAREFSRCS); do $(CC) $(CFLAGS) -c $$i; done + $(AR) rc librsaref.a $(RSAREFSRCS:.c=.o) + $(RANLIB) librsaref.a + +# Creates /etc/ssh_host_key +generate-host-key: + -@if test -f $(install_prefix)$(HOST_KEY_FILE); \ + then echo "You already have a host key in $(install_prefix)$(HOST_KEY_FILE)."; \ + else \ + umask 022; echo "Generating 1024 bit host key."; \ + ./ssh-keygen -b 1024 -f $(install_prefix)$(HOST_KEY_FILE) -N ''; \ + fi + +# Creates install directories +make-dirs: + -umask 022; if test '!' -d $(install_prefix)$(prefix); then \ + mkdir $(install_prefix)$(prefix); fi; \ + if test '!' -d $(install_prefix)$(exec_prefix); then \ + mkdir $(install_prefix)$(exec_prefix); fi; \ + if test '!' -d $(install_prefix)$(etcdir); then \ + mkdir $(install_prefix)$(etcdir); fi; \ + if test '!' -d $(install_prefix)$(bindir); then \ + mkdir $(install_prefix)$(bindir); fi; \ + if test '!' -d $(install_prefix)$(sbindir); then \ + mkdir $(install_prefix)$(sbindir); fi; \ + if test '!' -d $(install_prefix)$(mandir); then \ + mkdir $(install_prefix)$(mandir); fi; \ + if test '!' -d $(install_prefix)$(man1dir); then \ + mkdir $(install_prefix)$(man1dir); fi; \ + if test '!' -d $(install_prefix)$(man8dir); then \ + mkdir $(install_prefix)$(man8dir); fi + +# Ssh is much to large and hairy to be installed suid root by +# default. Disabled for now/bg. If you really need rhosts +# authentication do a manual chmod u+s $(install_prefix)$(bindir)/ssh. +# +# Ssh is preferably installed suid root. It can also be used non-root, +# but then it cannot connect from a privileged socket, and rhosts +# authentication will be disabled. +# +# Sshd is not suid root, but should preferably be run as root +# (otherwise it can only log in as the user it runs as, and must be +# bound to a non-privileged port). Also, password authentication may +# not be available if non-root and using shadow passwords. +install: $(PROGRAMS) make-dirs generate-host-key + $(INSTALL_PROGRAM) -o root -m 0755 ssh $(install_prefix)$(bindir)/ssh + -if test "`echo ssh | sed '$(transform)'`" '!=' ssh; then \ + rm -f $(install_prefix)$(bindir)/`echo ssh | sed '$(transform)'`; \ + $(LN_S) ssh \ + $(install_prefix)$(bindir)/`echo ssh | sed '$(transform)'`; fi + rm -f $(install_prefix)$(bindir)/slogin + $(LN_S) ssh $(install_prefix)$(bindir)/slogin + -if test "`echo slogin | sed '$(transform)'`" '!=' slogin; then \ + rm -f $(install_prefix)$(bindir)/`echo slogin | sed '$(transform)'`;\ + $(LN_S) ssh \ + $(install_prefix)$(bindir)/`echo slogin | sed '$(transform)'`; fi + -for p in $(NORMAL_PROGRAMS); do \ + $(INSTALL_PROGRAM) -m 0755 $$p $(install_prefix)$(bindir)/$$p; \ + if test "`echo $$p | sed '$(transform)'`" '!=' $$p; then \ + rm -f $(install_prefix)$(bindir)/`echo $$p | sed '$(transform)'`; \ + $(LN_S) $$p \ + $(install_prefix)$(bindir)/`echo $$p | sed '$(transform)'`; fi; \ + done +# Remove $(etcdir)/sshd_pid as it is now $(bindir)/sshd.pid + -rm -f $(install_prefix)$(etcdir)/sshd_pid +# Remove $(bindir)/sshd to avoid confusion since it is now in $(sbindir) + -rm -f $(install_prefix)$(bindir)/sshd + -rm -f $(install_prefix)$(bindir)/`echo sshd | sed '$(transform)'` + -for p in $(SBIN_PROGRAMS); do \ + $(INSTALL_PROGRAM) -m 0755 $$p $(install_prefix)$(sbindir)/$$p; \ + if test "`echo $$p | sed '$(transform)'`" '!=' $$p; then \ + rm -f $(install_prefix)$(sbindir)/`echo $$p | sed '$(transform)'`;\ + $(LN_S) $$p \ + $(install_prefix)$(sbindir)/`echo $$p | sed '$(transform)'`; fi;\ + done + -for p in $(MAN1PAGES); do \ + $(INSTALL_DATA) -m 0644 $(srcdir)/$$p $(install_prefix)$(man1dir)/$$p ; \ + if test "`echo $$p | sed '$(transform)'`" '!=' $$p; then \ + rm -f $(install_prefix)$(man1dir)/`echo $$p | sed '$(transform)'`;\ + $(LN_S) $$p \ + $(install_prefix)$(man1dir)/`echo $$p | sed '$(transform)'`; \ + fi; \ + done + rm -f $(install_prefix)$(man1dir)/slogin.1 + $(LN_S) ssh.1 $(install_prefix)$(man1dir)/slogin.1 + if test "`echo slogin.1 | sed '$(transform)'`" '!=' slogin.1; then \ + rm -f $(install_prefix)$(man1dir)/`echo slogin.1 | sed '$(transform)'`;\ + $(LN_S) ssh.1 \ + $(install_prefix)$(man1dir)/`echo slogin.1 | sed '$(transform)'`; \ + fi + -for p in $(MAN1GENERATED); do \ + $(INSTALL_DATA) -m 0644 $$p $(install_prefix)$(man1dir)/$$p ; \ + if test "`echo $$p | sed '$(transform)'`" '!=' $$p; then \ + rm -f $(install_prefix)$(man1dir)/`echo $$p | sed '$(transform)'`;\ + $(LN_S) $$p \ + $(install_prefix)$(man1dir)/`echo $$p | sed '$(transform)'`; \ + fi; \ + done + -for p in $(MAN8GENERATED); do \ + $(INSTALL_DATA) -m 0644 $$p $(install_prefix)$(man8dir)/$$p; \ + if test "`echo $$p | sed '$(transform)'`" '!=' $$p; then \ + rm -f $(install_prefix)$(man8dir)/`echo $$p | sed '$(transform)'`;\ + $(LN_S) $$p \ + $(install_prefix)$(man8dir)/`echo $$p | sed '$(transform)'`; fi;\ + done + -if test '!' -f $(install_prefix)$(HOST_CONFIG_FILE); then \ + $(INSTALL_DATA) -m 0644 $(srcdir)/host_config.sample \ + $(install_prefix)$(HOST_CONFIG_FILE); fi + -if test '!' -f $(install_prefix)$(SERVER_CONFIG_FILE); then \ + cat $(srcdir)/server_config.sample | \ + sed "s#_ETCDIR_#$(etcdir)#g" >/tmp/ssh_inst.$$; \ + $(INSTALL_DATA) -m 0644 /tmp/ssh_inst.$$ \ + $(install_prefix)$(SERVER_CONFIG_FILE); \ + rm -f /tmp/ssh_inst.$$; fi + +uninstall: + for p in ssh $(NORMAL_PROGRAMS); do \ + rm -f $(install_prefix)$(bindir)/$$p; \ + rm -f $(install_prefix)$(bindir)/`echo $$p | sed '$(transform)'`; \ + done + for p in $(SBIN_PROGRAMS); do \ + rm -f $(install_prefix)$(sbindir)/$$p; \ + rm -f $(install_prefix)$(sbindir)/`echo $$p | sed '$(transform)'`; \ + done + rm -f $(install_prefix)$(bindir)/slogin + rm -f $(install_prefix)$(bindir)/`echo slogin | sed '$(transform)'` + for p in $(MAN1PAGES) $(MAN1GENERATED); do \ + rm -f $(install_prefix)$(man1dir)/$$p; \ + rm -f $(install_prefix)$(man1dir)/`echo $$p | sed '$(transform)'`; \ + done + for p in $(MAN8GENERATED); do \ + rm -f $(install_prefix)$(man8dir)/$$p; \ + rm -f $(install_prefix)$(man8dir)/`echo $$p | sed '$(transform)'`; \ + done + +clean: + -rm -f *.o minfd.h gmon.out core $(PROGRAMS) gen_minfd rfc-pg +# cd $(RSAREFSRCDIR); rm -f *.o *.a + +distclean: clean + -rm -f Makefile config.status config.cache config.log config.h + -rm -f ssh.1 sshd.8 + +dist: + -rm -rf $(DISTNAME) + -mkdir $(DISTNAME) + cp $(DISTFILES) $(DISTNAME) + -rm -f $(DISTNAME)/config.h +# tar cf - $(RSAREFDIR) | (cd $(DISTNAME); tar xf -) +# cd $(DISTNAME)/$(RSAREFSRCDIR); rm -f *.o *.a + tar cf $(DISTNAME).tar $(DISTNAME) + -rm -f $(DISTNAME).tar.gz + gzip $(DISTNAME).tar + rm -rf $(DISTNAME) + @echo Distribution left in $(DISTNAME).tar.gz +# @echo Incrementing version number... +# @old_version=`sed 's/.*\.\([0-9][0-9]*\)"$$/\1/' version.h`; \ +# new_version=`expr $$old_version + 1`; \ +# (echo "s/\.$$old_version\"/.$$new_version\"/g"; echo w; echo q) | ed version.h >/dev/null + +depend: + $(MAKEDEP) -I$(srcdir) -I. $(GMPINCS) $(ZINCS) $(DEFS) $(SRCS) Index: usr.bin/ssh/Makefile.inc =================================================================== RCS file: /cvs/src/usr.bin/ssh/Makefile.inc,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- usr.bin/ssh/Makefile.inc 1999/10/07 21:45:02 1.10 +++ usr.bin/ssh/Makefile.inc 1999/10/25 20:27:26 1.11 @@ -1 +1,11 @@ CFLAGS+= -I${.CURDIR}/.. + +.include + +.if exists(${.CURDIR}/../lib/${__objdir}) +LDADD+= -L${.CURDIR}/../lib/${__objdir} -lssh +DPADD+= ${.CURDIR}/../lib/${__objdir}/libssh.a +.else +LDADD+= -L${.CURDIR}/../lib -lssh +DPADD+= ${.CURDIR}/../lib/libssh.a +.endif Index: usr.bin/ssh/OVERVIEW =================================================================== RCS file: /cvs/src/usr.bin/ssh/OVERVIEW,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- usr.bin/ssh/OVERVIEW 1999/09/27 21:15:53 1.2 +++ usr.bin/ssh/OVERVIEW 1999/11/20 10:42:35 1.5 @@ -1,8 +1,9 @@ -This document is inteded for those who wish to read the ssh source +This document is intended for those who wish to read the ssh source code. This tries to give an overview of the structure of the code. Copyright (c) 1995 Tatu Ylonen Updated 17 Nov 1995. +Updated 19 Oct 1999 for OpenSSH-1.2 The software consists of ssh (client), sshd (server), scp, sdist, and the auxiliary programs ssh-keygen, ssh-agent, ssh-add, and @@ -22,14 +23,13 @@ Compression Library - - Ssh uses the GNU GZIP compression library (ZLIB). It resides in - the zlib095 subdirectory. + - Ssh uses the GNU GZIP compression library (ZLIB). Encryption/Decryption - Ssh contains several encryption algorithms. These are all accessed through the cipher.h interface. The interface code is - in cipher.c, and the implementations in des.c, ssh_md5.c, rc4.c. + in cipher.c, and the implementations are in libc. Multiple Precision Integer Library @@ -70,11 +70,11 @@ channels inside the secure channel, and uses this framework to implement X11 forwarding, TCP/IP forwarding, and authentication agent forwarding. + The new, Protocol 1.5, channel close implementation is in nchan.c Authentication agent - - Code to communicate with the authentication agent is in - authfd.c. The files gen-minfd.c, minfd.h, minfd.c + - Code to communicate with the authentication agent is in authfd.c. Authentication methods @@ -83,8 +83,7 @@ code is linked into the server. The routines also manipulate known hosts files using code in hostfile.c. Code in canohost.c is used to retrieve the canonical host name of the remote host. - Code in match.c is used to match host names. Code for osf C2 - extended security is in osfc2.c. + Code in match.c is used to match host names. - In the client end, authentication code is in sshconnect.c. It reads Passwords/passphrases using code in readpass.c. It reads Index: usr.bin/ssh/README =================================================================== RCS file: /cvs/src/usr.bin/ssh/README,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- usr.bin/ssh/README 1999/09/26 20:53:32 1.1 +++ usr.bin/ssh/README 1999/11/20 10:42:35 1.2 @@ -1,7 +1,7 @@ Ssh (Secure Shell) is a program to log into another computer over a network, to execute commands in a remote machine, and to move files from one machine to another. It provides strong authentication and -secure communications over insecure channels. It is inteded as a +secure communications over insecure channels. It is intended as a replacement for rlogin, rsh, rcp, and rdist. See the file INSTALL for installation instructions. See COPYING for Index: usr.bin/ssh/README.AFS-KERBEROS =================================================================== RCS file: README.AFS-KERBEROS diff -N README.AFS-KERBEROS --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsIYFSU31367 Wed Dec 8 12:42:01 1999 @@ -0,0 +1,44 @@ + +ssh-1.2.26-afs-kerberos.patch-1 +AFS, Kerberos v4 support for SSH + +Here are the extra flags to configure, and what they do: + +--with-krb4[=PATH] Compile in Kerberos v4 support: + Kerberos v4 authentication + Kerberos v4 password authentication + Kerberos v4 ~/.klogin authorization + +These are all enabled by the 'KerberosAuthentication' config option. +Kerberos v4 and Kerberos v5 support are mutually exclusive for now. +PATH default is /usr/kerberos. + +--with-hesiod[=PATH] Compile in support for Hesiod: + getpwnam(), getpwuid() replacements + +--with-afs Compile in AFS support (requires KTH krb4): + ticket/token passing + process authentication groups + local Xauthority files (for AFS home dirs) + /ticket TKT_ROOT directory (if it exists) + +Binaries built with AFS support will work just fine on non-AFS machines! +You will need to use the KTH krb4 libs (ftp://ftp.pdc.kth.se/pub/krb/src), +or just their libkafs, also available separately from CMU as libkrbafs +(http://andrew2.andrew.cmu.edu/dist/krbafs.html). + +Additional Kerberos client and server config options (and their defaults): + + KerberosAuthentication yes + KerberosOrLocalPasswd no + KerberosTgtPassing yes + AFSTokenPassing yes + KerberosTicketCleanup yes + +See sshd(8) and ssh(1) for details. + +The latest version of this patch can be found at + + http://www.monkey.org/~dugsong/ssh-afs-kerberos.html + +dugsong@monkey.org Index: usr.bin/ssh/README.DEATTACK =================================================================== RCS file: README.DEATTACK diff -N README.DEATTACK --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsviUUX31367 Wed Dec 8 12:42:01 1999 @@ -0,0 +1,109 @@ +============================================================================ + + CORE SDI S.A. + Buenos Aires, Argentina + + + + SSH insertion attack detection +============================================================================ + + +Crc32 Compensation attack detector +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This document describes the scope and characteristics of SSH crc32 +compensation attack detector engine. It will inspect an encrypted SSH protocol +1.5 stream for suspicious patterns. If either the server or client is under +attack, the detector closes the conection and logs the attack. + + +Attack characteristics +~~~~~~~~~~~~~~~~~~~~~~ +An attacker, with sniffing and spoofing capabilities on the SSH network stream, may perform an active network attack by constructing a packet using a +known cipher/plaintext pair and computing addditional data to fill the packet +in a way that will produce a valid CRC-32 field and pass as a valid packet when +decryped and integrity checked on the server side. + If the attack succeeds, arbitrary commands will get executed on the server. + + This attack doesnt affect the confidential security characteristics of the +products using this protocols. However, integrity and authentication +of packets can no longer be trusted. + +Solution +~~~~~~~~ + This is not an implementation bug, but a protocol design vulnerability. The +protocol must be updated to use cryptographic strong message authentication +codes. SSH Protocol version 2 as published in [1] includes the use of a real +strong MAC. + However, this will require to update all clients and servers simultaneusly +while disabling compatibility with protocol version 1.5. On many installations +this is not practical. + + A mid-term solution exists, that will help protecting the server from the +auth/integrity vulnerabilities. On most scenarios it will be enough to upgrade +only the servers. + + This approach is based on the fact that an attacker will need to exploit some +of the linear characteristics of the integrity function in order to implement +the attack. In that context, the constructed packets will follow certain +patterns that could be detected on the encrypted stream. + + This is not a general solution, but a countermeasure against a model of all +of the possible attacks that exploits this vulnerabilities. + + The provided patch looks for patterns of repeated ciphered blocks in +each SSH packet received, the performance loss in speed is less 2% in an +uncompressed stream compared to an unpatched server. Memory usage increases +in about 8k per conection. + The chances of reporting a false attack in a 32GB file transfer is around +1 in 2**51. + +Contact information +~~~~~~~~~~~~~~~~~~~ + + These vulnerabilities were discovered by Ariel Futoransky + and Emiliano Kargieman. + + Comments and questions regarding this vulnerability and the fix + should be sent to: + + Ariel Futoransky + Emiliano Kargieman + + For more information about CORE SDI S.A. contact + or visit + + For more information about this problem and related ones visit: + + + + You can contact CORE SDI S.A. at using the + the following PGP key: + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia +Comment: Requires PGP version 2.6 or later. + +mQCNAzVgfMgAAAEEAJSfJNdvCwIAc4AK0ckeimubLIwzsRVDRhjPQIOYt/7kxxio +DZybr53fwMEjyT8cHXRL08i0R9rcuFeCNAez6XcalbhqUKXDcLL/cZK80CCDSCs5 +tRCZGGOEBnXQIoyvbvi4gNYhBS5wUvmh3b/mvRFTvhmRrUy9m/nO/LnPTgz1AAUR +tCBDT1JFTEFCUyA8Y29yZWxhYnNAY29yZS1zZGkuY29tPokAlQMFEDVgfMn5zvy5 +z04M9QEBC6ED/0Szt3f54JTvkZG3ezQ8G60HvAw4/A5Ti6i3oze6jsXxzGp6pA1x +i0jaZpKaUSpo0MLc7BcijMKneuUHnN3XtN5YxtFt0aEoot1MIvv4BsdeUb3x257G +3+vr8SxGk44Vm4tfuN8F/2dNo/00yYP9rd3zQ8Tl+gmr5VxnLViZIDuh +=ulRg +-----END PGP PUBLIC KEY BLOCK----- + +Copyright +~~~~~~~~~ + +This file, deattack.c and deattack.h are copyright (c) 1998 +CORE SDI S.A., Buenos Aires, Argentina. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that this copyright notice is retained. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES +ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES RESULTING +FROM THE USE OR MISUSE OF THIS SOFTWARE. + Index: usr.bin/ssh/RFC =================================================================== RCS file: RFC diff -N RFC --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsoUndI31367 Wed Dec 8 12:42:01 1999 @@ -0,0 +1,2187 @@ + + + + + + +Network Working Group T. Ylonen +Internet-Draft Helsinki University of Technology +draft-ylonen-ssh-protocol-00.txt 15 November 1995 +Expires: 15 May 1996 + + + The SSH (Secure Shell) Remote Login Protocol + +Status of This Memo + + This document is an Internet-Draft. Internet-Drafts are working + documents of the Internet Engineering Task Force (IETF), its areas, + and its working groups. Note that other groups may also distribute + working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six + months and may be updated, replaced, or obsoleted by other docu- + ments at any time. It is inappropriate to use Internet-Drafts as + reference material or to cite them other than as ``work in pro- + gress.'' + + To learn the current status of any Internet-Draft, please check the + ``1id-abstracts.txt'' listing contained in the Internet- Drafts + Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe), + munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or + ftp.isi.edu (US West Coast). + + The distribution of this memo is unlimited. + +Introduction + + SSH (Secure Shell) is a program to log into another computer over a + network, to execute commands in a remote machine, and to move files + from one machine to another. It provides strong authentication and + secure communications over insecure networks. Its features include + the following: + + o Closes several security holes (e.g., IP, routing, and DNS spoof- + ing). New authentication methods: .rhosts together with RSA + [RSA] based host authentication, and pure RSA authentication. + + o All communications are automatically and transparently + encrypted. Encryption is also used to protect integrity. + + o X11 connection forwarding provides secure X11 sessions. + + o Arbitrary TCP/IP ports can be redirected over the encrypted + channel in both directions. + + + +Ylonen [Page 1] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + o Client RSA-authenticates the server machine in the beginning of + every connection to prevent trojan horses (by routing or DNS + spoofing) and man-in-the-middle attacks, and the server RSA- + authenticates the client machine before accepting .rhosts or + /etc/hosts.equiv authentication (to prevent DNS, routing, or IP + spoofing). + + o An authentication agent, running in the user's local workstation + or laptop, can be used to hold the user's RSA authentication + keys. + + The goal has been to make the software as easy to use as possible for + ordinary users. The protocol has been designed to be as secure as + possible while making it possible to create implementations that are + easy to use and install. The sample implementation has a number of + convenient features that are not described in this document as they + are not relevant for the protocol. + + +Overview of the Protocol + + The software consists of a server program running on a server + machine, and a client program running on a client machine (plus a few + auxiliary programs). The machines are connected by an insecure IP + [RFC0791] network (that can be monitored, tampered with, and spoofed + by hostile parties). + + A connection is always initiated by the client side. The server + listens on a specific port waiting for connections. Many clients may + connect to the same server machine. + + The client and the server are connected via a TCP/IP [RFC0793] socket + that is used for bidirectional communication. Other types of tran- + sport can be used but are currently not defined. + + When the client connects the server, the server accepts the connec- + tion and responds by sending back its version identification string. + The client parses the server's identification, and sends its own + identification. The purpose of the identification strings is to + validate that the connection was to the correct port, declare the + protocol version number used, and to declare the software version + used on each side (for debugging purposes). The identification + strings are human-readable. If either side fails to understand or + support the other side's version, it closes the connection. + + After the protocol identification phase, both sides switch to a + packet based binary protocol. The server starts by sending its host + key (every host has an RSA key used to authenticate the host), server + + + +Ylonen [Page 2] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + key (an RSA key regenerated every hour), and other information to the + client. The client then generates a 256 bit session key, encrypts it + using both RSA keys (see below for details), and sends the encrypted + session key and selected cipher type to the server. Both sides then + turn on encryption using the selected algorithm and key. The server + sends an encrypted confirmation message to the client. + + The client then authenticates itself using any of a number of authen- + tication methods. The currently supported authentication methods are + .rhosts or /etc/hosts.equiv authentication (disabled by default), the + same with RSA-based host authentication, RSA authentication, and + password authentication. + + After successful authentication, the client makes a number of + requests to prepare for the session. Typical requests include allo- + cating a pseudo tty, starting X11 [X11] or TCP/IP port forwarding, + starting authentication agent forwarding, and executing the shell or + a command. + + When a shell or command is executed, the connection enters interac- + tive session mode. In this mode, data is passed in both directions, + new forwarded connections may be opened, etc. The interactive ses- + sion normally terminates when the server sends the exit status of the + program to the client. + + + The protocol makes several reservations for future extensibility. + First of all, the initial protocol identification messages include + the protocol version number. Second, the first packet by both sides + includes a protocol flags field, which can be used to agree on exten- + sions in a compatible manner. Third, the authentication and session + preparation phases work so that the client sends requests to the + server, and the server responds with success or failure. If the + client sends a request that the server does not support, the server + simply returns failure for it. This permits compatible addition of + new authentication methods and preparation operations. The interac- + tive session phase, on the other hand, works asynchronously and does + not permit the use of any extensions (because there is no easy and + reliable way to signal rejection to the other side and problems would + be hard to debug). Any compatible extensions to this phase must be + agreed upon during any of the earlier phases. + +The Binary Packet Protocol + + After the protocol identification strings, both sides only send spe- + cially formatted packets. The packet layout is as follows: + + o Packet length: 32 bit unsigned integer, coded as four 8-bit + + + +Ylonen [Page 3] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + bytes, msb first. Gives the length of the packet, not including + the length field and padding. The maximum length of a packet + (not including the length field and padding) is 262144 bytes. + + o Padding: 1-8 bytes of random data (or zeroes if not encrypting). + The amount of padding is (8 - (length % 8)) bytes (where % + stands for the modulo operator). The rationale for always hav- + ing some random padding at the beginning of each packet is to + make known plaintext attacks more difficult. + + o Packet type: 8-bit unsigned byte. The value 255 is reserved for + future extension. + + o Data: binary data bytes, depending on the packet type. The + number of data bytes is the "length" field minus 5. + + o Check bytes: 32-bit crc, four 8-bit bytes, msb first. The crc + is the Cyclic Redundancy Check, with the polynomial 0xedb88320, + of the Padding, Packet type, and Data fields. The crc is com- + puted before any encryption. + + The packet, except for the length field, may be encrypted using any + of a number of algorithms. The length of the encrypted part (Padding + + Type + Data + Check) is always a multiple of 8 bytes. Typically + the cipher is used in a chained mode, with all packets chained + together as if it was a single data stream (the length field is never + included in the encryption process). Details of encryption are + described below. + + When the session starts, encryption is turned off. Encryption is + enabled after the client has sent the session key. The encryption + algorithm to use is selected by the client. + + +Packet Compression + + If compression is supported (it is an optional feature, see + SSH_CMSG_REQUEST_COMPRESSION below), the packet type and data fields + of the packet are compressed using the gzip deflate algorithm [GZIP]. + If compression is in effect, the packet length field indicates the + length of the compressed data, plus 4 for the crc. The amount of + padding is computed from the compressed data, so that the amount of + data to be encrypted becomes a multiple of 8 bytes. + + When compressing, the packets (type + data portions) in each direc- + tion are compressed as if they formed a continuous data stream, with + only the current compression block flushed between packets. This + corresponds to the GNU ZLIB library Z_PARTIAL_FLUSH option. The + + + +Ylonen [Page 4] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + compression dictionary is not flushed between packets. The two + directions are compressed independently of each other. + + +Packet Encryption + + The protocol supports several encryption methods. During session + initialization, the server sends a bitmask of all encryption methods + that it supports, and the client selects one of these methods. The + client also generates a 256-bit random session key (32 8-bit bytes) + and sends it to the server. + + The encryption methods supported by the current implementation, and + their codes are: + + SSH_CIPHER_NONE 0 No encryption + SSH_CIPHER_IDEA 1 IDEA in CFB mode + SSH_CIPHER_DES 2 DES in CBC mode + SSH_CIPHER_3DES 3 Triple-DES in CBC mode + SSH_CIPHER_TSS 4 An experimental stream cipher + SSH_CIPHER_RC4 5 RC4 + + + All implementations are required to support SSH_CIPHER_DES and + SSH_CIPHER_3DES. Supporting SSH_CIPHER_IDEA, SSH_CIPHER_RC4, and + SSH_CIPHER_NONE is recommended. Support for SSH_CIPHER_TSS is + optional (and it is not described in this document). Other ciphers + may be added at a later time; support for them is optional. + + For encryption, the encrypted portion of the packet is considered a + linear byte stream. The length of the stream is always a multiple of + 8. The encrypted portions of consecutive packets (in the same direc- + tion) are encrypted as if they were a continuous buffer (that is, any + initialization vectors are passed from the previous packet to the + next packet). Data in each direction is encrypted independently. + + SSH_CIPHER_DES + The key is taken from the first 8 bytes of the session key. The + least significant bit of each byte is ignored. This results in + 56 bits of key data. DES [DES] is used in CBC mode. The iv + (initialization vector) is initialized to all zeroes. + + SSH_CIPHER_3DES + The variant of triple-DES used here works as follows: there are + three independent DES-CBC ciphers, with independent initializa- + tion vectors. The data (the whole encrypted data stream) is + first encrypted with the first cipher, then decrypted with the + second cipher, and finally encrypted with the third cipher. All + + + +Ylonen [Page 5] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + these operations are performed in CBC mode. + + The key for the first cipher is taken from the first 8 bytes of + the session key; the key for the next cipher from the next 8 + bytes, and the key for the third cipher from the following 8 + bytes. All three initialization vectors are initialized to + zero. + + (Note: the variant of 3DES used here differs from some other + descriptions.) + + SSH_CIPHER_IDEA + The key is taken from the first 16 bytes of the session key. + IDEA [IDEA] is used in CFB mode. The initialization vector is + initialized to all zeroes. + + SSH_CIPHER_TSS + All 32 bytes of the session key are used as the key. + + There is no reference available for the TSS algorithm; it is + currently only documented in the sample implementation source + code. The security of this cipher is unknown (but it is quite + fast). The cipher is basically a stream cipher that uses MD5 as + a random number generator and takes feedback from the data. + + SSH_CIPHER_RC4 + The first 16 bytes of the session key are used as the key for + the server to client direction. The remaining 16 bytes are used + as the key for the client to server direction. This gives + independent 128-bit keys for each direction. + + This algorithm is the alleged RC4 cipher posted to the Usenet in + 1995. It is widely believed to be equivalent with the original + RSADSI RC4 cipher. This is a very fast algorithm. + + +Data Type Encodings + + The Data field of each packet contains data encoded as described in + this section. There may be several data items; each item is coded as + described here, and their representations are concatenated together + (without any alignment or padding). + + Each data type is stored as follows: + + 8-bit byte + The byte is stored directly as a single byte. + + + + +Ylonen [Page 6] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + 32-bit unsigned integer + Stored in 4 bytes, msb first. + + Arbitrary length binary string + First 4 bytes are the length of the string, msb first (not + including the length itself). The following "length" bytes are + the string value. There are no terminating null characters. + + Multiple-precision integer + First 2 bytes are the number of bits in the integer, msb first + (for example, the value 0x00012345 would have 17 bits). The + value zero has zero bits. It is permissible that the number of + bits be larger than the real number of bits. + + The number of bits is followed by (bits + 7) / 8 bytes of binary + data, msb first, giving the value of the integer. + + +TCP/IP Port Number and Other Options + + The server listens for connections on TCP/IP port 22. + + The client may connect the server from any port. However, if the + client wishes to use any form of .rhosts or /etc/hosts.equiv authen- + tication, it must connect from a privileged port (less than 1024). + + For the IP Type of Service field [RFC0791], it is recommended that + interactive sessions (those having a user terminal or forwarding X11 + connections) use the IPTOS_LOWDELAY, and non-interactive connections + use IPTOS_THROUGHPUT. + + It is recommended that keepalives are used, because otherwise pro- + grams on the server may never notice if the other end of the connec- + tion is rebooted. + + +Protocol Version Identification + + After the socket is opened, the server sends an identification + string, which is of the form "SSH-.- + \n", where and are integers + and specify the protocol version number (not software distribution + version). is server side software version string (max 40 + characters); it is not interpreted by the remote side but may be use- + ful for debugging. + + The client parses the server's string, and sends a corresponding + string with its own information in response. If the server has lower + + + +Ylonen [Page 7] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + version number, and the client contains special code to emulate it, + the client responds with the lower number; otherwise it responds with + its own number. The server then compares the version number the + client sent with its own, and determines whether they can work + together. The server either disconnects, or sends the first packet + using the binary packet protocol and both sides start working accord- + ing to the lower of the protocol versions. + + By convention, changes which keep the protocol compatible with previ- + ous versions keep the same major protocol version; changes that are + not compatible increment the major version (which will hopefully + never happen). The version described in this document is 1.3. + + The client will + +Key Exchange and Server Host Authentication + + The first message sent by the server using the packet protocol is + SSH_SMSG_PUBLIC_KEY. It declares the server's host key, server pub- + lic key, supported ciphers, supported authentication methods, and + flags for protocol extensions. It also contains a 64-bit random + number (cookie) that must be returned in the client's reply (to make + IP spoofing more difficult). No encryption is used for this message. + + Both sides compute a session id as follows. The modulus of the + server key is interpreted as a byte string (without explicit length + field, with minimum length able to hold the whole value), most signi- + ficant byte first. This string is concatenated with the server host + key interpreted the same way. Additionally, the cookie is con- + catenated with this. Both sides compute MD5 of the resulting string. + The resulting 16 bytes (128 bits) are stored by both parties and are + called the session id. + + The client responds with a SSH_CMSG_SESSION_KEY message, which con- + tains the selected cipher type, a copy of the 64-bit cookie sent by + the server, client's protocol flags, and a session key encrypted with + both the server's host key and server key. No encryption is used for + this message. + + The session key is 32 8-bit bytes (a total of 256 random bits gen- + erated by the client). The client first xors the 16 bytes of the + session id with the first 16 bytes of the session key. The resulting + string is then encrypted using the smaller key (one with smaller + modulus), and the result is then encrypted using the other key. The + number of bits in the public modulus of the two keys must differ by + at least 128 bits. + + At each encryption step, a multiple-precision integer is constructed + + + +Ylonen [Page 8] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + from the data to be encrypted as follows (the integer is here inter- + preted as a sequence of bytes, msb first; the number of bytes is the + number of bytes needed to represent the modulus). + + The most significant byte (which is only partial as the value must be + less than the public modulus, which is never a power of two) is zero. + + The next byte contains the value 2 (which stands for public-key + encrypted data in the PKCS standard [PKCS#1]). Then, there are non- + zero random bytes to fill any unused space, a zero byte, and the data + to be encrypted in the least significant bytes, the last byte of the + data in the least significant byte. + + This algorithm is used twice. First, it is used to encrypt the 32 + random bytes generated by the client to be used as the session key + (xored by the session id). This value is converted to an integer as + described above, and encrypted with RSA using the key with the + smaller modulus. The resulting integer is converted to a byte + stream, msb first. This byte stream is padded and encrypted identi- + cally using the key with the larger modulus. + + After the client has sent the session key, it starts to use the + selected algorithm and key for decrypting any received packets, and + for encrypting any sent packets. Separate ciphers are used for dif- + ferent directions (that is, both directions have separate initializa- + tion vectors or other state for the ciphers). + + When the server has received the session key message, and has turned + on encryption, it sends a SSH_SMSG_SUCCESS message to the client. + + The recommended size of the host key is 1024 bits, and 768 bits for + the server key. The minimum size is 512 bits for the smaller key. + + +Declaring the User Name + + The client then sends a SSH_CMSG_USER message to the server. This + message specifies the user name to log in as. + + The server validates that such a user exists, checks whether authen- + tication is needed, and responds with either SSH_SMSG_SUCCESS or + SSH_SMSG_FAILURE. SSH_SMSG_SUCCESS indicates that no authentication + is needed for this user (no password), and authentication phase has + now been completed. SSH_SMSG_FAILURE indicates that authentication + is needed (or the user does not exist). + + If the user does not exist, it is recommended that this returns + failure, but the server keeps reading messages from the client, and + + + +Ylonen [Page 9] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + responds to any messages (except SSH_MSG_DISCONNECT, SSH_MSG_IGNORE, + and SSH_MSG_DEBUG) with SSH_SMSG_FAILURE. This way the client cannot + be certain whether the user exists. + + +Authentication Phase + + Provided the server didn't immediately accept the login, an authenti- + cation exchange begins. The client sends messages to the server + requesting different types of authentication in arbitrary order as + many times as desired (however, the server may close the connection + after a timeout). The server always responds with SSH_SMSG_SUCCESS + if it has accepted the authentication, and with SSH_SMSG_FAILURE if + it has denied authentication with the requested method or it does not + recognize the message. Some authentication methods cause an exchange + of further messages before the final result is sent. The authentica- + tion phase ends when the server responds with success. + + The recommended value for the authentication timeout (timeout before + disconnecting if no successful authentication has been made) is 5 + minutes. + + The following authentication methods are currently supported: + + SSH_AUTH_RHOSTS 1 .rhosts or /etc/hosts.equiv + SSH_AUTH_RSA 2 pure RSA authentication + SSH_AUTH_PASSWORD 3 password authentication + SSH_AUTH_RHOSTS_RSA 4 .rhosts with RSA host authentication + + + SSH_AUTH_RHOSTS + + This is the authentication method used by rlogin and rsh + [RFC1282]. + + The client sends SSH_CMSG_AUTH_RHOSTS with the client-side user + name as an argument. + + The server checks whether to permit authentication. On UNIX + systems, this is usually done by checking /etc/hosts.equiv, and + .rhosts in the user's home directory. The connection must come + from a privileged port. + + It is recommended that the server checks that there are no IP + options (such as source routing) specified for the socket before + accepting this type of authentication. The client host name + should be reverse-mapped and then forward mapped to ensure that + it has the proper IP-address. + + + +Ylonen [Page 10] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + This authentication method trusts the remote host (root on the + remote host can pretend to be any other user on that host), the + name services, and partially the network: anyone who can see + packets coming out from the server machine can do IP-spoofing + and pretend to be any machine; however, the protocol prevents + blind IP-spoofing (which used to be possible with rlogin). + + Many sites probably want to disable this authentication method + because of the fundamental insecurity of conventional .rhosts or + /etc/hosts.equiv authentication when faced with spoofing. It is + recommended that this method not be supported by the server by + default. + + SSH_AUTH_RHOSTS_RSA + + In addition to conventional .rhosts and hosts.equiv authentica- + tion, this method additionally requires that the client host be + authenticated using RSA. + + The client sends SSH_CMSG_AUTH_RHOSTS_RSA specifying the + client-side user name, and the public host key of the client + host. + + The server first checks if normal .rhosts or /etc/hosts.equiv + authentication would be accepted, and if not, responds with + SSH_SMSG_FAILURE. Otherwise, it checks whether it knows the + host key for the client machine (using the same name for the + host that was used for checking the .rhosts and /etc/hosts.equiv + files). If it does not know the RSA key for the client, access + is denied and SSH_SMSG_FAILURE is sent. + + If the server knows the host key of the client machine, it veri- + fies that the given host key matches that known for the client. + If not, access is denied and SSH_SMSG_FAILURE is sent. + + The server then sends a SSH_SMSG_AUTH_RSA_CHALLENGE message con- + taining an encrypted challenge for the client. The challenge is + 32 8-bit random bytes (256 bits). When encrypted, the highest + (partial) byte is left as zero, the next byte contains the value + 2, the following are non-zero random bytes, followed by a zero + byte, and the challenge put in the remaining bytes. This is + then encrypted using RSA with the client host's public key. + (The padding and encryption algorithm is the same as that used + for the session key.) + + The client decrypts the challenge using its private host key, + concatenates this with the session id, and computes an MD5 + checksum of the resulting 48 bytes. The MD5 output is returned + + + +Ylonen [Page 11] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + as 16 bytes in a SSH_CMSG_AUTH_RSA_RESPONSE message. (MD5 is + used to deter chosen plaintext attacks against RSA; the session + id binds it to a specific session). + + The server verifies that the MD5 of the decrypted challenge + returned by the client matches that of the original value, and + sends SSH_SMSG_SUCCESS if so. Otherwise it sends + SSH_SMSG_FAILURE and refuses the authentication attempt. + + This authentication method trusts the client side machine in + that root on that machine can pretend to be any user on that + machine. Additionally, it trusts the client host key. The name + and/or IP address of the client host is only used to select the + public host key. The same host name is used when scanning + .rhosts or /etc/hosts.equiv and when selecting the host key. It + would in principle be possible to eliminate the host name + entirely and substitute it directly by the host key. IP and/or + DNS [RFC1034] spoofing can only be used to pretend to be a host + for which the attacker has the private host key. + + SSH_AUTH_RSA + + The idea behind RSA authentication is that the server recognizes + the public key offered by the client, generates a random chal- + lenge, and encrypts the challenge with the public key. The + client must then prove that it has the corresponding private key + by decrypting the challenge. + + The client sends SSH_CMSG_AUTH_RSA with public key modulus (n) + as an argument. + + The server may respond immediately with SSH_SMSG_FAILURE if it + does not permit authentication with this key. Otherwise it gen- + erates a challenge, encrypts it using the user's public key + (stored on the server and identified using the modulus), and + sends SSH_SMSG_AUTH_RSA_CHALLENGE with the challenge (mp-int) as + an argument. + + The challenge is 32 8-bit random bytes (256 bits). When + encrypted, the highest (partial) byte is left as zero, the next + byte contains the value 2, the following are non-zero random + bytes, followed by a zero byte, and the challenge put in the + remaining bytes. This is then encrypted with the public key. + (The padding and encryption algorithm is the same as that used + for the session key.) + + The client decrypts the challenge using its private key, con- + catenates it with the session id, and computes an MD5 checksum + + + +Ylonen [Page 12] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + of the resulting 48 bytes. The MD5 output is returned as 16 + bytes in a SSH_CMSG_AUTH_RSA_RESPONSE message. (Note that the + MD5 is necessary to avoid chosen plaintext attacks against RSA; + the session id binds it to a specific session.) + + The server verifies that the MD5 of the decrypted challenge + returned by the client matches that of the original value, and + sends SSH_SMSG_SUCCESS if so. Otherwise it sends + SSH_SMSG_FAILURE and refuses the authentication attempt. + + This authentication method does not trust the remote host, the + network, name services, or anything else. Authentication is + based solely on the possession of the private identification + keys. Anyone in possession of the private keys can log in, but + nobody else. + + The server may have additional requirements for a successful + authentiation. For example, to limit damage due to a comprom- + ised RSA key, a server might restrict access to a limited set of + hosts. + + SSH_AUTH_PASSWORD + + The client sends a SSH_CMSG_AUTH_PASSWORD message with the plain + text password. (Note that even though the password is plain + text inside the message, it is normally encrypted by the packet + mechanism.) + + The server verifies the password, and sends SSH_SMSG_SUCCESS if + authentication was accepted and SSH_SMSG_FAILURE otherwise. + + Note that the password is read from the user by the client; the + user never interacts with a login program. + + This authentication method does not trust the remote host, the + network, name services or anything else. Authentication is + based solely on the possession of the password. Anyone in pos- + session of the password can log in, but nobody else. + +Preparatory Operations + + After successful authentication, the server waits for a request from + the client, processes the request, and responds with SSH_SMSG_SUCCESS + whenever a request has been successfully processed. If it receives a + message that it does not recognize or it fails to honor a request, it + returns SSH_SMSG_FAILURE. It is expected that new message types + might be added to this phase in future. + + + + +Ylonen [Page 13] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + The following messages are currently defined for this phase. + + SSH_CMSG_REQUEST_COMPRESSION + Requests that compression be enabled for this session. A gzip- + compatible compression level (1-9) is passed as an argument. + + SSH_CMSG_REQUEST_PTY + Requests that a pseudo terminal device be allocated for this + session. The user terminal type and terminal modes are supplied + as arguments. + + SSH_CMSG_X11_REQUEST_FORWARDING + Requests forwarding of X11 connections from the remote machine + to the local machine over the secure channel. Causes an + internet-domain socket to be allocated and the DISPLAY variable + to be set on the server. X11 authentication data is automati- + cally passed to the server, and the client may implement spoof- + ing of authentication data for added security. The authentica- + tion data is passed as arguments. + + SSH_CMSG_PORT_FORWARD_REQUEST + Requests forwarding of a TCP/IP port on the server host over the + secure channel. What happens is that whenever a connection is + made to the port on the server, a connection will be made from + the client end to the specified host/port. Any user can forward + unprivileged ports; only the root can forward privileged ports + (as determined by authentication done earlier). + + SSH_CMSG_AGENT_REQUEST_FORWARDING + Requests forwarding of the connection to the authentication + agent. + + SSH_CMSG_EXEC_SHELL + Starts a shell (command interpreter) for the user, and moves + into interactive session mode. + + SSH_CMSG_EXEC_CMD + Executes the given command (actually " -c " or + equivalent) for the user, and moves into interactive session + mode. + + +Interactive Session and Exchange of Data + + During the interactive session, any data written by the shell or com- + mand running on the server machine is forwarded to stdin or stderr on + the client machine, and any input available from stdin on the client + machine is forwarded to the program on the server machine. + + + +Ylonen [Page 14] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + All exchange is asynchronous; either side can send at any time, and + there are no acknowledgements (TCP/IP already provides reliable tran- + sport, and the packet protocol protects against tampering or IP + spoofing). + + When the client receives EOF from its standard input, it will send + SSH_CMSG_EOF; however, this in no way terminates the exchange. The + exchange terminates and interactive mode is left when the server + sends SSH_SMSG_EXITSTATUS to indicate that the client program has + terminated. Alternatively, either side may disconnect at any time by + sending SSH_MSG_DISCONNECT or closing the connection. + + The server may send any of the following messages: + + SSH_SMSG_STDOUT_DATA + Data written to stdout by the program running on the server. + The data is passed as a string argument. The client writes this + data to stdout. + + SSH_SMSG_STDERR_DATA + Data written to stderr by the program running on the server. + The data is passed as a string argument. The client writes this + data to stderr. (Note that if the program is running on a tty, + it is not possible to separate stdout and stderr data, and all + data will be sent as stdout data.) + + SSH_SMSG_EXITSTATUS + Indicates that the shell or command has exited. Exit status is + passed as an integer argument. This message causes termination + of the interactive session. + + SSH_SMSG_AGENT_OPEN + Indicates that someone on the server side is requesting a con- + nection to the authentication agent. The server-side channel + number is passed as an argument. The client must respond with + either SSH_CHANNEL_OPEN_CONFIRMATION or + SSH_CHANNEL_OPEN_FAILURE. + + SSH_SMSG_X11_OPEN + Indicates that a connection has been made to the X11 socket on + the server side and should be forwarded to the real X server. + An integer argument indicates the channel number allocated for + this connection on the server side. The client should send back + either SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE with the same server side channel + number. + + SSH_MSG_PORT_OPEN + + + +Ylonen [Page 15] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + Indicates that a connection has been made to a port on the + server side for which forwarding has been requested. Arguments + are server side channel number, host name to connect to, and + port to connect to. The client should send back either + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE with the same server side channel + number. + + SSH_MSG_CHANNEL_OPEN_CONFIRMATION + This is sent by the server to indicate that it has opened a con- + nection as requested in a previous message. The first argument + indicates the client side channel number, and the second argu- + ment is the channel number that the server has allocated for + this connection. + + SSH_MSG_CHANNEL_OPEN_FAILURE + This is sent by the server to indicate that it failed to open a + connection as requested in a previous message. The client-side + channel number is passed as an argument. The client will close + the descriptor associated with the channel and free the channel. + + SSH_MSG_CHANNEL_DATA + This packet contains data for a channel from the server. The + first argument is the client-side channel number, and the second + argument (a string) is the data. + + SSH_MSG_CHANNEL_CLOSE + This is sent by the server to indicate that whoever was in the + other end of the channel has closed it. The argument is the + client side channel number. The client will let all buffered + data in the channel to drain, and when ready, will close the + socket, free the channel, and send the server a + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION message for the channel. + + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION + This is send by the server to indicate that a channel previously + closed by the client has now been closed on the server side as + well. The argument indicates the client channel number. The + client frees the channel. + + The client may send any of the following messages: + + SSH_CMSG_STDIN_DATA + This is data to be sent as input to the program running on the + server. The data is passed as a string. + + SSH_CMSG_EOF + Indicates that the client has encountered EOF while reading + + + +Ylonen [Page 16] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + standard input. The server will allow any buffered input data + to drain, and will then close the input to the program. + + SSH_CMSG_WINDOW_SIZE + Indicates that window size on the client has been changed. The + server updates the window size of the tty and causes SIGWINCH to + be sent to the program. The new window size is passed as four + integer arguments: row, col, xpixel, ypixel. + + SSH_MSG_PORT_OPEN + Indicates that a connection has been made to a port on the + client side for which forwarding has been requested. Arguments + are client side channel number, host name to connect to, and + port to connect to. The server should send back either + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE with the same client side channel + number. + + SSH_MSG_CHANNEL_OPEN_CONFIRMATION + This is sent by the client to indicate that it has opened a con- + nection as requested in a previous message. The first argument + indicates the server side channel number, and the second argu- + ment is the channel number that the client has allocated for + this connection. + + SSH_MSG_CHANNEL_OPEN_FAILURE + This is sent by the client to indicate that it failed to open a + connection as requested in a previous message. The server side + channel number is passed as an argument. The server will close + the descriptor associated with the channel and free the channel. + + SSH_MSG_CHANNEL_DATA + This packet contains data for a channel from the client. The + first argument is the server side channel number, and the second + argument (a string) is the data. + + SSH_MSG_CHANNEL_CLOSE + This is sent by the client to indicate that whoever was in the + other end of the channel has closed it. The argument is the + server channel number. The server will allow buffered data to + drain, and when ready, will close the socket, free the channel, + and send the client a SSH_MSG_CHANNEL_CLOSE_CONFIRMATION message + for the channel. + + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION + This is send by the client to indicate that a channel previously + closed by the server has now been closed on the client side as + well. The argument indicates the server channel number. The + + + +Ylonen [Page 17] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + server frees the channel. + + Any unsupported messages during interactive mode cause the connection + to be terminated with SSH_MSG_DISCONNECT and an error message. Com- + patible protocol upgrades should agree about any extensions during + the preparation phase or earlier. + + +Termination of the Connection + + Normal termination of the connection is always initiated by the + server by sending SSH_SMSG_EXITSTATUS after the program has exited. + The client responds to this message by sending + SSH_CMSG_EXIT_CONFIRMATION and closes the socket; the server then + closes the socket. There are two purposes for the confirmation: some + systems may lose previously sent data when the socket is closed, and + closing the client side first causes any TCP/IP TIME_WAIT [RFC0793] + waits to occur on the client side, not consuming server resources. + + If the program terminates due to a signal, the server will send + SSH_MSG_DISCONNECT with an appropriate message. If the connection is + closed, all file descriptors to the program will be closed and the + server will exit. If the program runs on a tty, the kernel sends it + the SIGHUP signal when the pty master side is closed. + +Protocol Flags + + Both the server and the client pass 32 bits of protocol flags to the + other side. The flags are intended for compatible protocol exten- + sion; the server first announces which added capabilities it sup- + ports, and the client then sends the capabilities that it supports. + + The following flags are currently defined (the values are bit masks): + + 1 SSH_PROTOFLAG_SCREEN_NUMBER + This flag can only be sent by the client. It indicates that the + X11 forwarding requests it sends will include the screen number. + + 2 SSH_PROTOFLAG_HOST_IN_FWD_OPEN + If both sides specify this flag, SSH_SMSG_X11_OPEN and + SSH_MSG_PORT_OPEN messages will contain an additional field con- + taining a description of the host at the other end of the con- + nection. + +Detailed Description of Packet Types and Formats + + The supported packet types and the corresponding message numbers are + given in the following table. Messages with _MSG_ in their name may + + + +Ylonen [Page 18] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + be sent by either side. Messages with _CMSG_ are only sent by the + client, and messages with _SMSG_ only by the server. + + A packet may contain additional data after the arguments specified + below. Any such data should be ignored by the receiver. However, it + is recommended that no such data be stored without good reason. + (This helps build compatible extensions.) + + 0 SSH_MSG_NONE + This code is reserved. This message type is never sent. + + 1 SSH_MSG_DISCONNECT + + string Cause of disconnection + + This message may be sent by either party at any time. It causes + the immediate disconnection of the connection. The message is + intended to be displayed to a human, and describes the reason + for disconnection. + + 2 SSH_SMSG_PUBLIC_KEY + + 8 bytes anti_spoofing_cookie + 32-bit int server_key_bits + mp-int server_key_public_exponent + mp-int server_key_public_modulus + 32-bit int host_key_bits + mp-int host_key_public_exponent + mp-int host_key_public_modulus + 32-bit int protocol_flags + 32-bit int supported_ciphers_mask + 32-bit int supported_authentications_mask + + Sent as the first message by the server. This message gives the + server's host key, server key, protocol flags (intended for com- + patible protocol extension), supported_ciphers_mask (which is + the bitwise or of (1 << cipher_number), where << is the left + shift operator, for all supported ciphers), and + supported_authentications_mask (which is the bitwise or of (1 << + authentication_type) for all supported authentication types). + The anti_spoofing_cookie is 64 random bytes, and must be sent + back verbatim by the client in its reply. It is used to make + IP-spoofing more difficult (encryption and host keys are the + real defense against spoofing). + + 3 SSH_CMSG_SESSION_KEY + + 1 byte cipher_type (must be one of the supported values) + + + +Ylonen [Page 19] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + 8 bytes anti_spoofing_cookie (must match data sent by the server) + mp-int double-encrypted session key + 32-bit int protocol_flags + + Sent by the client as the first message in the session. Selects + the cipher to use, and sends the encrypted session key to the + server. The anti_spoofing_cookie must be the same bytes that + were sent by the server. Protocol_flags is intended for nego- + tiating compatible protocol extensions. + + 4 SSH_CMSG_USER + + string user login name on server + + Sent by the client to begin authentication. Specifies the user + name on the server to log in as. The server responds with + SSH_SMSG_SUCCESS if no authentication is needed for this user, + or SSH_SMSG_FAILURE if authentication is needed (or the user + does not exist). [Note to the implementator: the user name is + of arbitrary size. The implementation must be careful not to + overflow internal buffers.] + + 5 SSH_CMSG_AUTH_RHOSTS + + string client-side user name + + Requests authentication using /etc/hosts.equiv and .rhosts (or + equivalent mechanisms). This authentication method is normally + disabled in the server because it is not secure (but this is the + method used by rsh and rlogin). The server responds with + SSH_SMSG_SUCCESS if authentication was successful, and + SSH_SMSG_FAILURE if access was not granted. The server should + check that the client side port number is less than 1024 (a + privileged port), and immediately reject authentication if it is + not. Supporting this authentication method is optional. This + method should normally not be enabled in the server because it + is not safe. (However, not enabling this only helps if rlogind + and rshd are disabled.) + + 6 SSH_CMSG_AUTH_RSA + + mp-int identity_public_modulus + + Requests authentication using pure RSA authentication. The + server checks if the given key is permitted to log in, and if + so, responds with SSH_SMSG_AUTH_RSA_CHALLENGE. Otherwise, it + responds with SSH_SMSG_FAILURE. The client often tries several + different keys in sequence until one supported by the server is + + + +Ylonen [Page 20] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + found. Authentication is accepted if the client gives the + correct response to the challenge. The server is free to add + other criteria for authentication, such as a requirement that + the connection must come from a certain host. Such additions + are not visible at the protocol level. Supporting this authen- + tication method is optional but recommended. + + 7 SSH_SMSG_AUTH_RSA_CHALLENGE + + mp-int encrypted challenge + + Presents an RSA authentication challenge to the client. The + challenge is a 256-bit random value encrypted as described else- + where in this document. The client must decrypt the challenge + using the RSA private key, compute MD5 of the challenge plus + session id, and send back the resulting 16 bytes using + SSH_CMSG_AUTH_RSA_RESPONSE. + + 8 SSH_CMSG_AUTH_RSA_RESPONSE + + 16 bytes MD5 of decrypted challenge + + This message is sent by the client in response to an RSA chal- + lenge. The MD5 checksum is returned instead of the decrypted + challenge to deter known-plaintext attacks against the RSA key. + The server responds to this message with either SSH_SMSG_SUCCESS + or SSH_SMSG_FAILURE. + + 9 SSH_CMSG_AUTH_PASSWORD + + string plain text password + + Requests password authentication using the given password. Note + that even though the password is plain text inside the packet, + the whole packet is normally encrypted by the packet layer. It + would not be possible for the client to perform password + encryption/hashing, because it cannot know which kind of + encryption/hashing, if any, the server uses. The server + responds to this message with SSH_SMSG_SUCCESS or + SSH_SMSG_FAILURE. + + 10 SSH_CMSG_REQUEST_PTY + + string TERM environment variable value (e.g. vt100) + 32-bit int terminal height, rows (e.g., 24) + 32-bit int terminal width, columns (e.g., 80) + 32-bit int terminal width, pixels (0 if no graphics) (e.g., 480) + 32-bit int terminal height, pixels (0 if no graphics) (e.g., 640) + + + +Ylonen [Page 21] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + n bytes tty modes encoded in binary + + Requests a pseudo-terminal to be allocated for this command. + This message can be used regardless of whether the session will + later execute the shell or a command. If a pty has been + requested with this message, the shell or command will run on a + pty. Otherwise it will communicate with the server using pipes, + sockets or some other similar mechanism. + + The terminal type gives the type of the user's terminal. In the + UNIX environment it is passed to the shell or command in the + TERM environment variable. + + The width and height values give the initial size of the user's + terminal or window. All values can be zero if not supported by + the operating system. The server will pass these values to the + kernel if supported. + + Terminal modes are encoded into a byte stream in a portable for- + mat. The exact format is described later in this document. + + The server responds to the request with either SSH_SMSG_SUCCESS + or SSH_SMSG_FAILURE. If the server does not have the concept of + pseudo terminals, it should return success if it is possible to + execute a shell or a command so that it looks to the client as + if it was running on a pseudo terminal. + + 11 SSH_CMSG_WINDOW_SIZE + + 32-bit int terminal height, rows + 32-bit int terminal width, columns + 32-bit int terminal width, pixels + 32-bit int terminal height, pixels + + This message can only be sent by the client during the interac- + tive session. This indicates that the size of the user's window + has changed, and provides the new size. The server will update + the kernel's notion of the window size, and a SIGWINCH signal or + equivalent will be sent to the shell or command (if supported by + the operating system). + + 12 SSH_CMSG_EXEC_SHELL + + (no arguments) + + Starts a shell (command interpreter), and enters interactive + session mode. + + + + +Ylonen [Page 22] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + 13 SSH_CMSG_EXEC_CMD + + string command to execute + + Starts executing the given command, and enters interactive ses- + sion mode. On UNIX, the command is run as " -c ", where is the user's login shell. + + 14 SSH_SMSG_SUCCESS + + (no arguments) + + This message is sent by the server in response to the session + key, a successful authentication request, and a successfully + completed preparatory operation. + + 15 SSH_SMSG_FAILURE + + (no arguments) + + This message is sent by the server in response to a failed + authentication operation to indicate that the user has not yet + been successfully authenticated, and in response to a failed + preparatory operation. This is also sent in response to an + authentication or preparatory operation request that is not + recognized or supported. + + 16 SSH_CMSG_STDIN_DATA + + string data + + Delivers data from the client to be supplied as input to the + shell or program running on the server side. This message can + only be used in the interactive session mode. No acknowledge- + ment is sent for this message. + + 17 SSH_SMSG_STDOUT_DATA + + string data + + Delivers data from the server that was read from the standard + output of the shell or program running on the server side. This + message can only be used in the interactive session mode. No + acknowledgement is sent for this message. + + 18 SSH_SMSG_STDERR_DATA + + string data + + + +Ylonen [Page 23] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + Delivers data from the server that was read from the standard + error of the shell or program running on the server side. This + message can only be used in the interactive session mode. No + acknowledgement is sent for this message. + + 19 SSH_CMSG_EOF + + (no arguments) + + This message is sent by the client to indicate that EOF has been + reached on the input. Upon receiving this message, and after + all buffered input data has been sent to the shell or program, + the server will close the input file descriptor to the program. + This message can only be used in the interactive session mode. + No acknowledgement is sent for this message. + + 20 SSH_SMSG_EXITSTATUS + + 32-bit int exit status of the command + + Returns the exit status of the shell or program after it has + exited. The client should respond with + SSH_CMSG_EXIT_CONFIRMATION when it has received this message. + This will be the last message sent by the server. If the pro- + gram being executed dies with a signal instead of exiting nor- + mally, the server should terminate the session with + SSH_MSG_DISCONNECT (which can be used to pass a human-readable + string indicating that the program died due to a signal) instead + of using this message. + + 21 SSH_MSG_CHANNEL_OPEN_CONFIRMATION + + 32-bit int remote_channel + 32-bit int local_channel + + This is sent in response to any channel open request if the + channel has been successfully opened. Remote_channel is the + channel number received in the initial open request; + local_channel is the channel number the side sending this mes- + sage has allocated for the channel. Data can be transmitted on + the channel after this message. + + 22 SSH_MSG_CHANNEL_OPEN_FAILURE + + 32-bit int remote_channel + + This message indicates that an earlier channel open request by + the other side has failed or has been denied. Remote_channel is + + + +Ylonen [Page 24] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + the channel number given in the original request. + + 23 SSH_MSG_CHANNEL_DATA + + 32-bit int remote_channel + string data + + Data is transmitted in a channel in these messages. A channel + is bidirectional, and both sides can send these messages. There + is no acknowledgement for these messages. It is possible that + either side receives these messages after it has sent + SSH_MSG_CHANNEL_CLOSE for the channel. These messages cannot be + received after the party has sent or received + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION. + + 24 SSH_MSG_CHANNEL_CLOSE + + 32-bit int remote_channel + + When a channel is closed at one end of the connection, that side + sends this message. Upon receiving this message, the channel + should be closed. When this message is received, if the channel + is already closed (the receiving side has sent this message for + the same channel earlier), the channel is freed and no further + action is taken; otherwise the channel is freed and + SSH_MSG_CHANNEL_CLOSE_CONFIRMATION is sent in response. (It is + possible that the channel is closed simultaneously at both + ends.) + + 25 SSH_MSG_CHANNEL_CLOSE_CONFIRMATION + + 32-bit int remote_channel + + This message is sent in response to SSH_MSG_CHANNEL_CLOSE unless + the channel was already closed. When this message is sent or + received, the channel is freed. + + 26 (OBSOLETED; was unix-domain X11 forwarding) + + 27 SSH_SMSG_X11_OPEN + + 32-bit int local_channel + string originator_string (see below) + + This message can be sent by the server during the interactive + session mode to indicate that a client has connected the fake X + server. Local_channel is the channel number that the server has + allocated for the connection. The client should try to open a + + + +Ylonen [Page 25] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + connection to the real X server, and respond with + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE. + + The field originator_string is present if both sides specified + SSH_PROTOFLAG_HOST_IN_FWD_OPEN in the protocol flags. It con- + tains a description of the host originating the connection. + + 28 SSH_CMSG_PORT_FORWARD_REQUEST + + 32-bit int server_port + string host_to_connect + 32-bit int port_to_connect + + Sent by the client in the preparatory phase, this message + requests that server_port on the server machine be forwarded + over the secure channel to the client machine, and from there to + the specified host and port. The server should start listening + on the port, and send SSH_MSG_PORT_OPEN whenever a connection is + made to it. Supporting this message is optional, and the server + is free to reject any forward request. For example, it is + highly recommended that unless the user has been authenticated + as root, forwarding any privileged port numbers (below 1024) is + denied. + + 29 SSH_MSG_PORT_OPEN + + 32-bit int local_channel + string host_name + 32-bit int port + string originator_string (see below) + + Sent by either party in interactive session mode, this message + indicates that a connection has been opened to a forwarded + TCP/IP port. Local_channel is the channel number that the send- + ing party has allocated for the connection. Host_name is the + host the connection should be be forwarded to, and the port is + the port on that host to connect. The receiving party should + open the connection, and respond with + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE. It is recommended that the + receiving side check the host_name and port for validity to + avoid compromising local security by compromised remote side + software. Particularly, it is recommended that the client per- + mit connections only to those ports for which it has requested + forwarding with SSH_CMSG_PORT_FORWARD_REQUEST. + + The field originator_string is present if both sides specified + + + +Ylonen [Page 26] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + SSH_PROTOFLAG_HOST_IN_FWD_OPEN in the protocol flags. It con- + tains a description of the host originating the connection. + + 30 SSH_CMSG_AGENT_REQUEST_FORWARDING + + (no arguments) + + Requests that the connection to the authentication agent be for- + warded over the secure channel. The method used by clients to + contact the authentication agent within each machine is imple- + mentation and machine dependent. If the server accepts this + request, it should arrange that any clients run from this ses- + sion will actually contact the server program when they try to + contact the authentication agent. The server should then send a + SSH_SMSG_AGENT_OPEN to open a channel to the agent, and the + client should forward the connection to the real authentication + agent. Supporting this message is optional. + + 31 SSH_SMSG_AGENT_OPEN + + 32-bit int local_channel + + Sent by the server in interactive session mode, this message + requests opening a channel to the authentication agent. The + client should open a channel, and respond with either + SSH_MSG_CHANNEL_OPEN_CONFIRMATION or + SSH_MSG_CHANNEL_OPEN_FAILURE. + + 32 SSH_MSG_IGNORE + + string data + + Either party may send this message at any time. This message, + and the argument string, is silently ignored. This message + might be used in some implementations to make traffic analysis + more difficult. This message is not currently sent by the + implementation, but all implementations are required to recog- + nize and ignore it. + + 33 SSH_CMSG_EXIT_CONFIRMATION + + (no arguments) + + Sent by the client in response to SSH_SMSG_EXITSTATUS. This is + the last message sent by the client. + + 34 SSH_CMSG_X11_REQUEST_FORWARDING + + + + +Ylonen [Page 27] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + string x11_authentication_protocol + string x11_authentication_data + 32-bit int screen number (if SSH_PROTOFLAG_SCREEN_NUMBER) + + Sent by the client during the preparatory phase, this message + requests that the server create a fake X11 display and set the + DISPLAY environment variable accordingly. An internet-domain + display is preferable. The given authentication protocol and + the associated data should be recorded by the server so that it + is used as authentication on connections (e.g., in .Xauthority). + The authentication protocol must be one of the supported X11 + authentication protocols, e.g., "MIT-MAGIC-COOKIE-1". Authenti- + cation data must be a lowercase hex string of even length. Its + interpretation is protocol dependent. The data is in a format + that can be used with e.g. the xauth program. Supporting this + message is optional. + + The client is permitted (and recommended) to generate fake + authentication information and send fake information to the + server. This way, a corrupt server will not have access to the + user's terminal after the connection has terminated. The + correct authorization codes will also not be left hanging around + in files on the server (many users keep the same X session for + months, thus protecting the authorization data becomes impor- + tant). + + X11 authentication spoofing works by initially sending fake + (random) authentication data to the server, and interpreting the + first packet sent by the X11 client after the connection has + been opened. The first packet contains the client's authentica- + tion. If the packet contains the correct fake data, it is + replaced by the client by the correct authentication data, and + then sent to the X server. + + 35 SSH_CMSG_AUTH_RHOSTS_RSA + + string clint-side user name + 32-bit int client_host_key_bits + mp-int client_host_key_public_exponent + mp-int client_host_key_public_modulus + + Requests authentication using /etc/hosts.equiv and .rhosts (or + equivalent) together with RSA host authentication. The server + should check that the client side port number is less than 1024 + (a privileged port), and immediately reject authentication if it + is not. The server responds with SSH_SMSG_FAILURE or + SSH_SMSG_AUTH_RSA_CHALLENGE. The client must respond to the + challenge with the proper SSH_CMSG_AUTH_RSA_RESPONSE. The + + + +Ylonen [Page 28] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + server then responds with success if access was granted, or + failure if the client gave a wrong response. Supporting this + authentication method is optional but recommended in most + environments. + + 36 SSH_MSG_DEBUG + + string debugging message sent to the other side + + This message may be sent by either party at any time. It is + used to send debugging messages that may be informative to the + user in solving various problems. For example, if authentica- + tion fails because of some configuration error (e.g., incorrect + permissions for some file), it can be very helpful for the user + to make the cause of failure available. On the other hand, one + should not make too much information available for security rea- + sons. It is recommended that the client provides an option to + display the debugging information sent by the sender (the user + probably does not want to see it by default). The server can + log debugging data sent by the client (if any). Either party is + free to ignore any received debugging data. Every implementa- + tion must be able to receive this message, but no implementation + is required to send these. + + 37 SSH_CMSG_REQUEST_COMPRESSION + + 32-bit int gzip compression level (1-9) + + This message can be sent by the client in the preparatory opera- + tions phase. The server responds with SSH_SMSG_FAILURE if it + does not support compression or does not want to compress; it + responds with SSH_SMSG_SUCCESS if it accepted the compression + request. In the latter case the response to this packet will + still be uncompressed, but all further packets in either direc- + tion will be compressed by gzip. + + +Encoding of Terminal Modes + + Terminal modes (as passed in SSH_CMSG_REQUEST_PTY) are encoded into a + byte stream. It is intended that the coding be portable across dif- + ferent environments. + + The tty mode description is a stream of bytes. The stream consists + of opcode-argument pairs. It is terminated by opcode TTY_OP_END (0). + Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have 32-bit + integer arguments (stored msb first). Opcodes 160-255 are not yet + defined, and cause parsing to stop (they should only be used after + + + +Ylonen [Page 29] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + any other data). + + The client puts in the stream any modes it knows about, and the + server ignores any modes it does not know about. This allows some + degree of machine-independence, at least between systems that use a + POSIX-like [POSIX] tty interface. The protocol can support other + systems as well, but the client may need to fill reasonable values + for a number of parameters so the server pty gets set to a reasonable + mode (the server leaves all unspecified mode bits in their default + values, and only some combinations make sense). + + The following opcodes have been defined. The naming of opcodes + mostly follows the POSIX terminal mode flags. + + 0 TTY_OP_END + Indicates end of options. + + 1 VINTR + Interrupt character; 255 if none. Similarly for the other char- + acters. Not all of these characters are supported on all sys- + tems. + + 2 VQUIT + The quit character (sends SIGQUIT signal on UNIX systems). + + 3 VERASE + Erase the character to left of the cursor. + + 4 VKILL + Kill the current input line. + + 5 VEOF + End-of-file character (sends EOF from the terminal). + + 6 VEOL + End-of-line character in addition to carriage return and/or + linefeed. + + 7 VEOL2 + Additional end-of-line character. + + 8 VSTART + Continues paused output (normally ^Q). + + 9 VSTOP + Pauses output (^S). + + 10 VSUSP + + + +Ylonen [Page 30] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + Suspends the current program. + + 11 VDSUSP + Another suspend character. + + 12 VREPRINT + Reprints the current input line. + + 13 VWERASE + Erases a word left of cursor. + + 14 VLNEXT + More special input characters; these are probably not supported + on most systems. + + 15 VFLUSH + + 16 VSWTCH + + 17 VSTATUS + + 18 VDISCARD + + + 30 IGNPAR + The ignore parity flag. The next byte should be 0 if this flag + is not set, and 1 if it is set. + + 31 PARMRK + More flags. The exact definitions can be found in the POSIX + standard. + + 32 INPCK + + 33 ISTRIP + + 34 INLCR + + 35 IGNCR + + 36 ICRNL + + 37 IUCLC + + 38 IXON + + 39 IXANY + + + + +Ylonen [Page 31] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + 40 IXOFF + + 41 IMAXBEL + + + 50 ISIG + + 51 ICANON + + 52 XCASE + + 53 ECHO + + 54 ECHOE + + 55 ECHOK + + 56 ECHONL + + 57 NOFLSH + + 58 TOSTOP + + 59 IEXTEN + + 60 ECHOCTL + + 61 ECHOKE + + 62 PENDIN + + + 70 OPOST + + 71 OLCUC + + 72 ONLCR + + 73 OCRNL + + 74 ONOCR + + 75 ONLRET + + + 90 CS7 + + 91 CS8 + + + +Ylonen [Page 32] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + 92 PARENB + + 93 PARODD + + + 192 TTY_OP_ISPEED + Specifies the input baud rate in bits per second. + + 193 TTY_OP_OSPEED + Specifies the output baud rate in bits per second. + + +The Authentication Agent Protocol + + The authentication agent is a program that can be used to hold RSA + authentication keys for the user (in future, it might hold data for + other authentication types as well). An authorized program can send + requests to the agent to generate a proper response to an RSA chal- + lenge. How the connection is made to the agent (or its representa- + tive) inside a host and how access control is done inside a host is + implementation-dependent; however, how it is forwarded and how one + interacts with it is specified in this protocol. The connection to + the agent is normally automatically forwarded over the secure chan- + nel. + + A program that wishes to use the agent first opens a connection to + its local representative (typically, the agent itself or an SSH + server). It then writes a request to the connection, and waits for + response. It is recommended that at least five minutes of timeout + are provided waiting for the agent to respond to an authentication + challenge (this gives sufficient time for the user to cut-and-paste + the challenge to a separate machine, perform the computation there, + and cut-and-paste the result back if so desired). + + Messages sent to and by the agent are in the following format: + + 4 bytes Length, msb first. Does not include length itself. + 1 byte Packet type. The value 255 is reserved for future extensions. + data Any data, depending on packet type. Encoding as in the ssh packet + protocol. + + + The following message types are currently defined: + + 1 SSH_AGENTC_REQUEST_RSA_IDENTITIES + + (no arguments) + + + + +Ylonen [Page 33] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + Requests the agent to send a list of all RSA keys for which it + can answer a challenge. + + 2 SSH_AGENT_RSA_IDENTITIES_ANSWER + + 32-bit int howmany + howmany times: + 32-bit int bits + mp-int public exponent + mp-int public modulus + string comment + + The agent sends this message in response to the to + SSH_AGENTC_REQUEST_RSA_IDENTITIES. The answer lists all RSA + keys for which the agent can answer a challenge. The comment + field is intended to help identify each key; it may be printed + by an application to indicate which key is being used. If the + agent is not holding any keys, howmany will be zero. + + 3 SSH_AGENTC_RSA_CHALLENGE + + 32-bit int bits + mp-int public exponent + mp-int public modulus + mp-int challenge + 16 bytes session_id + 32-bit int response_type + + Requests RSA decryption of random challenge to authenticate the + other side. The challenge will be decrypted with the RSA + private key corresponding to the given public key. + + The decrypted challenge must contain a zero in the highest (par- + tial) byte, 2 in the next byte, followed by non-zero random + bytes, a zero byte, and then the real challenge value in the + lowermost bytes. The real challenge must be 32 8-bit bytes (256 + bits). + + Response_type indicates the format of the response to be + returned. Currently the only supported value is 1, which means + to compute MD5 of the real challenge plus session id, and return + the resulting 16 bytes in a SSH_AGENT_RSA_RESPONSE message. + + 4 SSH_AGENT_RSA_RESPONSE + + 16 bytes MD5 of decrypted challenge + + Answers an RSA authentication challenge. The response is 16 + + + +Ylonen [Page 34] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + bytes: the MD5 checksum of the 32-byte challenge. + + 5 SSH_AGENT_FAILURE + + (no arguments) + + This message is sent whenever the agent fails to answer a + request properly. For example, if the agent cannot answer a + challenge (e.g., no longer has the proper key), it can respond + with this. The agent also responds with this message if it + receives a message it does not recognize. + + 6 SSH_AGENT_SUCCESS + + (no arguments) + + This message is sent by the agent as a response to certain + requests that do not otherwise cause a message be sent. + Currently, this is only sent in response to + SSH_AGENTC_ADD_RSA_IDENTITY and SSH_AGENTC_REMOVE_RSA_IDENTITY. + + 7 SSH_AGENTC_ADD_RSA_IDENTITY + + 32-bit int bits + mp-int public modulus + mp-int public exponent + mp-int private exponent + mp-int multiplicative inverse of p mod q + mp-int p + mp-int q + string comment + + Registers an RSA key with the agent. After this request, the + agent can use this RSA key to answer requests. The agent + responds with SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE. + + 8 SSH_AGENT_REMOVE_RSA_IDENTITY + + 32-bit int bits + mp-int public exponent + mp-int public modulus + + Removes an RSA key from the agent. The agent will no longer + accept challenges for this key and will not list it as a sup- + ported identity. The agent responds with SSH_AGENT_SUCCESS or + SSH_AGENT_FAILURE. + + If the agent receives a message that it does not understand, it + + + +Ylonen [Page 35] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + responds with SSH_AGENT_FAILURE. This permits compatible future + extensions. + + It is possible that several clients have a connection open to the + authentication agent simultaneously. Each client will use a separate + connection (thus, any SSH connection can have multiple agent connec- + tions active simultaneously). + + +References + + + [DES] FIPS PUB 46-1: Data Encryption Standard. National Bureau of + Standards, January 1988. FIPS PUB 81: DES Modes of Operation. + National Bureau of Standards, December 1980. Bruce Schneier: + Applied Cryptography. John Wiley & Sons, 1994. J. Seberry and + J. Pieprzyk: Cryptography: An Introduction to Computer Secu- + rity. Prentice-Hall, 1989. + + [GZIP] + The GNU GZIP program; available for anonymous ftp at + prep.ai.mit.edu. Please let me know if you know a paper + describing the algorithm. + + [IDEA] + Xuejia Lai: On the Design and Security of Block Ciphers, ETH + Series in Information Processing, vol. 1, Hartung-Gorre Verlag, + Konstanz, Switzerland, 1992. Bruce Schneier: Applied Cryptogra- + phy, John Wiley & Sons, 1994. See also the following patents: + PCT/CH91/00117, EP 0 482 154 B1, US Pat. 5,214,703. + + [PKCS#1] + PKCS #1: RSA Encryption Standard. Version 1.5, RSA Labora- + tories, November 1993. Available for anonymous ftp at + ftp.rsa.com. + + [POSIX] + Portable Operating System Interface (POSIX) - Part 1: Applica- + tion Program Interface (API) [C language], ISO/IEC 9945-1, IEEE + Std 1003.1, 1990. + + [RFC0791] + J. Postel: Internet Protocol, RFC 791, USC/ISI, September 1981. + + [RFC0793] + J. Postel: Transmission Control Protocol, RFC 793, USC/ISI, Sep- + tember 1981. + + + + +Ylonen [Page 36] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + [RFC1034] + P. Mockapetris: Domain Names - Concepts and Facilities, RFC + 1034, USC/ISI, November 1987. + + [RFC1282] + B. Kantor: BSD Rlogin, RFC 1258, UCSD, December 1991. + + [RSA] Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994. + See also R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic + Communications System and Method. US Patent 4,405,829, 1983. + + [X11] R. Scheifler: X Window System Protocol, X Consortium Standard, + Version 11, Release 6. Massachusetts Institute of Technology, + Laboratory of Computer Science, 1994. + + +Security Considerations + + This protocol deals with the very issue of user authentication and + security. + + First of all, as an implementation issue, the server program will + have to run as root (or equivalent) on the server machine. This is + because the server program will need be able to change to an arbi- + trary user id. The server must also be able to create a privileged + TCP/IP port. + + The client program will need to run as root if any variant of .rhosts + authentication is to be used. This is because the client program + will need to create a privileged port. The client host key is also + usually stored in a file which is readable by root only. The client + needs the host key in .rhosts authentication only. Root privileges + can be dropped as soon as the privileged port has been created and + the host key has been read. + + The SSH protocol offers major security advantages over existing tel- + net and rlogin protocols. + + o IP spoofing is restricted to closing a connection (by encryp- + tion, host keys, and the special random cookie). If encryption + is not used, IP spoofing is possible for those who can hear + packets going out from the server. + + o DNS spoofing is made ineffective (by host keys). + + o Routing spoofing is made ineffective (by host keys). + + o All data is encrypted with strong algorithms to make + + + +Ylonen [Page 37] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + eavesdropping as difficult as possible. This includes encrypt- + ing any authentication information such as passwords. The + information for decrypting session keys is destroyed every hour. + + o Strong authentication methods: .rhosts combined with RSA host + authentication, and pure RSA authentication. + + o X11 connections and arbitrary TCP/IP ports can be forwarded + securely. + + o Man-in-the-middle attacks are deterred by using the server host + key to encrypt the session key. + + o Trojan horses to catch a password by routing manipulation are + deterred by checking that the host key of the server machine + matches that stored on the client host. + + The security of SSH against man-in-the-middle attacks and the secu- + rity of the new form of .rhosts authentication, as well as server + host validation, depends on the integrity of the host key and the + files containing known host keys. + + The host key is normally stored in a root-readable file. If the host + key is compromised, it permits attackers to use IP, DNS and routing + spoofing as with current rlogin and rsh. It should never be any + worse than the current situation. + + The files containing known host keys are not sensitive. However, if + an attacker gets to modify the known host key files, it has the same + consequences as a compromised host key, because the attacker can then + change the recorded host key. + + The security improvements obtained by this protocol for X11 are of + particular significance. Previously, there has been no way to pro- + tect data communicated between an X server and a client running on a + remote machine. By creating a fake display on the server, and for- + warding all X11 requests over the secure channel, SSH can be used to + run any X11 applications securely without any cooperation with the + vendors of the X server or the application. + + Finally, the security of this program relies on the strength of the + underlying cryptographic algorithms. The RSA algorithm is used for + authentication key exchange. It is widely believed to be secure. Of + the algorithms used to encrypt the session, DES has a rather small + key these days, probably permitting governments and organized crimi- + nals to break it in very short time with specialized hardware. 3DES + is probably safe (but slower). IDEA is widely believed to be secure. + People have varying degrees of confidence in the other algorithms. + + + +Ylonen [Page 38] + +Internet-Draft SSH (Secure Shell) Remote Login Protocol 15 Nov 1995 + + + This program is not secure if used with no encryption at all. + + +Additional Information + + Additional information (especially on the implementation and mailing + lists) is available via WWW at http://www.cs.hut.fi/ssh. + + Comments should be sent to Tatu Ylonen or the SSH + Mailing List . + +Author's Address + + + Tatu Ylonen + Helsinki University of Technology + Otakaari 1 + FIN-02150 Espoo, Finland + + Phone: +358-0-451-3374 + Fax: +358-0-451-3293 + EMail: ylo@cs.hut.fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Ylonen [Page 39] + Index: usr.bin/ssh/acconfig.h =================================================================== RCS file: acconfig.h diff -N acconfig.h --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvszXIqK31367 Wed Dec 8 12:42:01 1999 @@ -0,0 +1,186 @@ +/* + +acconfig.h - template used by autoheader to create config.h.in +config.h.in - used by autoconf to create config.h +config.h - created by autoconf; contains defines generated by autoconf + +Copyright (c) 1995 Tatu Ylonen + +*/ + +#define RCSID(msg) \ +static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } + +@TOP@ + +/* Define if you have SYSV-style /dev/ptmx and /dev/pts/. */ +#undef HAVE_DEV_PTMX + +/* Define if you have /dev/pts and /dev/ptc devices (as in AIX). */ +#undef HAVE_DEV_PTS_AND_PTC + +/* Define if you have shadow passwords in /etc/security/passwd (AIX style). */ +#undef HAVE_ETC_SECURITY_PASSWD + +/* Define if you have shadow passwords in /etc/security/passwd.adjunct + (SunOS style). */ +#undef HAVE_ETC_SECURITY_PASSWD_ADJUNCT + +/* Define if you have OSF1 C2 security installed on the system */ +#undef HAVE_OSF1_C2_SECURITY + +/* Define if you have shadow passwords in /etc/shadow (Solaris style). */ +#undef HAVE_ETC_SHADOW + +/* Define if you have system login defaults in /etc/default/login. */ +#undef HAVE_ETC_DEFAULT_LOGIN + +/* Define if utmp structure has host field. */ +#undef HAVE_HOST_IN_UTMP + +/* Define if utmp structure has addr field. */ +#undef HAVE_ADDR_IN_UTMP + +/* Define if utmp structure has id field. */ +#undef HAVE_ID_IN_UTMP + +/* Define if utmp structure has name field. */ +#undef HAVE_NAME_IN_UTMP + +/* Define if utmp structure has pid field. */ +#undef HAVE_PID_IN_UTMP + +/* Define if utmpx structure has ut_session. */ +#undef HAVE_UT_SESSION + +/* Define if utmpx structure has ut_syslen. */ +#undef HAVE_UT_SYSLEN + +/* Define if /var/adm/lastlog or whatever it is called is a directory + (e.g. SGI IRIX). */ +#undef LASTLOG_IS_DIR + +/* Define to use RSAREF. */ +#undef RSAREF + +/* Define this to be the path of the rsh program to support executing rsh. */ +#undef RSH_PATH + +/* Define this to be the path of the xauth program. */ +#undef XAUTH_PATH + +/* Default path for utmp. Determined by configure. */ +#undef SSH_UTMP + +/* Default path for wtmp. Determined by configure. */ +#undef SSH_WTMP + +/* Default path for lastlog. Determined by configure. */ +#undef SSH_LASTLOG + +/* This is defined if we found a lastlog file. The presence of lastlog.h + alone is not a sufficient indicator (at least newer BSD systems have + lastlog but no lastlog.h. */ +#undef HAVE_LASTLOG + +/* Define this if libutil.a contains BSD 4.4 compatible login(), logout(), + and logwtmp() calls. */ +#undef HAVE_LIBUTIL_LOGIN + +/* Location of system mail spool directory. */ +#undef MAIL_SPOOL_DIRECTORY + +/* Defined if mail goes to $HOME/newmail instead of a global mail spool. */ +#undef HAVE_TILDE_NEWMAIL + +/* Define this to be the default user path if you don't like the default. + See the --with-path= configure option. */ +#undef DEFAULT_PATH + +/* Define this if O_NONBLOCK does not work on your system (e.g., Ultrix). */ +#undef O_NONBLOCK_BROKEN + +/* Define this if sys/syslog.h needs to be included in addition to syslog.h. + This is the case on some Ultrix versions. */ +#undef NEED_SYS_SYSLOG_H + +/* Define this to include IDEA encryption. */ +#undef WITH_IDEA + +/* Define this to include RC4 encryption. */ +#undef WITH_RC4 + +/* Define this to include Blowfish encryption. */ +#undef WITH_BLOWFISH + +/* Define this to include libwrap (tcp_wrappers) support. */ +#undef LIBWRAP + +/* This is defined to pw_encrypt on Linux when using John Faugh's shadow + password implementation. */ +#undef crypt + +/* This is defined on 386BSD to preted we are on FreeBSD. */ +#undef __FreeBSD__ + +/* If defines, this overrides "tty" as the terminal group. */ +#undef TTY_GROUP + +/* Define this if you want to support Security Dynammics SecurID + cards. */ +#undef HAVE_SECURID + +/* Define this if you are using HPSUX. HPUX uses non-standard shared + memory communication for X, which seems to be enabled by the display name + matching that of the local host. This circumvents it by using the IP + address instead of the host name in DISPLAY. */ +#undef HPSUX_NONSTANDARD_X11_KLUDGE + +/* Define this if inet_network should be used instead of inet_addr. This is + the case on DGUX 5.4. */ +#undef BROKEN_INET_ADDR + +/* Define this if your system does not like sizeof(struct sockaddr_un) as the + size argument in bind and connect calls for unix domain sockets. */ +#undef USE_STRLEN_FOR_AF_UNIX + +/* Define this to use pipes instead of socketpairs for communicating with the + client program. Socketpairs do not seem to work on all systems. */ +#undef USE_PIPES + +/* Directory containing ssh_config, ssh_known_hosts, sshd_pid, etc. Normally + /etc. */ +#undef ETCDIR + +/* Define this if speed_t is defined in stdtypes.h or otherwise gets included + into ttymodes.c from system headers. */ +#undef SPEED_T_IN_STDTYPES_H + +/* Define this if compiling with SOCKS (the firewall traversal library). + Also, you must define connect, getsockname, bind, accept, listen, and + select to their R-versions. */ +#undef SOCKS +#undef connect +#undef getsockname +#undef bind +#undef accept +#undef listen +#undef select + +/* Define these if on SCO Unix. */ +#undef HAVE_SCO_ETC_SHADOW +#undef SCO + +/* Define this if you want to compile in Kerberos V4 support. + This can be done at configure time with the --with-krb4 argument. */ +#undef KRB4 + +/* Define this if you want to compile in AFS support. + This can be done at configure time with the --with-afs argument. */ +#undef AFS + +/* Define this if you want to enable nonstandard krb4 TGT forwarding. */ +#undef KERBEROS_TGT_PASSING + +/* Define this if you want to add optional compression support. */ +#undef WITH_ZLIB Index: usr.bin/ssh/atomicio.c =================================================================== RCS file: atomicio.c diff -N atomicio.c --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsVeOkq31367 Wed Dec 8 12:42:02 1999 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1999 Theo de Raadt + * 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("$Id: atomicio.c,v 1.1 1999/12/06 20:15:25 deraadt Exp $"); + +#include "xmalloc.h" +#include "ssh.h" + +/* + * ensure all of data on socket comes through. f==read || f==write + */ +int +atomicio(f, fd, s, n) + int (*f) (); + int fd; + void *s; + size_t n; +{ + int res, pos = 0; + + while (n > pos) { + res = (f) (fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + case 0: + return (res); + default: + pos += res; + } + } + return (pos); +} Index: usr.bin/ssh/auth-krb4.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/auth-krb4.c,v retrieving revision 1.4 retrieving revision 1.11 diff -u -r1.4 -r1.11 --- usr.bin/ssh/auth-krb4.c 1999/10/01 18:18:40 1.4 +++ usr.bin/ssh/auth-krb4.c 1999/12/01 16:54:34 1.11 @@ -1,209 +1,348 @@ /* + * Dug Song + * Kerberos v4 authentication and ticket-passing routines. + */ - auth-kerberos.c - - Dug Song - - Kerberos v4 authentication and ticket-passing routines. - - $Id: auth-krb4.c,v 1.4 1999/10/01 18:18:40 deraadt Exp $ -*/ - #include "includes.h" #include "packet.h" #include "xmalloc.h" #include "ssh.h" +#include "servconf.h" #ifdef KRB4 -int ssh_tf_init(uid_t uid) +char *ticket = NULL; + +extern ServerOptions options; + +/* + * try krb4 authentication, + * return 1 on success, 0 on failure, -1 if krb4 is not available + */ + +int +auth_krb4_password(struct passwd * pw, const char *password) { - extern char *ticket; - char *tkt_root = TKT_ROOT; - struct stat st; - int fd; - - /* Set unique ticket string manually since we're still root. */ - ticket = xmalloc(MAXPATHLEN); + AUTH_DAT adata; + KTEXT_ST tkt; + struct hostent *hp; + unsigned long faddr; + char localhost[MAXHOSTNAMELEN]; + char phost[INST_SZ]; + char realm[REALM_SZ]; + int r; + + /* + * Try Kerberos password authentication only for non-root + * users and only if Kerberos is installed. + */ + if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) { + + /* Set up our ticket file. */ + if (!krb4_init(pw->pw_uid)) { + log("Couldn't initialize Kerberos ticket file for %s!", + pw->pw_name); + goto kerberos_auth_failure; + } + /* Try to get TGT using our password. */ + r = krb_get_pw_in_tkt((char *) pw->pw_name, "", + realm, "krbtgt", realm, + DEFAULT_TKT_LIFE, (char *) password); + if (r != INTK_OK) { + packet_send_debug("Kerberos V4 password " + "authentication for %s failed: %s", + pw->pw_name, krb_err_txt[r]); + goto kerberos_auth_failure; + } + /* Successful authentication. */ + chown(tkt_string(), pw->pw_uid, pw->pw_gid); + + /* + * Now that we have a TGT, try to get a local + * "rcmd" ticket to ensure that we are not talking + * to a bogus Kerberos server. + */ + (void) gethostname(localhost, sizeof(localhost)); + (void) strlcpy(phost, (char *) krb_get_phost(localhost), + INST_SZ); + r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33); + + if (r == KSUCCESS) { + if (!(hp = gethostbyname(localhost))) { + log("Couldn't get local host address!"); + goto kerberos_auth_failure; + } + memmove((void *) &faddr, (void *) hp->h_addr, + sizeof(faddr)); + + /* Verify our "rcmd" ticket. */ + r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost, + faddr, &adata, ""); + if (r == RD_AP_UNDEC) { + /* + * Probably didn't have a srvtab on + * localhost. Allow login. + */ + log("Kerberos V4 TGT for %s unverifiable, " + "no srvtab installed? krb_rd_req: %s", + pw->pw_name, krb_err_txt[r]); + } else if (r != KSUCCESS) { + log("Kerberos V4 %s ticket unverifiable: %s", + KRB4_SERVICE_NAME, krb_err_txt[r]); + goto kerberos_auth_failure; + } + } else if (r == KDC_PR_UNKNOWN) { + /* + * Allow login if no rcmd service exists, but + * log the error. + */ + log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s " + "not registered, or srvtab is wrong?", pw->pw_name, + krb_err_txt[r], KRB4_SERVICE_NAME, phost); + } else { + /* + * TGT is bad, forget it. Possibly spoofed! + */ + packet_send_debug("WARNING: Kerberos V4 TGT " + "possibly spoofed for %s: %s", + pw->pw_name, krb_err_txt[r]); + goto kerberos_auth_failure; + } + + /* Authentication succeeded. */ + return 1; + +kerberos_auth_failure: + krb4_cleanup_proc(NULL); + + if (!options.kerberos_or_local_passwd) + return 0; + } else { + /* Logging in as root or no local Kerberos realm. */ + packet_send_debug("Unable to authenticate to Kerberos."); + } + /* Fall back to ordinary passwd authentication. */ + return -1; +} + +void +krb4_cleanup_proc(void *ignore) +{ + debug("krb4_cleanup_proc called"); + if (ticket) { + (void) dest_tkt(); + xfree(ticket); + ticket = NULL; + } +} + +int +krb4_init(uid_t uid) +{ + static int cleanup_registered = 0; + char *tkt_root = TKT_ROOT; + struct stat st; + int fd; + + if (!ticket) { + /* Set unique ticket string manually since we're still root. */ + ticket = xmalloc(MAXPATHLEN); #ifdef AFS - if (lstat("/ticket", &st) != -1) - tkt_root = "/ticket/"; + if (lstat("/ticket", &st) != -1) + tkt_root = "/ticket/"; #endif /* AFS */ - snprintf(ticket, MAXPATHLEN, "%s%d_%d", tkt_root, uid, getpid()); - (void) krb_set_tkt_string(ticket); + snprintf(ticket, MAXPATHLEN, "%s%d_%d", tkt_root, uid, getpid()); + (void) krb_set_tkt_string(ticket); + } + /* Register ticket cleanup in case of fatal error. */ + if (!cleanup_registered) { + fatal_add_cleanup(krb4_cleanup_proc, NULL); + cleanup_registered = 1; + } + /* Try to create our ticket file. */ + if ((fd = mkstemp(ticket)) != -1) { + close(fd); + return 1; + } + /* Ticket file exists - make sure user owns it (just passed ticket). */ + if (lstat(ticket, &st) != -1) { + if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) && + st.st_uid == uid) + return 1; + } + /* Failure - cancel cleanup function, leaving bad ticket for inspection. */ + log("WARNING: bad ticket file %s", ticket); + fatal_remove_cleanup(krb4_cleanup_proc, NULL); + cleanup_registered = 0; + xfree(ticket); + ticket = NULL; - /* Make sure we own this ticket file, and we created it. */ - if (lstat(ticket, &st) == -1 && errno == ENOENT) { - /* good, no ticket file exists. create it. */ - if ((fd = open(ticket, O_RDWR|O_CREAT|O_EXCL, 0600)) != -1) { - close(fd); - return 1; - } - } - else { - /* file exists. make sure server_user owns it (e.g. just passed ticket), - and that it isn't a symlink, and that it is mode 600. */ - if (st.st_mode == (S_IFREG|S_IRUSR|S_IWUSR) && st.st_uid == uid) - return 1; - } - /* Failure. */ - log("WARNING: bad ticket file %s", ticket); - return 0; + return 0; } -int auth_krb4(const char *server_user, KTEXT auth, char **client) +int +auth_krb4(const char *server_user, KTEXT auth, char **client) { - AUTH_DAT adat = { 0 }; - KTEXT_ST reply; - char instance[INST_SZ]; - int r, s; - u_int cksum; - Key_schedule schedule; - struct sockaddr_in local, foreign; - - s = packet_get_connection_in(); - - r = sizeof(local); - memset(&local, 0, sizeof(local)); - if (getsockname(s, (struct sockaddr *) &local, &r) < 0) - debug("getsockname failed: %.100s", strerror(errno)); - r = sizeof(foreign); - memset(&foreign, 0, sizeof(foreign)); - if (getpeername(s, (struct sockaddr *)&foreign, &r) < 0) - debug("getpeername failed: %.100s", strerror(errno)); - - instance[0] = '*'; instance[1] = 0; - - /* Get the encrypted request, challenge, and session key. */ - if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) { - packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]); - return 0; - } - des_key_sched((des_cblock *)adat.session, schedule); - - *client = xmalloc(MAX_K_NAME_SZ); - (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname, - *adat.pinst ? "." : "", adat.pinst, adat.prealm); - - /* Check ~/.klogin authorization now. */ - if (kuserok(&adat, (char *)server_user) != KSUCCESS) { - packet_send_debug("Kerberos V4 .klogin authorization failed!"); - log("Kerberos V4 .klogin authorization failed for %s to account %s", - *client, server_user); - return 0; - } - /* Increment the checksum, and return it encrypted with the session key. */ - cksum = adat.checksum + 1; - cksum = htonl(cksum); - - /* If we can't successfully encrypt the checksum, we send back an empty - message, admitting our failure. */ - if ((r = krb_mk_priv((u_char *)&cksum, reply.dat, sizeof(cksum)+1, - schedule, &adat.session, &local, &foreign)) < 0) { - packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]); - reply.dat[0] = 0; - reply.length = 0; - } - else - reply.length = r; - - /* Clear session key. */ - memset(&adat.session, 0, sizeof(&adat.session)); - - packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE); - packet_put_string((char *) reply.dat, reply.length); - packet_send(); - packet_write_wait(); - return 1; + AUTH_DAT adat = {0}; + KTEXT_ST reply; + char instance[INST_SZ]; + int r, s; + u_int cksum; + Key_schedule schedule; + struct sockaddr_in local, foreign; + + s = packet_get_connection_in(); + + r = sizeof(local); + memset(&local, 0, sizeof(local)); + if (getsockname(s, (struct sockaddr *) & local, &r) < 0) + debug("getsockname failed: %.100s", strerror(errno)); + r = sizeof(foreign); + memset(&foreign, 0, sizeof(foreign)); + if (getpeername(s, (struct sockaddr *) & foreign, &r) < 0) { + debug("getpeername failed: %.100s", strerror(errno)); + fatal_cleanup(); + } + instance[0] = '*'; + instance[1] = 0; + + /* Get the encrypted request, challenge, and session key. */ + if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) { + packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]); + return 0; + } + des_key_sched((des_cblock *) adat.session, schedule); + + *client = xmalloc(MAX_K_NAME_SZ); + (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname, + *adat.pinst ? "." : "", adat.pinst, adat.prealm); + + /* Check ~/.klogin authorization now. */ + if (kuserok(&adat, (char *) server_user) != KSUCCESS) { + packet_send_debug("Kerberos V4 .klogin authorization failed!"); + log("Kerberos V4 .klogin authorization failed for %s to account %s", + *client, server_user); + xfree(*client); + return 0; + } + /* Increment the checksum, and return it encrypted with the + session key. */ + cksum = adat.checksum + 1; + cksum = htonl(cksum); + + /* If we can't successfully encrypt the checksum, we send back an + empty message, admitting our failure. */ + if ((r = krb_mk_priv((u_char *) & cksum, reply.dat, sizeof(cksum) + 1, + schedule, &adat.session, &local, &foreign)) < 0) { + packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]); + reply.dat[0] = 0; + reply.length = 0; + } else + reply.length = r; + + /* Clear session key. */ + memset(&adat.session, 0, sizeof(&adat.session)); + + packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE); + packet_put_string((char *) reply.dat, reply.length); + packet_send(); + packet_write_wait(); + return 1; } #endif /* KRB4 */ #ifdef AFS -int auth_kerberos_tgt(struct passwd *pw, const char *string) +int +auth_kerberos_tgt(struct passwd *pw, const char *string) { - CREDENTIALS creds; - extern char *ticket; - int r; - - if (!radix_to_creds(string, &creds)) { - log("Protocol error decoding Kerberos V4 tgt"); - packet_send_debug("Protocol error decoding Kerberos V4 tgt"); - goto auth_kerberos_tgt_failure; - } - if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */ - strlcpy(creds.service, "krbtgt", sizeof creds.service); - - if (strcmp(creds.service, "krbtgt")) { - log("Kerberos V4 tgt (%s%s%s@%s) rejected for uid %d", - creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm, - pw->pw_uid); - packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for uid %d", - creds.pname, creds.pinst[0] ? "." : "", creds.pinst, - creds.realm, pw->pw_uid); - goto auth_kerberos_tgt_failure; - } - if (!ssh_tf_init(pw->pw_uid) || - (r = in_tkt(creds.pname, creds.pinst)) || - (r = save_credentials(creds.service, creds.instance, creds.realm, - creds.session, creds.lifetime, creds.kvno, - &creds.ticket_st, creds.issue_date))) { - xfree(ticket); - ticket = NULL; - packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials"); - goto auth_kerberos_tgt_failure; - } - /* Successful authentication, passed all checks. */ - chown(ticket, pw->pw_uid, pw->pw_gid); - packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)", - creds.service, creds.instance, creds.realm, - creds.pname, creds.pinst[0] ? "." : "", - creds.pinst, creds.realm); - - packet_start(SSH_SMSG_SUCCESS); - packet_send(); - packet_write_wait(); - return 1; + CREDENTIALS creds; + + if (!radix_to_creds(string, &creds)) { + log("Protocol error decoding Kerberos V4 tgt"); + packet_send_debug("Protocol error decoding Kerberos V4 tgt"); + goto auth_kerberos_tgt_failure; + } + if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */ + strlcpy(creds.service, "krbtgt", sizeof creds.service); + + if (strcmp(creds.service, "krbtgt")) { + log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname, + creds.pinst[0] ? "." : "", creds.pinst, creds.realm, + pw->pw_name); + packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", + creds.pname, creds.pinst[0] ? "." : "", creds.pinst, + creds.realm, pw->pw_name); + goto auth_kerberos_tgt_failure; + } + if (!krb4_init(pw->pw_uid)) + goto auth_kerberos_tgt_failure; + + if (in_tkt(creds.pname, creds.pinst) != KSUCCESS) + goto auth_kerberos_tgt_failure; + + if (save_credentials(creds.service, creds.instance, creds.realm, + creds.session, creds.lifetime, creds.kvno, + &creds.ticket_st, creds.issue_date) != KSUCCESS) { + packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials"); + goto auth_kerberos_tgt_failure; + } + /* Successful authentication, passed all checks. */ + chown(tkt_string(), pw->pw_uid, pw->pw_gid); + + packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)", + creds.service, creds.instance, creds.realm, creds.pname, + creds.pinst[0] ? "." : "", creds.pinst, creds.realm); + memset(&creds, 0, sizeof(creds)); + packet_start(SSH_SMSG_SUCCESS); + packet_send(); + packet_write_wait(); + return 1; auth_kerberos_tgt_failure: - memset(&creds, 0, sizeof(creds)); - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - return 0; + krb4_cleanup_proc(NULL); + memset(&creds, 0, sizeof(creds)); + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + return 0; } -int auth_afs_token(char *server_user, uid_t uid, const char *string) +int +auth_afs_token(struct passwd *pw, const char *token_string) { - CREDENTIALS creds; + CREDENTIALS creds; + uid_t uid = pw->pw_uid; - if (!radix_to_creds(string, &creds)) { - log("Protocol error decoding AFS token"); - packet_send_debug("Protocol error decoding AFS token"); - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - return 0; - } - if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */ - strlcpy(creds.service, "afs", sizeof creds.service); - - if (strncmp(creds.pname, "AFS ID ", 7) == 0) - uid = atoi(creds.pname + 7); - - if (kafs_settoken(creds.realm, uid, &creds)) { - log("AFS token (%s@%s) rejected for uid %d", creds.pname, - creds.realm, uid); - packet_send_debug("AFS token (%s@%s) rejected for uid %d", creds.pname, - creds.realm, uid); - packet_start(SSH_SMSG_FAILURE); - packet_send(); - packet_write_wait(); - return 0; - } - packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service, - creds.realm, creds.pname, creds.realm); - packet_start(SSH_SMSG_SUCCESS); - packet_send(); - packet_write_wait(); - return 1; + if (!radix_to_creds(token_string, &creds)) { + log("Protocol error decoding AFS token"); + packet_send_debug("Protocol error decoding AFS token"); + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + return 0; + } + if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */ + strlcpy(creds.service, "afs", sizeof creds.service); + + if (strncmp(creds.pname, "AFS ID ", 7) == 0) + uid = atoi(creds.pname + 7); + + if (kafs_settoken(creds.realm, uid, &creds)) { + log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm, + pw->pw_name); + packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname, + creds.realm, pw->pw_name); + memset(&creds, 0, sizeof(creds)); + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + return 0; + } + packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service, + creds.realm, creds.pname, creds.realm); + memset(&creds, 0, sizeof(creds)); + packet_start(SSH_SMSG_SUCCESS); + packet_send(); + packet_write_wait(); + return 1; } #endif /* AFS */ Index: usr.bin/ssh/auth-passwd.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/auth-passwd.c,v retrieving revision 1.8 retrieving revision 1.13 diff -u -r1.8 -r1.13 --- usr.bin/ssh/auth-passwd.c 1999/10/19 15:56:41 1.8 +++ usr.bin/ssh/auth-passwd.c 1999/12/01 16:54:35 1.13 @@ -1,180 +1,62 @@ /* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Created: Sat Mar 18 05:11:38 1995 ylo + * Password authentication. This file contains the functions to check whether + * the password is valid for the user. + */ -auth-passwd.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Sat Mar 18 05:11:38 1995 ylo - -Password authentication. This file contains the functions to check whether -the password is valid for the user. - -*/ - #include "includes.h" -RCSID("$Id: auth-passwd.c,v 1.8 1999/10/19 15:56:41 deraadt Exp $"); +RCSID("$Id: auth-passwd.c,v 1.13 1999/12/01 16:54:35 markus Exp $"); #include "packet.h" #include "ssh.h" #include "servconf.h" #include "xmalloc.h" - -#ifdef KRB4 -extern char *ticket; -#endif /* KRB4 */ - -/* Tries to authenticate the user using password. Returns true if - authentication succeeds. */ -int auth_password(struct passwd *pw, const char *password) +/* + * Tries to authenticate the user using password. Returns true if + * authentication succeeds. + */ +int +auth_password(struct passwd * pw, const char *password) { - extern ServerOptions options; - char *encrypted_password; + extern ServerOptions options; + char *encrypted_password; - if (pw->pw_uid == 0 && options.permit_root_login == 2) - { - /*packet_send_debug("Server does not permit root login with password.");*/ - return 0; - } - - if (*password == '\0' && options.permit_empty_passwd == 0) - { - /*packet_send_debug("Server does not permit empty password login.");*/ - return 0; - } - - /* deny if no user. */ - if (pw == NULL) - return 0; + if (pw->pw_uid == 0 && options.permit_root_login == 2) + return 0; + if (*password == '\0' && options.permit_empty_passwd == 0) + return 0; + /* deny if no user. */ + if (pw == NULL) + return 0; #ifdef SKEY - if (options.skey_authentication == 1) { - if (strncasecmp(password, "s/key", 5) == 0) { - char *skeyinfo = skey_keyinfo(pw->pw_name); - if(skeyinfo == NULL){ - debug("generating fake skeyinfo for %.100s.", pw->pw_name); - skeyinfo = skey_fake_keyinfo(pw->pw_name); - } - if(skeyinfo != NULL) - packet_send_debug(skeyinfo); - /* Try again. */ - return 0; - } - else if (skey_haskey(pw->pw_name) == 0 && - skey_passcheck(pw->pw_name, (char *)password) != -1) { - /* Authentication succeeded. */ - return 1; - } - /* Fall back to ordinary passwd authentication. */ - } -#endif - -#if defined(KRB4) - /* Support for Kerberos v4 authentication - Dug Song */ - if (options.kerberos_authentication) - { - AUTH_DAT adata; - KTEXT_ST tkt; - struct hostent *hp; - unsigned long faddr; - char localhost[MAXHOSTNAMELEN]; /* local host name */ - char phost[INST_SZ]; /* host instance */ - char realm[REALM_SZ]; /* local Kerberos realm */ - int r; - - /* Try Kerberos password authentication only for non-root - users and only if Kerberos is installed. */ - if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) { - - /* Set up our ticket file. */ - if (!ssh_tf_init(pw->pw_uid)) { - log("Couldn't initialize Kerberos ticket file for %s!", - pw->pw_name); - goto kerberos_auth_failure; - } - /* Try to get TGT using our password. */ - r = krb_get_pw_in_tkt((char *)pw->pw_name, "", realm, "krbtgt", realm, - DEFAULT_TKT_LIFE, (char *)password); - if (r != INTK_OK) { - packet_send_debug("Kerberos V4 password authentication for %s " - "failed: %s", pw->pw_name, krb_err_txt[r]); - goto kerberos_auth_failure; - } - /* Successful authentication. */ - chown(ticket, pw->pw_uid, pw->pw_gid); - - (void) gethostname(localhost, sizeof(localhost)); - (void) strlcpy(phost, (char *)krb_get_phost(localhost), INST_SZ); - - /* Now that we have a TGT, try to get a local "rcmd" ticket to - ensure that we are not talking to a bogus Kerberos server. */ - r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33); - - if (r == KSUCCESS) { - if (!(hp = gethostbyname(localhost))) { - log("Couldn't get local host address!"); - goto kerberos_auth_failure; - } - memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr)); - - /* Verify our "rcmd" ticket. */ - r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost, faddr, &adata, ""); - if (r == RD_AP_UNDEC) { - /* Probably didn't have a srvtab on localhost. Allow login. */ - log("Kerberos V4 TGT for %s unverifiable, no srvtab installed? " - "krb_rd_req: %s", pw->pw_name, krb_err_txt[r]); - } - else if (r != KSUCCESS) { - log("Kerberos V4 %s ticket unverifiable: %s", - KRB4_SERVICE_NAME, krb_err_txt[r]); - goto kerberos_auth_failure; - } - } - else if (r == KDC_PR_UNKNOWN) { - /* Allow login if no rcmd service exists, but log the error. */ - log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s " - "not registered, or srvtab is wrong?", pw->pw_name, - krb_err_txt[r], KRB4_SERVICE_NAME, phost); + if (options.skey_authentication == 1) { + int ret = auth_skey_password(pw, password); + if (ret == 1 || ret == 0) + return ret; + /* Fall back to ordinary passwd authentication. */ } - else { - /* TGT is bad, forget it. Possibly spoofed! */ - packet_send_debug("WARNING: Kerberos V4 TGT possibly spoofed for" - "%s: %s", pw->pw_name, krb_err_txt[r]); - goto kerberos_auth_failure; +#endif +#ifdef KRB4 + if (options.kerberos_authentication == 1) { + int ret = auth_krb4_password(pw, password); + if (ret == 1 || ret == 0) + return ret; + /* Fall back to ordinary passwd authentication. */ } - - /* Authentication succeeded. */ - return 1; - - kerberos_auth_failure: - (void) dest_tkt(); - xfree(ticket); - ticket = NULL; - if (!options.kerberos_or_local_passwd ) return 0; - } - else { - /* Logging in as root or no local Kerberos realm. */ - packet_send_debug("Unable to authenticate to Kerberos."); - } - /* Fall back to ordinary passwd authentication. */ - } -#endif /* KRB4 */ - - /* Check for users with no password. */ - if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0) - { - packet_send_debug("Login permitted without a password because the account has no password."); - return 1; /* The user has no password and an empty password was tried. */ - } - - /* Encrypt the candidate password using the proper salt. */ - encrypted_password = crypt(password, - (pw->pw_passwd[0] && pw->pw_passwd[1]) ? - pw->pw_passwd : "xx"); +#endif + + /* Check for users with no password. */ + if (strcmp(password, "") == 0 && strcmp(pw->pw_passwd, "") == 0) + return 1; + /* Encrypt the candidate password using the proper salt. */ + encrypted_password = crypt(password, + (pw->pw_passwd[0] && pw->pw_passwd[1]) ? pw->pw_passwd : "xx"); - /* Authentication is accepted if the encrypted passwords are identical. */ - return (strcmp(encrypted_password, pw->pw_passwd) == 0); + /* Authentication is accepted if the encrypted passwords are identical. */ + return (strcmp(encrypted_password, pw->pw_passwd) == 0); } Index: usr.bin/ssh/auth-rh-rsa.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/auth-rh-rsa.c,v retrieving revision 1.2 retrieving revision 1.10 diff -u -r1.2 -r1.10 --- usr.bin/ssh/auth-rh-rsa.c 1999/10/03 21:50:03 1.2 +++ usr.bin/ssh/auth-rh-rsa.c 1999/11/24 19:53:43 1.10 @@ -1,83 +1,107 @@ /* + * + * auth-rh-rsa.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Sun May 7 03:08:06 1995 ylo + * + * Rhosts or /etc/hosts.equiv authentication combined with RSA host + * authentication. + * + */ -auth-rh-rsa.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Sun May 7 03:08:06 1995 ylo - -Rhosts or /etc/hosts.equiv authentication combined with RSA host -authentication. - -*/ - #include "includes.h" -RCSID("$Id: auth-rh-rsa.c,v 1.2 1999/10/03 21:50:03 provos Exp $"); +RCSID("$Id: auth-rh-rsa.c,v 1.10 1999/11/24 19:53:43 markus Exp $"); #include "packet.h" #include "ssh.h" #include "xmalloc.h" #include "uidswap.h" +#include "servconf.h" -/* Tries to authenticate the user using the .rhosts file and the host using - its host key. Returns true if authentication succeeds. - .rhosts and .shosts will be ignored if ignore_rhosts is non-zero. */ - -int auth_rhosts_rsa(struct passwd *pw, const char *client_user, - unsigned int client_host_key_bits, - BIGNUM *client_host_key_e, BIGNUM *client_host_key_n, - int ignore_rhosts, int strict_modes) +/* + * 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, const char *client_user, + BIGNUM *client_host_key_e, BIGNUM *client_host_key_n) { - const char *canonical_hostname; - HostStatus host_status; - BIGNUM *ke, *kn; - - debug("Trying rhosts with RSA host authentication for %.100s", client_user); - - /* Check if we would accept it using rhosts authentication. */ - if (!auth_rhosts(pw, client_user, ignore_rhosts, strict_modes)) - return 0; - - canonical_hostname = get_canonical_hostname(); - - debug("Rhosts RSA authentication: canonical host %.900s", - canonical_hostname); - - /* Check if we know the host and its host key. */ - /* Check system-wide host file. */ - ke = BN_new(); - kn = BN_new(); - host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, - client_host_key_bits, client_host_key_e, - client_host_key_n, ke, kn); - BN_free(ke); - BN_free(kn); - if (host_status != HOST_OK) { - /* The host key was not found. */ - 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; - } - - /* 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_bits, - client_host_key_e, client_host_key_n)) - { - log("Client on %.800s failed to respond correctly to host authentication.", - canonical_hostname); - return 0; - } - - /* We have authenticated the user using .rhosts or /etc/hosts.equiv, and - the host using RSA. We accept the authentication. */ - - log("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.", - pw->pw_name, client_user, canonical_hostname); - packet_send_debug("Rhosts with RSA host authentication accepted."); - return 1; + extern ServerOptions options; + const char *canonical_hostname; + HostStatus host_status; + BIGNUM *ke, *kn; + + debug("Trying rhosts with RSA host authentication for %.100s", client_user); + + /* Check if we would accept it using rhosts authentication. */ + if (!auth_rhosts(pw, client_user)) + return 0; + + canonical_hostname = get_canonical_hostname(); + + debug("Rhosts RSA authentication: canonical host %.900s", + canonical_hostname); + + /* Check if we know the host and its host key. */ + ke = BN_new(); + kn = BN_new(); + host_status = check_host_in_hostfile(SSH_SYSTEM_HOSTFILE, canonical_hostname, + client_host_key_e, client_host_key_n, + ke, kn); + + /* Check user host file unless ignored. */ + if (host_status != HOST_OK && !options.ignore_user_known_hosts) { + struct stat st; + char *user_hostfile = tilde_expand_filename(SSH_USER_HOSTFILE, pw->pw_uid); + /* + * Check file permissions of SSH_USER_HOSTFILE, auth_rsa() + * did already check pw->pw_dir, but there is a race XXX + */ + if (options.strict_modes && + (stat(user_hostfile, &st) == 0) && + ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || + (st.st_mode & 022) != 0)) { + log("Rhosts RSA authentication refused for %.100s: bad owner or modes for %.200s", + pw->pw_name, user_hostfile); + } else { + /* XXX race between stat and the following open() */ + temporarily_use_uid(pw->pw_uid); + host_status = check_host_in_hostfile(user_hostfile, canonical_hostname, + client_host_key_e, client_host_key_n, + ke, kn); + restore_uid(); + } + xfree(user_hostfile); + } + BN_free(ke); + BN_free(kn); + + if (host_status != HOST_OK) { + 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; + } + /* 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_e, client_host_key_n)) { + log("Client on %.800s failed to respond correctly to host authentication.", + canonical_hostname); + return 0; + } + /* + * We have authenticated the user using .rhosts or /etc/hosts.equiv, + * and the host using RSA. We accept the authentication. + */ + + verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.", + pw->pw_name, client_user, canonical_hostname); + packet_send_debug("Rhosts with RSA host authentication accepted."); + return 1; } Index: usr.bin/ssh/auth-rhosts.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/auth-rhosts.c,v retrieving revision 1.5 retrieving revision 1.11 diff -u -r1.5 -r1.11 --- usr.bin/ssh/auth-rhosts.c 1999/10/03 20:09:18 1.5 +++ usr.bin/ssh/auth-rhosts.c 1999/11/24 19:53:43 1.11 @@ -1,298 +1,266 @@ /* + * + * auth-rhosts.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Fri Mar 17 05:12:18 1995 ylo + * + * Rhosts authentication. This file contains code to check whether to admit + * the login based on rhosts authentication. This file also processes + * /etc/hosts.equiv. + * + */ -auth-rhosts.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Fri Mar 17 05:12:18 1995 ylo - -Rhosts authentication. This file contains code to check whether to admit -the login based on rhosts authentication. This file also processes -/etc/hosts.equiv. - -*/ - #include "includes.h" -RCSID("$Id: auth-rhosts.c,v 1.5 1999/10/03 20:09:18 deraadt Exp $"); +RCSID("$Id: auth-rhosts.c,v 1.11 1999/11/24 19:53:43 markus Exp $"); #include "packet.h" #include "ssh.h" #include "xmalloc.h" #include "uidswap.h" +#include "servconf.h" -/* This function processes an rhosts-style file (.rhosts, .shosts, or - /etc/hosts.equiv). This returns true if authentication can be granted - based on the file, and returns zero otherwise. */ - -int check_rhosts_file(const char *filename, const char *hostname, - const char *ipaddr, const char *client_user, - const char *server_user) +/* + * This function processes an rhosts-style file (.rhosts, .shosts, or + * /etc/hosts.equiv). This returns true if authentication can be granted + * based on the file, and returns zero otherwise. + */ + +int +check_rhosts_file(const char *filename, const char *hostname, + const char *ipaddr, const char *client_user, + const char *server_user) { - FILE *f; - char buf[1024]; /* Must not be larger than host, user, dummy below. */ - - /* Open the .rhosts file. */ - f = fopen(filename, "r"); - if (!f) - return 0; /* Cannot read the .rhosts - deny access. */ - - /* Go through the file, checking every entry. */ - while (fgets(buf, sizeof(buf), f)) - { - /* All three must be at least as big as buf to avoid overflows. */ - char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp; - int negated; - - for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) - ; - if (*cp == '#' || *cp == '\n' || !*cp) - continue; - - /* NO_PLUS is supported at least on OSF/1. We skip it (we don't ever - support the plus syntax). */ - if (strncmp(cp, "NO_PLUS", 7) == 0) - continue; - - /* This should be safe because each buffer is as big as the whole - string, and thus cannot be overwritten. */ - switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) - { - case 0: - packet_send_debug("Found empty line in %.100s.", filename); - continue; /* Empty line? */ - case 1: - /* Host name only. */ - strlcpy(userbuf, server_user, sizeof(userbuf)); - break; - case 2: - /* Got both host and user name. */ - break; - case 3: - packet_send_debug("Found garbage in %.100s.", filename); - continue; /* Extra garbage */ - default: - continue; /* Weird... */ - } + FILE *f; + char buf[1024]; /* Must not be larger than host, user, dummy below. */ - host = hostbuf; - user = userbuf; - negated = 0; - - /* Process negated host names, or positive netgroups. */ - if (host[0] == '-') - { - negated = 1; - host++; - } - else - if (host[0] == '+') - host++; - - if (user[0] == '-') - { - negated = 1; - user++; - } - else - if (user[0] == '+') - user++; - - /* Check for empty host/user names (particularly '+'). */ - if (!host[0] || !user[0]) - { - /* We come here if either was '+' or '-'. */ - packet_send_debug("Ignoring wild host/user names in %.100s.", - filename); - continue; - } - - /* Verify that host name matches. */ - if (host[0] == '@') - { - if (!innetgr(host + 1, hostname, NULL, NULL) && - !innetgr(host + 1, ipaddr, NULL, NULL)) - continue; - } - else - if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0) - continue; /* Different hostname. */ - - /* Verify that user name matches. */ - if (user[0] == '@') - { - if (!innetgr(user + 1, NULL, client_user, NULL)) - continue; - } - else - if (strcmp(user, client_user) != 0) - continue; /* Different username. */ - - /* Found the user and host. */ - fclose(f); - - /* If the entry was negated, deny access. */ - if (negated) - { - packet_send_debug("Matched negative entry in %.100s.", - filename); - return 0; - } - - /* Accept authentication. */ - return 1; - } - - /* Authentication using this file denied. */ - fclose(f); - return 0; + /* Open the .rhosts file, deny if unreadable */ + f = fopen(filename, "r"); + if (!f) + return 0; + + while (fgets(buf, sizeof(buf), f)) { + /* All three must be at least as big as buf to avoid overflows. */ + char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp; + int negated; + + for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) + ; + if (*cp == '#' || *cp == '\n' || !*cp) + continue; + + /* + * NO_PLUS is supported at least on OSF/1. We skip it (we + * don't ever support the plus syntax). + */ + if (strncmp(cp, "NO_PLUS", 7) == 0) + continue; + + /* + * This should be safe because each buffer is as big as the + * whole string, and thus cannot be overwritten. + */ + switch (sscanf(buf, "%s %s %s", hostbuf, userbuf, dummy)) { + case 0: + packet_send_debug("Found empty line in %.100s.", filename); + continue; + case 1: + /* Host name only. */ + strlcpy(userbuf, server_user, sizeof(userbuf)); + break; + case 2: + /* Got both host and user name. */ + break; + case 3: + packet_send_debug("Found garbage in %.100s.", filename); + continue; + default: + /* Weird... */ + continue; + } + + host = hostbuf; + user = userbuf; + negated = 0; + + /* Process negated host names, or positive netgroups. */ + if (host[0] == '-') { + negated = 1; + host++; + } else if (host[0] == '+') + host++; + + if (user[0] == '-') { + negated = 1; + user++; + } else if (user[0] == '+') + user++; + + /* Check for empty host/user names (particularly '+'). */ + if (!host[0] || !user[0]) { + /* We come here if either was '+' or '-'. */ + packet_send_debug("Ignoring wild host/user names in %.100s.", + filename); + continue; + } + /* Verify that host name matches. */ + if (host[0] == '@') { + if (!innetgr(host + 1, hostname, NULL, NULL) && + !innetgr(host + 1, ipaddr, NULL, NULL)) + continue; + } else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0) + continue; /* Different hostname. */ + + /* Verify that user name matches. */ + if (user[0] == '@') { + if (!innetgr(user + 1, NULL, client_user, NULL)) + continue; + } else if (strcmp(user, client_user) != 0) + continue; /* Different username. */ + + /* Found the user and host. */ + fclose(f); + + /* If the entry was negated, deny access. */ + if (negated) { + packet_send_debug("Matched negative entry in %.100s.", + filename); + return 0; + } + /* Accept authentication. */ + return 1; + } + + /* Authentication using this file denied. */ + fclose(f); + return 0; } -/* Tries to authenticate the user using the .shosts or .rhosts file. - Returns true if authentication succeeds. If ignore_rhosts is - true, only /etc/hosts.equiv will be considered (.rhosts and .shosts - are ignored). */ +/* + * Tries to authenticate the user using the .shosts or .rhosts file. Returns + * true if authentication succeeds. If ignore_rhosts is true, only + * /etc/hosts.equiv will be considered (.rhosts and .shosts are ignored). + */ -int auth_rhosts(struct passwd *pw, const char *client_user, - int ignore_rhosts, int strict_modes) +int +auth_rhosts(struct passwd *pw, const char *client_user) { - char buf[1024]; - const char *hostname, *ipaddr; - int port; - struct stat st; - static const char *rhosts_files[] = { ".shosts", ".rhosts", NULL }; - unsigned int rhosts_file_index; - - /* Quick check: if the user has no .shosts or .rhosts files, return failure - immediately without doing costly lookups from name servers. */ - /* Switch to the user's uid. */ - temporarily_use_uid(pw->pw_uid); - for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; - rhosts_file_index++) - { - /* Check users .rhosts or .shosts. */ - snprintf(buf, sizeof buf, "%.500s/%.100s", - pw->pw_dir, rhosts_files[rhosts_file_index]); - if (stat(buf, &st) >= 0) - break; - } - /* Switch back to privileged uid. */ - restore_uid(); - - if (!rhosts_files[rhosts_file_index] && stat("/etc/hosts.equiv", &st) < 0 && - stat(SSH_HOSTS_EQUIV, &st) < 0) - return 0; /* The user has no .shosts or .rhosts file and there are no - system-wide files. */ - - /* Get the name, address, and port of the remote host. */ - hostname = get_canonical_hostname(); - ipaddr = get_remote_ipaddr(); - port = get_remote_port(); - - /* Check that the connection comes from a privileged port. - Rhosts authentication only makes sense for priviledged programs. - Of course, if the intruder has root access on his local machine, - he can connect from any port. So do not use .rhosts - authentication from machines that you do not trust. */ - if (port >= IPPORT_RESERVED || - port < IPPORT_RESERVED / 2) - { - log("Connection from %.100s from nonpriviledged port %d", - hostname, port); - packet_send_debug("Your ssh client is not running as root."); - return 0; - } - - /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */ - if (pw->pw_uid != 0) - { - if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user, - pw->pw_name)) - { - packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.", - hostname, ipaddr); - return 1; - } - if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user, - pw->pw_name)) - { - packet_send_debug("Accepted for %.100s [%.100s] by %.100s.", - hostname, ipaddr, SSH_HOSTS_EQUIV); - return 1; - } - } - - /* Check that the home directory is owned by root or the user, and is not - group or world writable. */ - if (stat(pw->pw_dir, &st) < 0) - { - log("Rhosts authentication refused for %.100: no home directory %.200s", - pw->pw_name, pw->pw_dir); - packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s", - pw->pw_name, pw->pw_dir); - return 0; - } - if (strict_modes && - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || - (st.st_mode & 022) != 0)) - { - log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.", - pw->pw_name); - packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.", - pw->pw_name); - return 0; - } - - /* Check all .rhosts files (currently .shosts and .rhosts). */ - /* Temporarily use the user's uid. */ - temporarily_use_uid(pw->pw_uid); - for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; - rhosts_file_index++) - { - /* Check users .rhosts or .shosts. */ - snprintf(buf, sizeof buf, "%.500s/%.100s", - pw->pw_dir, rhosts_files[rhosts_file_index]); - if (stat(buf, &st) < 0) - continue; /* No such file. */ - - /* Make sure that the file is either owned by the user or by root, - and make sure it is not writable by anyone but the owner. This is - to help avoid novices accidentally allowing access to their account - by anyone. */ - if (strict_modes && - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || - (st.st_mode & 022) != 0)) - { - log("Rhosts authentication refused for %.100s: bad modes for %.200s", - pw->pw_name, buf); - packet_send_debug("Bad file modes for %.200s", buf); - continue; - } - - /* Check if we have been configured to ignore .rhosts and .shosts - files. */ - if (ignore_rhosts) - { - packet_send_debug("Server has been configured to ignore %.100s.", - rhosts_files[rhosts_file_index]); - continue; - } - - /* Check if authentication is permitted by the file. */ - if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) - { - packet_send_debug("Accepted by %.100s.", - rhosts_files[rhosts_file_index]); - /* Restore the privileged uid. */ - restore_uid(); - return 1; - } - } - - /* Rhosts authentication denied. */ - /* Restore the privileged uid. */ - restore_uid(); - return 0; + extern ServerOptions options; + char buf[1024]; + const char *hostname, *ipaddr; + struct stat st; + static const char *rhosts_files[] = {".shosts", ".rhosts", NULL}; + unsigned int rhosts_file_index; + + /* Switch to the user's uid. */ + temporarily_use_uid(pw->pw_uid); + /* + * Quick check: if the user has no .shosts or .rhosts files, return + * failure immediately without doing costly lookups from name + * servers. + */ + for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; + rhosts_file_index++) { + /* Check users .rhosts or .shosts. */ + snprintf(buf, sizeof buf, "%.500s/%.100s", + pw->pw_dir, rhosts_files[rhosts_file_index]); + if (stat(buf, &st) >= 0) + break; + } + /* Switch back to privileged uid. */ + restore_uid(); + + /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */ + if (!rhosts_files[rhosts_file_index] && + stat("/etc/hosts.equiv", &st) < 0 && + stat(SSH_HOSTS_EQUIV, &st) < 0) + return 0; + + hostname = get_canonical_hostname(); + ipaddr = get_remote_ipaddr(); + + /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */ + if (pw->pw_uid != 0) { + if (check_rhosts_file("/etc/hosts.equiv", hostname, ipaddr, client_user, + pw->pw_name)) { + packet_send_debug("Accepted for %.100s [%.100s] by /etc/hosts.equiv.", + hostname, ipaddr); + return 1; + } + if (check_rhosts_file(SSH_HOSTS_EQUIV, hostname, ipaddr, client_user, + pw->pw_name)) { + packet_send_debug("Accepted for %.100s [%.100s] by %.100s.", + hostname, ipaddr, SSH_HOSTS_EQUIV); + return 1; + } + } + /* + * Check that the home directory is owned by root or the user, and is + * not group or world writable. + */ + if (stat(pw->pw_dir, &st) < 0) { + log("Rhosts authentication refused for %.100s: no home directory %.200s", + pw->pw_name, pw->pw_dir); + packet_send_debug("Rhosts authentication refused for %.100: no home directory %.200s", + pw->pw_name, pw->pw_dir); + return 0; + } + if (options.strict_modes && + ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || + (st.st_mode & 022) != 0)) { + log("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.", + pw->pw_name); + packet_send_debug("Rhosts authentication refused for %.100s: bad ownership or modes for home directory.", + pw->pw_name); + return 0; + } + /* Temporarily use the user's uid. */ + temporarily_use_uid(pw->pw_uid); + + /* Check all .rhosts files (currently .shosts and .rhosts). */ + for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; + rhosts_file_index++) { + /* Check users .rhosts or .shosts. */ + snprintf(buf, sizeof buf, "%.500s/%.100s", + pw->pw_dir, rhosts_files[rhosts_file_index]); + if (stat(buf, &st) < 0) + continue; + + /* + * Make sure that the file is either owned by the user or by + * root, and make sure it is not writable by anyone but the + * owner. This is to help avoid novices accidentally + * allowing access to their account by anyone. + */ + if (options.strict_modes && + ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || + (st.st_mode & 022) != 0)) { + log("Rhosts authentication refused for %.100s: bad modes for %.200s", + pw->pw_name, buf); + packet_send_debug("Bad file modes for %.200s", buf); + continue; + } + /* Check if we have been configured to ignore .rhosts and .shosts files. */ + if (options.ignore_rhosts) { + packet_send_debug("Server has been configured to ignore %.100s.", + rhosts_files[rhosts_file_index]); + continue; + } + /* Check if authentication is permitted by the file. */ + if (check_rhosts_file(buf, hostname, ipaddr, client_user, pw->pw_name)) { + packet_send_debug("Accepted by %.100s.", + rhosts_files[rhosts_file_index]); + /* Restore the privileged uid. */ + restore_uid(); + return 1; + } + } + + /* Restore the privileged uid. */ + restore_uid(); + return 0; } Index: usr.bin/ssh/auth-rsa.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/auth-rsa.c,v retrieving revision 1.5 retrieving revision 1.16 diff -u -r1.5 -r1.16 --- usr.bin/ssh/auth-rsa.c 1999/10/18 01:54:18 1.5 +++ usr.bin/ssh/auth-rsa.c 1999/12/02 23:05:08 1.16 @@ -1,22 +1,22 @@ /* + * + * auth-rsa.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Mon Mar 27 01:46:52 1995 ylo + * + * RSA-based authentication. This code determines whether to admit a login + * based on RSA authentication. This file also contains functions to check + * validity of the host key. + * + */ -auth-rsa.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Mon Mar 27 01:46:52 1995 ylo - -RSA-based authentication. This code determines whether to admit a login -based on RSA authentication. This file also contains functions to check -validity of the host key. - -*/ - #include "includes.h" -RCSID("$Id: auth-rsa.c,v 1.5 1999/10/18 01:54:18 provos Exp $"); +RCSID("$Id: auth-rsa.c,v 1.16 1999/12/02 23:05:08 markus Exp $"); #include "rsa.h" #include "packet.h" @@ -24,9 +24,10 @@ #include "ssh.h" #include "mpaux.h" #include "uidswap.h" +#include "servconf.h" #include -#include +#include /* Flags that may be set in authorized_keys options. */ extern int no_port_forwarding_flag; @@ -36,443 +37,429 @@ extern char *forced_command; extern struct envstring *custom_environment; -/* Session identifier that is used to bind key exchange and authentication - responses to a particular session. */ +/* + * Session identifier that is used to bind key exchange and authentication + * responses to a particular session. + */ extern unsigned char session_id[16]; -/* The .ssh/authorized_keys file contains public keys, one per line, in the - following format: - options bits e n comment - where bits, e and n are decimal numbers, - and comment is any string of characters up to newline. The maximum - length of a line is 8000 characters. See the documentation for a - description of the options. -*/ - -/* Performs the RSA authentication challenge-response dialog with the client, - and returns true (non-zero) if the client gave the correct answer to - our challenge; returns zero if the client gives a wrong answer. */ +/* + * The .ssh/authorized_keys file contains public keys, one per line, in the + * following format: + * options bits e n comment + * where bits, e and n are decimal numbers, + * and comment is any string of characters up to newline. The maximum + * length of a line is 8000 characters. See the documentation for a + * description of the options. + */ + +/* + * Performs the RSA authentication challenge-response dialog with the client, + * and returns true (non-zero) if the client gave the correct answer to + * our challenge; returns zero if the client gives a wrong answer. + */ int -auth_rsa_challenge_dialog(unsigned int bits, BIGNUM *e, BIGNUM *n) +auth_rsa_challenge_dialog(BIGNUM *e, BIGNUM *n) { - BIGNUM *challenge, *encrypted_challenge, *aux; - RSA *pk; - BN_CTX *ctx = BN_CTX_new(); - unsigned char buf[32], mdbuf[16], response[16]; - MD5_CTX md; - unsigned int i; - int plen, len; - - encrypted_challenge = BN_new(); - challenge = BN_new(); - aux = BN_new(); - - /* Generate a random challenge. */ - BN_rand(challenge, 256, 0, 0); - BN_mod(challenge, challenge, n, ctx); - - /* Create the public key data structure. */ - pk = RSA_new(); - pk->e = BN_new(); - BN_copy(pk->e, e); - pk->n = BN_new(); - BN_copy(pk->n, n); - - /* Encrypt the challenge with the public key. */ - rsa_public_encrypt(encrypted_challenge, challenge, pk); - RSA_free(pk); - - /* Send the encrypted challenge to the client. */ - packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); - packet_put_bignum(encrypted_challenge); - packet_send(); - packet_write_wait(); - - /* The response is MD5 of decrypted challenge plus session id. */ - len = BN_num_bytes(challenge); - assert(len <= 32 && len); - memset(buf, 0, 32); - BN_bn2bin(challenge, buf + 32 - len); - MD5Init(&md); - MD5Update(&md, buf, 32); - MD5Update(&md, session_id, 16); - MD5Final(mdbuf, &md); - - /* We will no longer need these. */ - BN_clear_free(encrypted_challenge); - BN_clear_free(challenge); - BN_clear_free(aux); - BN_CTX_free(ctx); - - /* Wait for a response. */ - packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE); - packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE); - for (i = 0; i < 16; i++) - response[i] = packet_get_char(); - - /* Verify that the response is the original challenge. */ - if (memcmp(response, mdbuf, 16) != 0) - { - /* Wrong answer. */ - return 0; - } - - /* Correct answer. */ - return 1; + BIGNUM *challenge, *encrypted_challenge, *aux; + RSA *pk; + BN_CTX *ctx = BN_CTX_new(); + unsigned char buf[32], mdbuf[16], response[16]; + MD5_CTX md; + unsigned int i; + int plen, len; + + encrypted_challenge = BN_new(); + challenge = BN_new(); + aux = BN_new(); + + /* Generate a random challenge. */ + BN_rand(challenge, 256, 0, 0); + BN_mod(challenge, challenge, n, ctx); + + /* Create the public key data structure. */ + pk = RSA_new(); + pk->e = BN_new(); + BN_copy(pk->e, e); + pk->n = BN_new(); + BN_copy(pk->n, n); + + /* Encrypt the challenge with the public key. */ + rsa_public_encrypt(encrypted_challenge, challenge, pk); + RSA_free(pk); + + /* Send the encrypted challenge to the client. */ + packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); + packet_put_bignum(encrypted_challenge); + packet_send(); + packet_write_wait(); + + /* 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); + + /* We will no longer need these. */ + BN_clear_free(encrypted_challenge); + BN_clear_free(challenge); + BN_clear_free(aux); + BN_CTX_free(ctx); + + /* Wait for a response. */ + packet_read_expect(&plen, SSH_CMSG_AUTH_RSA_RESPONSE); + packet_integrity_check(plen, 16, SSH_CMSG_AUTH_RSA_RESPONSE); + for (i = 0; i < 16; i++) + response[i] = packet_get_char(); + + /* 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 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. */ +/* + * 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, int strict_modes) +auth_rsa(struct passwd *pw, BIGNUM *client_n) { - char line[8192]; - int authenticated; - unsigned int bits; - FILE *f; - unsigned long linenum = 0; - struct stat st; - BIGNUM *e, *n; - - /* Temporarily use the user's uid. */ - temporarily_use_uid(pw->pw_uid); - - /* The authorized keys. */ - snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, - SSH_USER_PERMITTED_KEYS); - - /* Fail quietly if file does not exist */ - if (stat(line, &st) < 0) - { - /* Restore the privileged uid. */ - restore_uid(); - return 0; - } - - /* Open the file containing the authorized keys. */ - f = fopen(line, "r"); - if (!f) - { - /* Restore the privileged uid. */ - restore_uid(); - packet_send_debug("Could not open %.900s for reading.", line); - packet_send_debug("If your home is on an NFS volume, it may need to be world-readable."); - return 0; - } - - if (strict_modes) { - int fail=0; - char buf[1024]; - /* Check open file in order to avoid open/stat races */ - if (fstat(fileno(f), &st) < 0 || - (st.st_uid != 0 && st.st_uid != pw->pw_uid) || - (st.st_mode & 022) != 0) { - snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: " - "bad ownership or modes for '%s'.", pw->pw_name, line); - fail=1; - }else{ - /* Check path to SSH_USER_PERMITTED_KEYS */ - int i; - static const char *check[] = { - "", SSH_USER_DIR, NULL - }; - for (i=0; check[i]; i++) { - snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]); - if (stat(line, &st) < 0 || - (st.st_uid != 0 && st.st_uid != pw->pw_uid) || - (st.st_mode & 022) != 0) { - snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: " - "bad ownership or modes for '%s'.", pw->pw_name, line); - fail=1; - break; - } - } - } - if (fail) { - log(buf); - packet_send_debug(buf); - restore_uid(); - return 0; - } - } - - /* Flag indicating whether authentication has succeeded. */ - authenticated = 0; - - /* Initialize mp-int variables. */ - e = BN_new(); - n = BN_new(); - - /* Go though the accepted keys, looking for the current key. If found, - perform a challenge-response dialog to verify that the user really has - the corresponding private key. */ - while (fgets(line, sizeof(line), f)) - { - char *cp; - char *options; - - linenum++; - - /* Skip leading whitespace. */ - for (cp = line; *cp == ' ' || *cp == '\t'; cp++) - ; - - /* Skip empty and comment lines. */ - if (!*cp || *cp == '\n' || *cp == '#') - continue; - - /* Check if there are options for this key, and if so, save their - starting address and skip the option part for now. If there are no - options, set the starting address to NULL. */ - if (*cp < '0' || *cp > '9') - { - int quoted = 0; - options = cp; - for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) - { - if (*cp == '\\' && cp[1] == '"') - cp++; /* Skip both */ - else - if (*cp == '"') - quoted = !quoted; - } - } - else - options = NULL; - - /* Parse the key from the line. */ - if (!auth_rsa_read_key(&cp, &bits, e, n)) - { - debug("%.100s, line %lu: bad key syntax", - SSH_USER_PERMITTED_KEYS, linenum); - packet_send_debug("%.100s, line %lu: bad key syntax", - SSH_USER_PERMITTED_KEYS, linenum); - continue; + extern ServerOptions options; + char line[8192], file[1024]; + int authenticated; + unsigned int bits; + FILE *f; + unsigned long linenum = 0; + struct stat st; + BIGNUM *e, *n; + + /* Temporarily use the user's uid. */ + temporarily_use_uid(pw->pw_uid); + + /* The authorized keys. */ + snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir, + SSH_USER_PERMITTED_KEYS); + + /* Fail quietly if file does not exist */ + if (stat(file, &st) < 0) { + /* Restore the privileged uid. */ + restore_uid(); + return 0; } - /* cp now points to the comment part. */ - - /* Check if the we have found the desired key (identified by its - modulus). */ - if (BN_cmp(n, client_n) != 0) - continue; /* Wrong key. */ - - /* We have found the desired key. */ - - /* Perform the challenge-response dialog for this key. */ - if (!auth_rsa_challenge_dialog(bits, e, n)) - { - /* Wrong response. */ - log("Wrong response to RSA authentication challenge."); - packet_send_debug("Wrong response to RSA authentication challenge."); - continue; + /* 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."); + 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. */ - authenticated = 1; - - /* RSA part of authentication was accepted. Now process the options. */ - if (options) - { - while (*options && *options != ' ' && *options != '\t') - { - cp = "no-port-forwarding"; - if (strncmp(options, cp, strlen(cp)) == 0) - { - packet_send_debug("Port forwarding disabled."); - no_port_forwarding_flag = 1; - options += strlen(cp); - goto next_option; - } - cp = "no-agent-forwarding"; - if (strncmp(options, cp, strlen(cp)) == 0) - { - packet_send_debug("Agent forwarding disabled."); - no_agent_forwarding_flag = 1; - options += strlen(cp); - goto next_option; - } - cp = "no-X11-forwarding"; - if (strncmp(options, cp, strlen(cp)) == 0) - { - packet_send_debug("X11 forwarding disabled."); - no_x11_forwarding_flag = 1; - options += strlen(cp); - goto next_option; + if (options.strict_modes) { + int fail = 0; + char buf[1024]; + /* Check open file in order to avoid open/stat races */ + if (fstat(fileno(f), &st) < 0 || + (st.st_uid != 0 && st.st_uid != pw->pw_uid) || + (st.st_mode & 022) != 0) { + snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: " + "bad ownership or modes for '%s'.", pw->pw_name, file); + fail = 1; + } else { + /* Check path to SSH_USER_PERMITTED_KEYS */ + int i; + static const char *check[] = { + "", SSH_USER_DIR, NULL + }; + for (i = 0; check[i]; i++) { + snprintf(line, sizeof line, "%.500s/%.100s", pw->pw_dir, check[i]); + if (stat(line, &st) < 0 || + (st.st_uid != 0 && st.st_uid != pw->pw_uid) || + (st.st_mode & 022) != 0) { + snprintf(buf, sizeof buf, "RSA authentication refused for %.100s: " + "bad ownership or modes for '%s'.", pw->pw_name, line); + fail = 1; + break; + } + } } - cp = "no-pty"; - if (strncmp(options, cp, strlen(cp)) == 0) - { - packet_send_debug("Pty allocation disabled."); - no_pty_flag = 1; - options += strlen(cp); - goto next_option; + if (fail) { + log(buf); + packet_send_debug(buf); + restore_uid(); + return 0; } - cp = "command=\""; - if (strncmp(options, cp, strlen(cp)) == 0) - { - int i; - options += strlen(cp); - forced_command = xmalloc(strlen(options) + 1); - i = 0; - while (*options) - { - if (*options == '"') - break; - if (*options == '\\' && options[1] == '"') - { - options += 2; - forced_command[i++] = '"'; - continue; + } + /* Flag indicating whether authentication has succeeded. */ + authenticated = 0; + + e = BN_new(); + n = BN_new(); + + /* + * Go though the accepted keys, looking for the current key. If + * found, perform a challenge-response dialog to verify that the + * user really has the corresponding private key. + */ + while (fgets(line, sizeof(line), f)) { + char *cp; + char *options; + + linenum++; + + /* Skip leading whitespace, empty and comment lines. */ + for (cp = line; *cp == ' ' || *cp == '\t'; cp++) + ; + if (!*cp || *cp == '\n' || *cp == '#') + continue; + + /* + * Check if there are options for this key, and if so, + * save their starting address and skip the option part + * for now. If there are no options, set the starting + * address to NULL. + */ + if (*cp < '0' || *cp > '9') { + int quoted = 0; + options = cp; + for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { + if (*cp == '\\' && cp[1] == '"') + cp++; /* Skip both */ + else if (*cp == '"') + quoted = !quoted; } - forced_command[i++] = *options++; - } - if (!*options) - { - debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - continue; - } - forced_command[i] = 0; - packet_send_debug("Forced command: %.900s", forced_command); - options++; - goto next_option; + } else + options = NULL; + + /* Parse the key from the line. */ + if (!auth_rsa_read_key(&cp, &bits, e, n)) { + debug("%.100s, line %lu: bad key syntax", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: bad key syntax", + SSH_USER_PERMITTED_KEYS, linenum); + continue; } - cp = "environment=\""; - if (strncmp(options, cp, strlen(cp)) == 0) - { - int i; - char *s; - struct envstring *new_envstring; - options += strlen(cp); - s = xmalloc(strlen(options) + 1); - i = 0; - while (*options) - { - if (*options == '"') - break; - if (*options == '\\' && options[1] == '"') - { - options += 2; - s[i++] = '"'; - continue; - } - s[i++] = *options++; - } - if (!*options) - { - debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - continue; - } - s[i] = 0; - packet_send_debug("Adding to environment: %.900s", s); - debug("Adding to environment: %.900s", s); - options++; - new_envstring = xmalloc(sizeof(struct envstring)); - new_envstring->s = s; - new_envstring->next = custom_environment; - custom_environment = new_envstring; - goto next_option; + /* cp now points to the comment part. */ + + /* Check if the we have found the desired key (identified by its modulus). */ + if (BN_cmp(n, client_n) != 0) + continue; + + /* check the real bits */ + if (bits != BN_num_bits(n)) + log("Warning: %s, line %ld: keysize mismatch: " + "actual %d vs. announced %d.", + file, linenum, BN_num_bits(n), bits); + + /* We have found the desired key. */ + + /* Perform the challenge-response dialog for this key. */ + if (!auth_rsa_challenge_dialog(e, n)) { + /* Wrong response. */ + verbose("Wrong response to RSA authentication challenge."); + packet_send_debug("Wrong response to RSA authentication challenge."); + continue; } - cp = "from=\""; - if (strncmp(options, cp, strlen(cp)) == 0) - { - char *patterns = xmalloc(strlen(options) + 1); - int i; - options += strlen(cp); - i = 0; - while (*options) - { - if (*options == '"') - break; - if (*options == '\\' && options[1] == '"') - { - options += 2; - patterns[i++] = '"'; - continue; + /* + * 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. + */ + authenticated = 1; + + /* RSA part of authentication was accepted. Now process the options. */ + if (options) { + while (*options && *options != ' ' && *options != '\t') { + cp = "no-port-forwarding"; + if (strncmp(options, cp, strlen(cp)) == 0) { + packet_send_debug("Port forwarding disabled."); + no_port_forwarding_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "no-agent-forwarding"; + if (strncmp(options, cp, strlen(cp)) == 0) { + packet_send_debug("Agent forwarding disabled."); + no_agent_forwarding_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "no-X11-forwarding"; + if (strncmp(options, cp, strlen(cp)) == 0) { + packet_send_debug("X11 forwarding disabled."); + no_x11_forwarding_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "no-pty"; + if (strncmp(options, cp, strlen(cp)) == 0) { + packet_send_debug("Pty allocation disabled."); + no_pty_flag = 1; + options += strlen(cp); + goto next_option; + } + cp = "command=\""; + if (strncmp(options, cp, strlen(cp)) == 0) { + int i; + options += strlen(cp); + forced_command = xmalloc(strlen(options) + 1); + i = 0; + while (*options) { + if (*options == '"') + break; + if (*options == '\\' && options[1] == '"') { + options += 2; + forced_command[i++] = '"'; + continue; + } + forced_command[i++] = *options++; + } + if (!*options) { + debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + forced_command[i] = 0; + packet_send_debug("Forced command: %.900s", forced_command); + options++; + goto next_option; + } + cp = "environment=\""; + if (strncmp(options, cp, strlen(cp)) == 0) { + int i; + char *s; + struct envstring *new_envstring; + options += strlen(cp); + s = xmalloc(strlen(options) + 1); + i = 0; + while (*options) { + if (*options == '"') + break; + if (*options == '\\' && options[1] == '"') { + options += 2; + s[i++] = '"'; + continue; + } + s[i++] = *options++; + } + if (!*options) { + debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + s[i] = 0; + packet_send_debug("Adding to environment: %.900s", s); + debug("Adding to environment: %.900s", s); + options++; + new_envstring = xmalloc(sizeof(struct envstring)); + new_envstring->s = s; + new_envstring->next = custom_environment; + custom_environment = new_envstring; + goto next_option; + } + cp = "from=\""; + if (strncmp(options, cp, strlen(cp)) == 0) { + char *patterns = xmalloc(strlen(options) + 1); + int i; + options += strlen(cp); + i = 0; + while (*options) { + if (*options == '"') + break; + if (*options == '\\' && options[1] == '"') { + options += 2; + patterns[i++] = '"'; + continue; + } + patterns[i++] = *options++; + } + if (!*options) { + debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + packet_send_debug("%.100s, line %lu: missing end quote", + SSH_USER_PERMITTED_KEYS, linenum); + continue; + } + patterns[i] = 0; + options++; + if (!match_hostname(get_canonical_hostname(), patterns, + strlen(patterns)) && + !match_hostname(get_remote_ipaddr(), patterns, + strlen(patterns))) { + log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).", + pw->pw_name, get_canonical_hostname(), + get_remote_ipaddr()); + packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", + get_canonical_hostname()); + xfree(patterns); + authenticated = 0; + break; + } + xfree(patterns); + /* Host name matches. */ + goto next_option; + } + bad_option: + log("Bad options in %.100s file, line %lu: %.50s", + SSH_USER_PERMITTED_KEYS, linenum, options); + packet_send_debug("Bad options in %.100s file, line %lu: %.50s", + SSH_USER_PERMITTED_KEYS, linenum, options); + authenticated = 0; + break; + + next_option: + /* + * Skip the comma, and move to the next option + * (or break out if there are no more). + */ + if (!*options) + fatal("Bugs in auth-rsa.c option processing."); + if (*options == ' ' || *options == '\t') + break; /* End of options. */ + if (*options != ',') + goto bad_option; + options++; + /* Process the next option. */ + continue; } - patterns[i++] = *options++; - } - if (!*options) - { - debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - packet_send_debug("%.100s, line %lu: missing end quote", - SSH_USER_PERMITTED_KEYS, linenum); - continue; - } - patterns[i] = 0; - options++; - if (!match_hostname(get_canonical_hostname(), patterns, - strlen(patterns)) && - !match_hostname(get_remote_ipaddr(), patterns, - strlen(patterns))) - { - log("RSA authentication tried for %.100s with correct key but not from a permitted host (host=%.200s, ip=%.200s).", - pw->pw_name, get_canonical_hostname(), - get_remote_ipaddr()); - packet_send_debug("Your host '%.200s' is not permitted to use this key for login.", - get_canonical_hostname()); - xfree(patterns); - authenticated = 0; - break; - } - xfree(patterns); - /* Host name matches. */ - goto next_option; } - bad_option: - /* Unknown option. */ - log("Bad options in %.100s file, line %lu: %.50s", - SSH_USER_PERMITTED_KEYS, linenum, options); - packet_send_debug("Bad options in %.100s file, line %lu: %.50s", - SSH_USER_PERMITTED_KEYS, linenum, options); - authenticated = 0; - break; - - next_option: - /* Skip the comma, and move to the next option (or break out - if there are no more). */ - if (!*options) - fatal("Bugs in auth-rsa.c option processing."); - if (*options == ' ' || *options == '\t') - break; /* End of options. */ - if (*options != ',') - goto bad_option; - options++; - /* Process the next option. */ - continue; - } + /* + * Break out of the loop if authentication was successful; + * otherwise continue searching. + */ + if (authenticated) + break; } + + /* Restore the privileged uid. */ + restore_uid(); + + /* Close the file. */ + fclose(f); - /* Break out of the loop if authentication was successful; otherwise - continue searching. */ - if (authenticated) - break; - } - - /* Restore the privileged uid. */ - restore_uid(); - - /* Close the file. */ - fclose(f); - - /* Clear any mp-int variables. */ - BN_clear_free(n); - BN_clear_free(e); + BN_clear_free(n); + BN_clear_free(e); - if (authenticated) - packet_send_debug("RSA authentication accepted."); + if (authenticated) + packet_send_debug("RSA authentication accepted."); - /* Return authentication result. */ - return authenticated; + /* Return authentication result. */ + return authenticated; } Index: usr.bin/ssh/auth-skey.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/auth-skey.c,v retrieving revision 1.2 retrieving revision 1.5 diff -u -r1.2 -r1.5 --- usr.bin/ssh/auth-skey.c 1999/10/16 20:57:52 1.2 +++ usr.bin/ssh/auth-skey.c 1999/12/06 19:04:57 1.5 @@ -1,12 +1,40 @@ #include "includes.h" -RCSID("$Id: auth-skey.c,v 1.2 1999/10/16 20:57:52 deraadt Exp $"); +RCSID("$Id: auth-skey.c,v 1.5 1999/12/06 19:04:57 deraadt Exp $"); #include "ssh.h" +#include "packet.h" #include -/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */ +/* + * try skey authentication, + * return 1 on success, 0 on failure, -1 if skey is not available + */ +int +auth_skey_password(struct passwd * pw, const char *password) +{ + if (strncasecmp(password, "s/key", 5) == 0) { + char *skeyinfo = skey_keyinfo(pw->pw_name); + if (skeyinfo == NULL) { + debug("generating fake skeyinfo for %.100s.", + pw->pw_name); + skeyinfo = skey_fake_keyinfo(pw->pw_name); + } + if (skeyinfo != NULL) + packet_send_debug(skeyinfo); + /* Try again. */ + return 0; + } else if (skey_haskey(pw->pw_name) == 0 && + skey_passcheck(pw->pw_name, (char *) password) != -1) { + /* Authentication succeeded. */ + return 1; + } + /* Fall back to ordinary passwd authentication. */ + return -1; +} +/* from %OpenBSD: skeylogin.c,v 1.32 1999/08/16 14:46:56 millert Exp % */ + #define ROUND(x) (((x)[0] << 24) + (((x)[1]) << 16) + (((x)[2]) << 8) + \ ((x)[3])) @@ -30,6 +58,7 @@ return i; } + char * skey_fake_keyinfo(char *username) { @@ -75,6 +104,7 @@ SEEK_SET) != -1 && read(fd, hseed, SKEY_MAX_SEED_LEN) == SKEY_MAX_SEED_LEN) { close(fd); + fd = -1; secret = hseed; secretlen = SKEY_MAX_SEED_LEN; flg = 0; @@ -84,6 +114,8 @@ secretlen = strlen(secret); flg = 0; } + if (fd != -1) + close(fd); } /* Put that in your pipe and smoke it */ Index: usr.bin/ssh/authfd.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/authfd.c,v retrieving revision 1.8 retrieving revision 1.15 diff -u -r1.8 -r1.15 --- usr.bin/ssh/authfd.c 1999/10/14 18:17:41 1.8 +++ usr.bin/ssh/authfd.c 1999/12/06 20:15:26 1.15 @@ -1,20 +1,20 @@ /* + * + * authfd.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Wed Mar 29 01:30:28 1995 ylo + * + * Functions for connecting the local authentication agent. + * + */ -authfd.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Wed Mar 29 01:30:28 1995 ylo - -Functions for connecting the local authentication agent. - -*/ - #include "includes.h" -RCSID("$Id: authfd.c,v 1.8 1999/10/14 18:17:41 markus Exp $"); +RCSID("$Id: authfd.c,v 1.15 1999/12/06 20:15:26 deraadt Exp $"); #include "ssh.h" #include "rsa.h" @@ -31,535 +31,548 @@ int ssh_get_authentication_socket() { - const char *authsocket; - int sock; - struct sockaddr_un sunaddr; - - authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); - if (!authsocket) - return -1; - - sunaddr.sun_family = AF_UNIX; - strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); - - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - return -1; - - if (connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) - { - close(sock); - return -1; - } - - return sock; + const char *authsocket; + int sock; + struct sockaddr_un sunaddr; + + authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); + if (!authsocket) + return -1; + + sunaddr.sun_family = AF_UNIX; + strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + /* close on exec */ + if (fcntl(sock, F_SETFD, 1) == -1) { + close(sock); + return -1; + } + if (connect(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) { + close(sock); + return -1; + } + return sock; } -/* Closes the agent socket if it should be closed (depends on how it was - obtained). The argument must have been returned by - ssh_get_authentication_socket(). */ +/* + * Closes the agent socket if it should be closed (depends on how it was + * obtained). The argument must have been returned by + * ssh_get_authentication_socket(). + */ -void ssh_close_authentication_socket(int sock) +void +ssh_close_authentication_socket(int sock) { - if (getenv(SSH_AUTHSOCKET_ENV_NAME)) - close(sock); + if (getenv(SSH_AUTHSOCKET_ENV_NAME)) + close(sock); } -/* Opens and connects a private socket for communication with the - authentication agent. Returns the file descriptor (which must be - shut down and closed by the caller when no longer needed). - Returns NULL if an error occurred and the connection could not be - opened. */ +/* + * Opens and connects a private socket for communication with the + * authentication agent. Returns the file descriptor (which must be + * shut down and closed by the caller when no longer needed). + * Returns NULL if an error occurred and the connection could not be + * opened. + */ -AuthenticationConnection *ssh_get_authentication_connection() +AuthenticationConnection * +ssh_get_authentication_connection() { - AuthenticationConnection *auth; - int sock; - - sock = ssh_get_authentication_socket(); - - /* Fail if we couldn't obtain a connection. This happens if we exited - due to a timeout. */ - if (sock < 0) - return NULL; - - /* Applocate the connection structure and initialize it. */ - auth = xmalloc(sizeof(*auth)); - auth->fd = sock; - buffer_init(&auth->packet); - buffer_init(&auth->identities); - auth->howmany = 0; + AuthenticationConnection *auth; + int sock; - return auth; + sock = ssh_get_authentication_socket(); + + /* + * Fail if we couldn't obtain a connection. This happens if we + * exited due to a timeout. + */ + if (sock < 0) + return NULL; + + auth = xmalloc(sizeof(*auth)); + auth->fd = sock; + buffer_init(&auth->packet); + buffer_init(&auth->identities); + auth->howmany = 0; + + return auth; } -/* Closes the connection to the authentication agent and frees any associated - memory. */ +/* + * Closes the connection to the authentication agent and frees any associated + * memory. + */ -void ssh_close_authentication_connection(AuthenticationConnection *ac) +void +ssh_close_authentication_connection(AuthenticationConnection *ac) { - buffer_free(&ac->packet); - buffer_free(&ac->identities); - close(ac->fd); - /* Free the connection data structure. */ - xfree(ac); + buffer_free(&ac->packet); + buffer_free(&ac->identities); + close(ac->fd); + xfree(ac); } -/* Returns the first authentication identity held by the agent. - Returns true if an identity is available, 0 otherwise. - The caller must initialize the integers before the call, and free the - comment after a successful call (before calling ssh_get_next_identity). */ +/* + * Returns the first authentication identity held by the agent. + * Returns true if an identity is available, 0 otherwise. + * The caller must initialize the integers before the call, and free the + * comment after a successful call (before calling ssh_get_next_identity). + */ int ssh_get_first_identity(AuthenticationConnection *auth, - int *bitsp, BIGNUM *e, BIGNUM *n, char **comment) + BIGNUM *e, BIGNUM *n, char **comment) { - unsigned char msg[8192]; - int len, l; + unsigned char msg[8192]; + int len, l; + + /* + * Send a message to the agent requesting for a list of the + * identities it can represent. + */ + msg[0] = 0; + msg[1] = 0; + msg[2] = 0; + msg[3] = 1; + msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES; + if (atomicio(write, auth->fd, msg, 5) != 5) { + error("write auth->fd: %.100s", strerror(errno)); + return 0; + } + /* Read the length of the response. XXX implement timeouts here. */ + len = 4; + while (len > 0) { + l = read(auth->fd, msg + 4 - len, len); + if (l <= 0) { + error("read auth->fd: %.100s", strerror(errno)); + return 0; + } + len -= l; + } + + /* + * Extract the length, and check it for sanity. (We cannot trust + * authentication agents). + */ + len = GET_32BIT(msg); + if (len < 1 || len > 256 * 1024) + fatal("Authentication reply message too long: %d\n", len); + + /* Read the packet itself. */ + buffer_clear(&auth->identities); + while (len > 0) { + l = len; + if (l > sizeof(msg)) + l = sizeof(msg); + l = read(auth->fd, msg, l); + if (l <= 0) + fatal("Incomplete authentication reply."); + buffer_append(&auth->identities, (char *) msg, l); + len -= l; + } - /* Send a message to the agent requesting for a list of the identities - it can represent. */ - msg[0] = 0; - msg[1] = 0; - msg[2] = 0; - msg[3] = 1; - msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES; - if (write(auth->fd, msg, 5) != 5) - { - error("write auth->fd: %.100s", strerror(errno)); - return 0; - } - - /* Read the length of the response. XXX implement timeouts here. */ - len = 4; - while (len > 0) - { - l = read(auth->fd, msg + 4 - len, len); - if (l <= 0) - { - error("read auth->fd: %.100s", strerror(errno)); - return 0; - } - len -= l; - } - - /* Extract the length, and check it for sanity. (We cannot trust - authentication agents). */ - len = GET_32BIT(msg); - if (len < 1 || len > 256*1024) - fatal("Authentication reply message too long: %d\n", len); - - /* Read the packet itself. */ - buffer_clear(&auth->identities); - while (len > 0) - { - l = len; - if (l > sizeof(msg)) - l = sizeof(msg); - l = read(auth->fd, msg, l); - if (l <= 0) - fatal("Incomplete authentication reply."); - buffer_append(&auth->identities, (char *)msg, l); - len -= l; - } - - /* Get message type, and verify that we got a proper answer. */ - buffer_get(&auth->identities, (char *)msg, 1); - if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER) - fatal("Bad authentication reply message type: %d", msg[0]); - - /* Get the number of entries in the response and check it for sanity. */ - auth->howmany = buffer_get_int(&auth->identities); - if (auth->howmany > 1024) - fatal("Too many identities in authentication reply: %d\n", auth->howmany); + /* Get message type, and verify that we got a proper answer. */ + buffer_get(&auth->identities, (char *) msg, 1); + if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER) + fatal("Bad authentication reply message type: %d", msg[0]); + + /* Get the number of entries in the response and check it for sanity. */ + auth->howmany = buffer_get_int(&auth->identities); + if (auth->howmany > 1024) + fatal("Too many identities in authentication reply: %d\n", auth->howmany); - /* Return the first entry (if any). */ - return ssh_get_next_identity(auth, bitsp, e, n, comment); + /* Return the first entry (if any). */ + return ssh_get_next_identity(auth, e, n, comment); } -/* Returns the next authentication identity for the agent. Other functions - can be called between this and ssh_get_first_identity or two calls of this - function. This returns 0 if there are no more identities. The caller - must free comment after a successful return. */ +/* + * Returns the next authentication identity for the agent. Other functions + * can be called between this and ssh_get_first_identity or two calls of this + * function. This returns 0 if there are no more identities. The caller + * must free comment after a successful return. + */ int ssh_get_next_identity(AuthenticationConnection *auth, - int *bitsp, BIGNUM *e, BIGNUM *n, char **comment) + BIGNUM *e, BIGNUM *n, char **comment) { - /* Return failure if no more entries. */ - if (auth->howmany <= 0) - return 0; - - /* Get the next entry from the packet. These will abort with a fatal - error if the packet is too short or contains corrupt data. */ - *bitsp = buffer_get_int(&auth->identities); - buffer_get_bignum(&auth->identities, e); - buffer_get_bignum(&auth->identities, n); - *comment = buffer_get_string(&auth->identities, NULL); + unsigned int bits; + + /* Return failure if no more entries. */ + if (auth->howmany <= 0) + return 0; + + /* + * Get the next entry from the packet. These will abort with a fatal + * error if the packet is too short or contains corrupt data. + */ + bits = buffer_get_int(&auth->identities); + buffer_get_bignum(&auth->identities, e); + buffer_get_bignum(&auth->identities, n); + *comment = buffer_get_string(&auth->identities, NULL); + + if (bits != BN_num_bits(n)) + error("Warning: keysize mismatch: actual %d, announced %u", + BN_num_bits(n), bits); - /* Decrement the number of remaining entries. */ - auth->howmany--; + /* Decrement the number of remaining entries. */ + auth->howmany--; - return 1; + return 1; } -/* Generates a random challenge, sends it to the agent, and waits for response - from the agent. Returns true (non-zero) if the agent gave the correct - answer, zero otherwise. Response type selects the style of response - desired, with 0 corresponding to protocol version 1.0 (no longer supported) - and 1 corresponding to protocol version 1.1. */ +/* + * Generates a random challenge, sends it to the agent, and waits for + * response from the agent. Returns true (non-zero) if the agent gave the + * correct answer, zero otherwise. Response type selects the style of + * response desired, with 0 corresponding to protocol version 1.0 (no longer + * supported) and 1 corresponding to protocol version 1.1. + */ int ssh_decrypt_challenge(AuthenticationConnection *auth, - int bits, BIGNUM *e, BIGNUM *n, BIGNUM *challenge, + BIGNUM* e, BIGNUM *n, BIGNUM *challenge, unsigned char session_id[16], unsigned int response_type, unsigned char response[16]) { - Buffer buffer; - unsigned char buf[8192]; - int len, l, i; - - /* Response type 0 is no longer supported. */ - if (response_type == 0) - fatal("Compatibility with ssh protocol version 1.0 no longer supported."); - - /* Format a message to the agent. */ - buf[0] = SSH_AGENTC_RSA_CHALLENGE; - buffer_init(&buffer); - buffer_append(&buffer, (char *)buf, 1); - buffer_put_int(&buffer, bits); - buffer_put_bignum(&buffer, e); - buffer_put_bignum(&buffer, n); - buffer_put_bignum(&buffer, challenge); - buffer_append(&buffer, (char *)session_id, 16); - buffer_put_int(&buffer, response_type); - - /* Get the length of the message, and format it in the buffer. */ - len = buffer_len(&buffer); - PUT_32BIT(buf, len); - - /* Send the length and then the packet to the agent. */ - if (write(auth->fd, buf, 4) != 4 || - write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != - buffer_len(&buffer)) - { - error("Error writing to authentication socket."); - error_cleanup: - buffer_free(&buffer); - return 0; - } - - /* Wait for response from the agent. First read the length of the - response packet. */ - len = 4; - while (len > 0) - { - l = read(auth->fd, buf + 4 - len, len); - if (l <= 0) - { - error("Error reading response length from authentication socket."); - goto error_cleanup; - } - len -= l; - } - - /* Extract the length, and check it for sanity. */ - len = GET_32BIT(buf); - if (len > 256*1024) - fatal("Authentication response too long: %d", len); - - /* Read the rest of the response in tothe buffer. */ - buffer_clear(&buffer); - while (len > 0) - { - l = len; - if (l > sizeof(buf)) - l = sizeof(buf); - l = read(auth->fd, buf, l); - if (l <= 0) - { - error("Error reading response from authentication socket."); - goto error_cleanup; - } - buffer_append(&buffer, (char *)buf, l); - len -= l; - } - - /* Get the type of the packet. */ - buffer_get(&buffer, (char *)buf, 1); - - /* Check for agent failure message. */ - if (buf[0] == SSH_AGENT_FAILURE) - { - log("Agent admitted failure to authenticate using the key."); - goto error_cleanup; - } - - /* Now it must be an authentication response packet. */ - if (buf[0] != SSH_AGENT_RSA_RESPONSE) - fatal("Bad authentication response: %d", buf[0]); - - /* Get the response from the packet. This will abort with a fatal error - if the packet is corrupt. */ - for (i = 0; i < 16; i++) - response[i] = buffer_get_char(&buffer); - - /* The buffer containing the packet is no longer needed. */ - buffer_free(&buffer); - - /* Correct answer. */ - return 1; -} + Buffer buffer; + unsigned char buf[8192]; + int len, l, i; + + /* Response type 0 is no longer supported. */ + if (response_type == 0) + fatal("Compatibility with ssh protocol version 1.0 no longer supported."); + + /* Format a message to the agent. */ + buf[0] = SSH_AGENTC_RSA_CHALLENGE; + buffer_init(&buffer); + buffer_append(&buffer, (char *) buf, 1); + buffer_put_int(&buffer, BN_num_bits(n)); + buffer_put_bignum(&buffer, e); + buffer_put_bignum(&buffer, n); + buffer_put_bignum(&buffer, challenge); + buffer_append(&buffer, (char *) session_id, 16); + buffer_put_int(&buffer, response_type); + + /* Get the length of the message, and format it in the buffer. */ + len = buffer_len(&buffer); + PUT_32BIT(buf, len); + + /* Send the length and then the packet to the agent. */ + if (atomicio(write, auth->fd, buf, 4) != 4 || + atomicio(write, auth->fd, buffer_ptr(&buffer), + buffer_len(&buffer)) != buffer_len(&buffer)) { + error("Error writing to authentication socket."); +error_cleanup: + buffer_free(&buffer); + return 0; + } + /* + * Wait for response from the agent. First read the length of the + * response packet. + */ + len = 4; + while (len > 0) { + l = read(auth->fd, buf + 4 - len, len); + if (l <= 0) { + error("Error reading response length from authentication socket."); + goto error_cleanup; + } + len -= l; + } + + /* Extract the length, and check it for sanity. */ + len = GET_32BIT(buf); + if (len > 256 * 1024) + fatal("Authentication response too long: %d", len); + + /* Read the rest of the response in tothe buffer. */ + buffer_clear(&buffer); + while (len > 0) { + l = len; + if (l > sizeof(buf)) + l = sizeof(buf); + l = read(auth->fd, buf, l); + if (l <= 0) { + error("Error reading response from authentication socket."); + goto error_cleanup; + } + buffer_append(&buffer, (char *) buf, l); + len -= l; + } + + /* Get the type of the packet. */ + buffer_get(&buffer, (char *) buf, 1); + + /* Check for agent failure message. */ + if (buf[0] == SSH_AGENT_FAILURE) { + log("Agent admitted failure to authenticate using the key."); + goto error_cleanup; + } + /* Now it must be an authentication response packet. */ + if (buf[0] != SSH_AGENT_RSA_RESPONSE) + fatal("Bad authentication response: %d", buf[0]); + + /* + * Get the response from the packet. This will abort with a fatal + * error if the packet is corrupt. + */ + for (i = 0; i < 16; i++) + response[i] = buffer_get_char(&buffer); -/* Adds an identity to the authentication server. This call is not meant to - be used by normal applications. */ + /* The buffer containing the packet is no longer needed. */ + buffer_free(&buffer); -int ssh_add_identity(AuthenticationConnection *auth, - RSA *key, const char *comment) + /* Correct answer. */ + return 1; +} + +/* + * Adds an identity to the authentication server. This call is not meant to + * be used by normal applications. + */ + +int +ssh_add_identity(AuthenticationConnection *auth, + RSA * key, const char *comment) { - Buffer buffer; - unsigned char buf[8192]; - int len, l, type; - - /* Format a message to the agent. */ - buffer_init(&buffer); - buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY); - buffer_put_int(&buffer, BN_num_bits(key->n)); - buffer_put_bignum(&buffer, key->n); - buffer_put_bignum(&buffer, key->e); - buffer_put_bignum(&buffer, key->d); - /* To keep within the protocol: p < q for ssh. in SSL p > q */ - buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */ - buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */ - buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */ - buffer_put_string(&buffer, comment, strlen(comment)); - - /* Get the length of the message, and format it in the buffer. */ - len = buffer_len(&buffer); - PUT_32BIT(buf, len); - - /* Send the length and then the packet to the agent. */ - if (write(auth->fd, buf, 4) != 4 || - write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != - buffer_len(&buffer)) - { - error("Error writing to authentication socket."); - error_cleanup: - buffer_free(&buffer); - return 0; - } - - /* Wait for response from the agent. First read the length of the - response packet. */ - len = 4; - while (len > 0) - { - l = read(auth->fd, buf + 4 - len, len); - if (l <= 0) - { - error("Error reading response length from authentication socket."); - goto error_cleanup; - } - len -= l; - } - - /* Extract the length, and check it for sanity. */ - len = GET_32BIT(buf); - if (len > 256*1024) - fatal("Add identity response too long: %d", len); - - /* Read the rest of the response in tothe buffer. */ - buffer_clear(&buffer); - while (len > 0) - { - l = len; - if (l > sizeof(buf)) - l = sizeof(buf); - l = read(auth->fd, buf, l); - if (l <= 0) - { - error("Error reading response from authentication socket."); - goto error_cleanup; - } - buffer_append(&buffer, (char *)buf, l); - len -= l; - } - - /* Get the type of the packet. */ - type = buffer_get_char(&buffer); - switch (type) - { - case SSH_AGENT_FAILURE: - buffer_free(&buffer); - return 0; - case SSH_AGENT_SUCCESS: - buffer_free(&buffer); - return 1; - default: - fatal("Bad response to add identity from authentication agent: %d", - type); - } - /*NOTREACHED*/ - return 0; -} + Buffer buffer; + unsigned char buf[8192]; + int len, l, type; + + /* Format a message to the agent. */ + buffer_init(&buffer); + buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY); + buffer_put_int(&buffer, BN_num_bits(key->n)); + buffer_put_bignum(&buffer, key->n); + buffer_put_bignum(&buffer, key->e); + buffer_put_bignum(&buffer, key->d); + /* To keep within the protocol: p < q for ssh. in SSL p > q */ + buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */ + buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */ + buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */ + buffer_put_string(&buffer, comment, strlen(comment)); + + /* Get the length of the message, and format it in the buffer. */ + len = buffer_len(&buffer); + PUT_32BIT(buf, len); + + /* Send the length and then the packet to the agent. */ + if (atomicio(write, auth->fd, buf, 4) != 4 || + atomicio(write, auth->fd, buffer_ptr(&buffer), + buffer_len(&buffer)) != buffer_len(&buffer)) { + error("Error writing to authentication socket."); +error_cleanup: + buffer_free(&buffer); + return 0; + } + /* Wait for response from the agent. First read the length of the + response packet. */ + len = 4; + while (len > 0) { + l = read(auth->fd, buf + 4 - len, len); + if (l <= 0) { + error("Error reading response length from authentication socket."); + goto error_cleanup; + } + len -= l; + } + + /* Extract the length, and check it for sanity. */ + len = GET_32BIT(buf); + if (len > 256 * 1024) + fatal("Add identity response too long: %d", len); + + /* Read the rest of the response in tothe buffer. */ + buffer_clear(&buffer); + while (len > 0) { + l = len; + if (l > sizeof(buf)) + l = sizeof(buf); + l = read(auth->fd, buf, l); + if (l <= 0) { + error("Error reading response from authentication socket."); + goto error_cleanup; + } + buffer_append(&buffer, (char *) buf, l); + len -= l; + } -/* Removes an identity from the authentication server. This call is not meant - to be used by normal applications. */ + /* Get the type of the packet. */ + type = buffer_get_char(&buffer); + switch (type) { + case SSH_AGENT_FAILURE: + buffer_free(&buffer); + return 0; + case SSH_AGENT_SUCCESS: + buffer_free(&buffer); + return 1; + default: + fatal("Bad response to add identity from authentication agent: %d", + type); + } + /* NOTREACHED */ + return 0; +} + +/* + * Removes an identity from the authentication server. This call is not + * meant to be used by normal applications. + */ -int ssh_remove_identity(AuthenticationConnection *auth, RSA *key) +int +ssh_remove_identity(AuthenticationConnection *auth, RSA *key) { - Buffer buffer; - unsigned char buf[8192]; - int len, l, type; - - /* Format a message to the agent. */ - buffer_init(&buffer); - buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY); - buffer_put_int(&buffer, BN_num_bits(key->n)); - buffer_put_bignum(&buffer, key->e); - buffer_put_bignum(&buffer, key->n); - - /* Get the length of the message, and format it in the buffer. */ - len = buffer_len(&buffer); - PUT_32BIT(buf, len); - - /* Send the length and then the packet to the agent. */ - if (write(auth->fd, buf, 4) != 4 || - write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) != - buffer_len(&buffer)) - { - error("Error writing to authentication socket."); - error_cleanup: - buffer_free(&buffer); - return 0; - } - - /* Wait for response from the agent. First read the length of the - response packet. */ - len = 4; - while (len > 0) - { - l = read(auth->fd, buf + 4 - len, len); - if (l <= 0) - { - error("Error reading response length from authentication socket."); - goto error_cleanup; - } - len -= l; - } - - /* Extract the length, and check it for sanity. */ - len = GET_32BIT(buf); - if (len > 256*1024) - fatal("Remove identity response too long: %d", len); - - /* Read the rest of the response in tothe buffer. */ - buffer_clear(&buffer); - while (len > 0) - { - l = len; - if (l > sizeof(buf)) - l = sizeof(buf); - l = read(auth->fd, buf, l); - if (l <= 0) - { - error("Error reading response from authentication socket."); - goto error_cleanup; - } - buffer_append(&buffer, (char *)buf, l); - len -= l; - } - - /* Get the type of the packet. */ - type = buffer_get_char(&buffer); - switch (type) - { - case SSH_AGENT_FAILURE: - buffer_free(&buffer); - return 0; - case SSH_AGENT_SUCCESS: - buffer_free(&buffer); - return 1; - default: - fatal("Bad response to remove identity from authentication agent: %d", - type); - } - /*NOTREACHED*/ - return 0; -} + Buffer buffer; + unsigned char buf[8192]; + int len, l, type; + + /* Format a message to the agent. */ + buffer_init(&buffer); + buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY); + buffer_put_int(&buffer, BN_num_bits(key->n)); + buffer_put_bignum(&buffer, key->e); + buffer_put_bignum(&buffer, key->n); + + /* Get the length of the message, and format it in the buffer. */ + len = buffer_len(&buffer); + PUT_32BIT(buf, len); + + /* Send the length and then the packet to the agent. */ + if (atomicio(write, auth->fd, buf, 4) != 4 || + atomicio(write, auth->fd, buffer_ptr(&buffer), + buffer_len(&buffer)) != buffer_len(&buffer)) { + error("Error writing to authentication socket."); +error_cleanup: + buffer_free(&buffer); + return 0; + } + /* + * Wait for response from the agent. First read the length of the + * response packet. + */ + len = 4; + while (len > 0) { + l = read(auth->fd, buf + 4 - len, len); + if (l <= 0) { + error("Error reading response length from authentication socket."); + goto error_cleanup; + } + len -= l; + } -/* Removes all identities from the agent. This call is not meant - to be used by normal applications. */ + /* Extract the length, and check it for sanity. */ + len = GET_32BIT(buf); + if (len > 256 * 1024) + fatal("Remove identity response too long: %d", len); + + /* Read the rest of the response in tothe buffer. */ + buffer_clear(&buffer); + while (len > 0) { + l = len; + if (l > sizeof(buf)) + l = sizeof(buf); + l = read(auth->fd, buf, l); + if (l <= 0) { + error("Error reading response from authentication socket."); + goto error_cleanup; + } + buffer_append(&buffer, (char *) buf, l); + len -= l; + } -int ssh_remove_all_identities(AuthenticationConnection *auth) + /* Get the type of the packet. */ + type = buffer_get_char(&buffer); + switch (type) { + case SSH_AGENT_FAILURE: + buffer_free(&buffer); + return 0; + case SSH_AGENT_SUCCESS: + buffer_free(&buffer); + return 1; + default: + fatal("Bad response to remove identity from authentication agent: %d", + type); + } + /* NOTREACHED */ + return 0; +} + +/* + * Removes all identities from the agent. This call is not meant to be used + * by normal applications. + */ + +int +ssh_remove_all_identities(AuthenticationConnection *auth) { - Buffer buffer; - unsigned char buf[8192]; - int len, l, type; - - /* Get the length of the message, and format it in the buffer. */ - PUT_32BIT(buf, 1); - buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES; - - /* Send the length and then the packet to the agent. */ - if (write(auth->fd, buf, 5) != 5) - { - error("Error writing to authentication socket."); - return 0; - } - - /* Wait for response from the agent. First read the length of the - response packet. */ - len = 4; - while (len > 0) - { - l = read(auth->fd, buf + 4 - len, len); - if (l <= 0) - { - error("Error reading response length from authentication socket."); - return 0; - } - len -= l; - } - - /* Extract the length, and check it for sanity. */ - len = GET_32BIT(buf); - if (len > 256*1024) - fatal("Remove identity response too long: %d", len); - - /* Read the rest of the response into the buffer. */ - buffer_init(&buffer); - while (len > 0) - { - l = len; - if (l > sizeof(buf)) - l = sizeof(buf); - l = read(auth->fd, buf, l); - if (l <= 0) - { - error("Error reading response from authentication socket."); - buffer_free(&buffer); - return 0; - } - buffer_append(&buffer, (char *)buf, l); - len -= l; - } - - /* Get the type of the packet. */ - type = buffer_get_char(&buffer); - switch (type) - { - case SSH_AGENT_FAILURE: - buffer_free(&buffer); - return 0; - case SSH_AGENT_SUCCESS: - buffer_free(&buffer); - return 1; - default: - fatal("Bad response to remove identity from authentication agent: %d", - type); - } - /*NOTREACHED*/ - return 0; -} + Buffer buffer; + unsigned char buf[8192]; + int len, l, type; + + /* Get the length of the message, and format it in the buffer. */ + PUT_32BIT(buf, 1); + buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES; + + /* Send the length and then the packet to the agent. */ + if (atomicio(write, auth->fd, buf, 5) != 5) { + error("Error writing to authentication socket."); + return 0; + } + /* + * Wait for response from the agent. First read the length of the + * response packet. + */ + len = 4; + while (len > 0) { + l = read(auth->fd, buf + 4 - len, len); + if (l <= 0) { + error("Error reading response length from authentication socket."); + return 0; + } + len -= l; + } + + /* Extract the length, and check it for sanity. */ + len = GET_32BIT(buf); + if (len > 256 * 1024) + fatal("Remove identity response too long: %d", len); + + /* Read the rest of the response into the buffer. */ + buffer_init(&buffer); + while (len > 0) { + l = len; + if (l > sizeof(buf)) + l = sizeof(buf); + l = read(auth->fd, buf, l); + if (l <= 0) { + error("Error reading response from authentication socket."); + buffer_free(&buffer); + return 0; + } + buffer_append(&buffer, (char *) buf, l); + len -= l; + } + + /* Get the type of the packet. */ + type = buffer_get_char(&buffer); + switch (type) { + case SSH_AGENT_FAILURE: + buffer_free(&buffer); + return 0; + case SSH_AGENT_SUCCESS: + buffer_free(&buffer); + return 1; + default: + fatal("Bad response to remove identity from authentication agent: %d", + type); + } + /* NOTREACHED */ + return 0; +} Index: usr.bin/ssh/authfd.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/authfd.h,v retrieving revision 1.3 retrieving revision 1.6 diff -u -r1.3 -r1.6 --- usr.bin/ssh/authfd.h 1999/10/14 18:17:42 1.3 +++ usr.bin/ssh/authfd.h 1999/11/24 19:53:44 1.6 @@ -1,20 +1,20 @@ /* + * + * authfd.h + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Wed Mar 29 01:17:41 1995 ylo + * + * Functions to interface with the SSH_AUTHENTICATION_FD socket. + * + */ -authfd.h +/* RCSID("$Id: authfd.h,v 1.6 1999/11/24 19:53:44 markus Exp $"); */ -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Wed Mar 29 01:17:41 1995 ylo - -Functions to interface with the SSH_AUTHENTICATION_FD socket. - -*/ - -/* RCSID("$Id: authfd.h,v 1.3 1999/10/14 18:17:42 markus Exp $"); */ - #ifndef AUTHFD_H #define AUTHFD_H @@ -30,73 +30,90 @@ #define SSH_AGENTC_ADD_RSA_IDENTITY 7 #define SSH_AGENTC_REMOVE_RSA_IDENTITY 8 #define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9 - -typedef struct -{ - int fd; - Buffer packet; - Buffer identities; - int howmany; -} AuthenticationConnection; +typedef struct { + int fd; + Buffer packet; + Buffer identities; + int howmany; +} AuthenticationConnection; /* Returns the number of the authentication fd, or -1 if there is none. */ -int ssh_get_authentication_socket(); +int ssh_get_authentication_socket(); -/* This should be called for any descriptor returned by - ssh_get_authentication_socket(). Depending on the way the descriptor was - obtained, this may close the descriptor. */ -void ssh_close_authentication_socket(int authfd); - -/* Opens and connects a private socket for communication with the - authentication agent. Returns NULL if an error occurred and the - connection could not be opened. The connection should be closed by - the caller by calling ssh_close_authentication_connection(). */ +/* + * This should be called for any descriptor returned by + * ssh_get_authentication_socket(). Depending on the way the descriptor was + * obtained, this may close the descriptor. + */ +void ssh_close_authentication_socket(int authfd); + +/* + * Opens and connects a private socket for communication with the + * authentication agent. Returns NULL if an error occurred and the + * connection could not be opened. The connection should be closed by the + * caller by calling ssh_close_authentication_connection(). + */ AuthenticationConnection *ssh_get_authentication_connection(); -/* Closes the connection to the authentication agent and frees any associated - memory. */ -void ssh_close_authentication_connection(AuthenticationConnection *ac); - -/* Returns the first authentication identity held by the agent. - Returns true if an identity is available, 0 otherwise. - The caller must initialize the integers before the call, and free the - comment after a successful call (before calling ssh_get_next_identity). */ -int ssh_get_first_identity(AuthenticationConnection *connection, - int *bitsp, BIGNUM *e, BIGNUM *n, char **comment); - -/* Returns the next authentication identity for the agent. Other functions - can be called between this and ssh_get_first_identity or two calls of this - function. This returns 0 if there are no more identities. The caller - must free comment after a successful return. */ -int ssh_get_next_identity(AuthenticationConnection *connection, - int *bitsp, BIGNUM *e, BIGNUM *n, char **comment); +/* + * Closes the connection to the authentication agent and frees any associated + * memory. + */ +void ssh_close_authentication_connection(AuthenticationConnection * ac); + +/* + * Returns the first authentication identity held by the agent. Returns true + * if an identity is available, 0 otherwise. The caller must initialize the + * integers before the call, and free the comment after a successful call + * (before calling ssh_get_next_identity). + */ +int +ssh_get_first_identity(AuthenticationConnection * connection, + BIGNUM * e, BIGNUM * n, char **comment); + +/* + * Returns the next authentication identity for the agent. Other functions + * can be called between this and ssh_get_first_identity or two calls of this + * function. This returns 0 if there are no more identities. The caller + * must free comment after a successful return. + */ +int +ssh_get_next_identity(AuthenticationConnection * connection, + BIGNUM * e, BIGNUM * n, char **comment); /* Requests the agent to decrypt the given challenge. Returns true if the agent claims it was able to decrypt it. */ -int ssh_decrypt_challenge(AuthenticationConnection *auth, - int bits, BIGNUM *e, BIGNUM *n, BIGNUM *challenge, - unsigned char session_id[16], - unsigned int response_type, - unsigned char response[16]); - -/* Adds an identity to the authentication server. This call is not meant to - be used by normal applications. This returns true if the identity - was successfully added. */ -int ssh_add_identity(AuthenticationConnection *connection, - RSA *key, const char *comment); - -/* Removes the identity from the authentication server. This call is - not meant to be used by normal applications. This returns true if the - identity was successfully added. */ -int ssh_remove_identity(AuthenticationConnection *connection, - RSA *key); - -/* Removes all identities from the authentication agent. This call is not - meant to be used by normal applications. This returns true if the - operation was successful. */ -int ssh_remove_all_identities(AuthenticationConnection *connection); +int +ssh_decrypt_challenge(AuthenticationConnection * auth, + BIGNUM * e, BIGNUM * n, BIGNUM * challenge, + unsigned char session_id[16], + unsigned int response_type, + unsigned char response[16]); + +/* + * Adds an identity to the authentication server. This call is not meant to + * be used by normal applications. This returns true if the identity was + * successfully added. + */ +int +ssh_add_identity(AuthenticationConnection * connection, RSA * key, + const char *comment); + +/* + * Removes the identity from the authentication server. This call is not + * meant to be used by normal applications. This returns true if the + * identity was successfully added. + */ +int ssh_remove_identity(AuthenticationConnection * connection, RSA * key); + +/* + * Removes all identities from the authentication agent. This call is not + * meant to be used by normal applications. This returns true if the + * operation was successful. + */ +int ssh_remove_all_identities(AuthenticationConnection * connection); /* Closes the connection to the authentication agent. */ -void ssh_close_authentication(AuthenticationConnection *connection); +void ssh_close_authentication(AuthenticationConnection * connection); -#endif /* AUTHFD_H */ +#endif /* AUTHFD_H */ Index: usr.bin/ssh/authfile.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/authfile.c,v retrieving revision 1.7 retrieving revision 1.11 diff -u -r1.7 -r1.11 --- usr.bin/ssh/authfile.c 1999/10/11 20:00:35 1.7 +++ usr.bin/ssh/authfile.c 1999/12/06 19:11:15 1.11 @@ -1,21 +1,21 @@ /* + * + * authfile.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Mon Mar 27 03:52:05 1995 ylo + * + * This file contains functions for reading and writing identity files, and + * for reading the passphrase from the user. + * + */ -authfile.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Mon Mar 27 03:52:05 1995 ylo - -This file contains functions for reading and writing identity files, and -for reading the passphrase from the user. - -*/ - #include "includes.h" -RCSID("$Id: authfile.c,v 1.7 1999/10/11 20:00:35 markus Exp $"); +RCSID("$Id: authfile.c,v 1.11 1999/12/06 19:11:15 deraadt Exp $"); #include #include "xmalloc.h" @@ -27,324 +27,319 @@ /* Version identification string for identity files. */ #define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n" -/* Saves the authentication (private) key in a file, encrypting it with - passphrase. The identification of the file (lowest 64 bits of n) - will precede the key to provide identification of the key without - needing a passphrase. */ +/* + * Saves the authentication (private) key in a file, encrypting it with + * passphrase. The identification of the file (lowest 64 bits of n) will + * precede the key to provide identification of the key without needing a + * passphrase. + */ int save_private_key(const char *filename, const char *passphrase, RSA *key, const char *comment) { - Buffer buffer, encrypted; - char buf[100], *cp; - int f, i; - CipherContext cipher; - int cipher_type; - u_int32_t rand; - - /* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting to - another cipher; otherwise use SSH_AUTHFILE_CIPHER. */ - if (strcmp(passphrase, "") == 0) - cipher_type = SSH_CIPHER_NONE; - else - cipher_type = SSH_AUTHFILE_CIPHER; - - /* This buffer is used to built the secret part of the private key. */ - buffer_init(&buffer); - - /* Put checkbytes for checking passphrase validity. */ - rand = arc4random(); - buf[0] = rand & 0xff; - buf[1] = (rand >> 8) & 0xff; - buf[2] = buf[0]; - buf[3] = buf[1]; - buffer_append(&buffer, buf, 4); - - /* Store the private key (n and e will not be stored because they will - be stored in plain text, and storing them also in encrypted format - would just give known plaintext). */ - buffer_put_bignum(&buffer, key->d); - buffer_put_bignum(&buffer, key->iqmp); - buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */ - buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */ - - /* Pad the part to be encrypted until its size is a multiple of 8. */ - while (buffer_len(&buffer) % 8 != 0) - buffer_put_char(&buffer, 0); - - /* This buffer will be used to contain the data in the file. */ - buffer_init(&encrypted); - - /* First store keyfile id string. */ - cp = AUTHFILE_ID_STRING; - for (i = 0; cp[i]; i++) - buffer_put_char(&encrypted, cp[i]); - buffer_put_char(&encrypted, 0); - - /* Store cipher type. */ - buffer_put_char(&encrypted, cipher_type); - buffer_put_int(&encrypted, 0); /* For future extension */ - - /* Store public key. This will be in plain text. */ - buffer_put_int(&encrypted, BN_num_bits(key->n)); - buffer_put_bignum(&encrypted, key->n); - buffer_put_bignum(&encrypted, key->e); - buffer_put_string(&encrypted, comment, strlen(comment)); - - /* Allocate space for the private part of the key in the buffer. */ - buffer_append_space(&encrypted, &cp, buffer_len(&buffer)); - - cipher_set_key_string(&cipher, cipher_type, passphrase, 1); - cipher_encrypt(&cipher, (unsigned char *)cp, - (unsigned char *)buffer_ptr(&buffer), - buffer_len(&buffer)); - memset(&cipher, 0, sizeof(cipher)); - - /* Destroy temporary data. */ - memset(buf, 0, sizeof(buf)); - buffer_free(&buffer); - - /* Write to a file. */ - f = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600); - if (f < 0) - return 0; - - if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) != - buffer_len(&encrypted)) - { - debug("Write to key file %.200s failed: %.100s", filename, - strerror(errno)); - buffer_free(&encrypted); - close(f); - remove(filename); - return 0; - } - close(f); - buffer_free(&encrypted); - return 1; + Buffer buffer, encrypted; + char buf[100], *cp; + int fd, i; + CipherContext cipher; + int cipher_type; + u_int32_t rand; + + /* + * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting + * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. + */ + if (strcmp(passphrase, "") == 0) + cipher_type = SSH_CIPHER_NONE; + else + cipher_type = SSH_AUTHFILE_CIPHER; + + /* This buffer is used to built the secret part of the private key. */ + buffer_init(&buffer); + + /* Put checkbytes for checking passphrase validity. */ + rand = arc4random(); + buf[0] = rand & 0xff; + buf[1] = (rand >> 8) & 0xff; + buf[2] = buf[0]; + buf[3] = buf[1]; + buffer_append(&buffer, buf, 4); + + /* + * Store the private key (n and e will not be stored because they + * will be stored in plain text, and storing them also in encrypted + * format would just give known plaintext). + */ + buffer_put_bignum(&buffer, key->d); + buffer_put_bignum(&buffer, key->iqmp); + buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */ + buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */ + + /* Pad the part to be encrypted until its size is a multiple of 8. */ + while (buffer_len(&buffer) % 8 != 0) + buffer_put_char(&buffer, 0); + + /* This buffer will be used to contain the data in the file. */ + buffer_init(&encrypted); + + /* First store keyfile id string. */ + cp = AUTHFILE_ID_STRING; + for (i = 0; cp[i]; i++) + buffer_put_char(&encrypted, cp[i]); + buffer_put_char(&encrypted, 0); + + /* Store cipher type. */ + buffer_put_char(&encrypted, cipher_type); + buffer_put_int(&encrypted, 0); /* For future extension */ + + /* Store public key. This will be in plain text. */ + buffer_put_int(&encrypted, BN_num_bits(key->n)); + buffer_put_bignum(&encrypted, key->n); + buffer_put_bignum(&encrypted, key->e); + buffer_put_string(&encrypted, comment, strlen(comment)); + + /* Allocate space for the private part of the key in the buffer. */ + buffer_append_space(&encrypted, &cp, buffer_len(&buffer)); + + cipher_set_key_string(&cipher, cipher_type, passphrase, 1); + cipher_encrypt(&cipher, (unsigned char *) cp, + (unsigned char *) buffer_ptr(&buffer), + buffer_len(&buffer)); + memset(&cipher, 0, sizeof(cipher)); + + /* Destroy temporary data. */ + memset(buf, 0, sizeof(buf)); + buffer_free(&buffer); + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) + return 0; + if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) != + buffer_len(&encrypted)) { + debug("Write to key file %.200s failed: %.100s", filename, + strerror(errno)); + buffer_free(&encrypted); + close(fd); + remove(filename); + return 0; + } + close(fd); + buffer_free(&encrypted); + return 1; } -/* Loads the public part of the key file. Returns 0 if an error - was encountered (the file does not exist or is not readable), and - non-zero otherwise. */ +/* + * Loads the public part of the key file. Returns 0 if an error was + * encountered (the file does not exist or is not readable), and non-zero + * otherwise. + */ int -load_public_key(const char *filename, RSA *pub, +load_public_key(const char *filename, RSA * pub, char **comment_return) { - int f, i; - off_t len; - Buffer buffer; - char *cp; - - /* Read data from the file into the buffer. */ - f = open(filename, O_RDONLY); - if (f < 0) - return 0; - - len = lseek(f, (off_t)0, SEEK_END); - lseek(f, (off_t)0, SEEK_SET); - - buffer_init(&buffer); - buffer_append_space(&buffer, &cp, len); - - if (read(f, cp, (size_t)len) != (size_t)len) - { - debug("Read from key file %.200s failed: %.100s", filename, - strerror(errno)); - buffer_free(&buffer); - close(f); - return 0; - } - close(f); - - /* Check that it is at least big enought to contain the ID string. */ - if (len < strlen(AUTHFILE_ID_STRING) + 1) - { - debug("Bad key file %.200s.", filename); - buffer_free(&buffer); - return 0; - } - - /* Make sure it begins with the id string. Consume the id string from - the buffer. */ - for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++) - if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i]) - { - debug("Bad key file %.200s.", filename); + int fd, i; + off_t len; + Buffer buffer; + char *cp; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return 0; + len = lseek(fd, (off_t) 0, SEEK_END); + lseek(fd, (off_t) 0, SEEK_SET); + + buffer_init(&buffer); + buffer_append_space(&buffer, &cp, len); + + if (read(fd, cp, (size_t) len) != (size_t) len) { + debug("Read from key file %.200s failed: %.100s", filename, + strerror(errno)); + buffer_free(&buffer); + close(fd); + return 0; + } + close(fd); + + /* Check that it is at least big enought to contain the ID string. */ + if (len < strlen(AUTHFILE_ID_STRING) + 1) { + debug("Bad key file %.200s.", filename); + buffer_free(&buffer); + return 0; + } + /* + * Make sure it begins with the id string. Consume the id string + * from the buffer. + */ + for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) + if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) { + debug("Bad key file %.200s.", filename); + buffer_free(&buffer); + return 0; + } + /* Skip cipher type and reserved data. */ + (void) buffer_get_char(&buffer); /* cipher type */ + (void) buffer_get_int(&buffer); /* reserved */ + + /* Read the public key from the buffer. */ + buffer_get_int(&buffer); + pub->n = BN_new(); + buffer_get_bignum(&buffer, pub->n); + pub->e = BN_new(); + buffer_get_bignum(&buffer, pub->e); + if (comment_return) + *comment_return = buffer_get_string(&buffer, NULL); + /* The encrypted private part is not parsed by this function. */ + buffer_free(&buffer); - return 0; - } - /* Skip cipher type and reserved data. */ - (void)buffer_get_char(&buffer); /* cipher type */ - (void)buffer_get_int(&buffer); /* reserved */ - - /* Read the public key from the buffer. */ - buffer_get_int(&buffer); - pub->n = BN_new(); - buffer_get_bignum(&buffer, pub->n); - pub->e = BN_new(); - buffer_get_bignum(&buffer, pub->e); - if (comment_return) - *comment_return = buffer_get_string(&buffer, NULL); - /* The encrypted private part is not parsed by this function. */ - - buffer_free(&buffer); - - return 1; + return 1; } -/* Loads the private key from the file. Returns 0 if an error is encountered - (file does not exist or is not readable, or passphrase is bad). - This initializes the private key. */ +/* + * Loads the private key from the file. Returns 0 if an error is encountered + * (file does not exist or is not readable, or passphrase is bad). This + * initializes the private key. + * Assumes we are called under uid of the owner of the file. + */ int load_private_key(const char *filename, const char *passphrase, - RSA *prv, char **comment_return) + RSA * prv, char **comment_return) { - int f, i, check1, check2, cipher_type; - off_t len; - Buffer buffer, decrypted; - char *cp; - CipherContext cipher; - BN_CTX *ctx; - BIGNUM *aux; - struct stat st; - - /* Read the file into the buffer. */ - f = open(filename, O_RDONLY); - if (f < 0) - return 0; - - /* We assume we are called under uid of the owner of the file */ - if (fstat(f, &st) < 0 || - (st.st_uid != 0 && st.st_uid != getuid()) || - (st.st_mode & 077) != 0) { - error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); - error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - error("Bad ownership or mode(0%3.3o) for '%s'.", - st.st_mode & 0777, filename); - error("It is recommended that your private key files are NOT accessible by others."); - return 0; - } - - len = lseek(f, (off_t)0, SEEK_END); - lseek(f, (off_t)0, SEEK_SET); - - buffer_init(&buffer); - buffer_append_space(&buffer, &cp, len); - - if (read(f, cp, (size_t)len) != (size_t)len) - { - debug("Read from key file %.200s failed: %.100s", filename, - strerror(errno)); - buffer_free(&buffer); - close(f); - return 0; - } - close(f); - - /* Check that it is at least big enought to contain the ID string. */ - if (len < strlen(AUTHFILE_ID_STRING) + 1) - { - debug("Bad key file %.200s.", filename); - buffer_free(&buffer); - return 0; - } - - /* Make sure it begins with the id string. Consume the id string from - the buffer. */ - for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++) - if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i]) - { - debug("Bad key file %.200s.", filename); + int fd, i, check1, check2, cipher_type; + off_t len; + Buffer buffer, decrypted; + char *cp; + CipherContext cipher; + BN_CTX *ctx; + BIGNUM *aux; + struct stat st; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return 0; + + /* check owner and modes */ + if (fstat(fd, &st) < 0 || + (st.st_uid != 0 && st.st_uid != getuid()) || + (st.st_mode & 077) != 0) { + close(fd); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("Bad ownership or mode(0%3.3o) for '%s'.", + st.st_mode & 0777, filename); + error("It is recommended that your private key files are NOT accessible by others."); + return 0; + } + len = lseek(fd, (off_t) 0, SEEK_END); + lseek(fd, (off_t) 0, SEEK_SET); + + buffer_init(&buffer); + buffer_append_space(&buffer, &cp, len); + + if (read(fd, cp, (size_t) len) != (size_t) len) { + debug("Read from key file %.200s failed: %.100s", filename, + strerror(errno)); + buffer_free(&buffer); + close(fd); + return 0; + } + close(fd); + + /* Check that it is at least big enought to contain the ID string. */ + if (len < strlen(AUTHFILE_ID_STRING) + 1) { + debug("Bad key file %.200s.", filename); + buffer_free(&buffer); + return 0; + } + /* + * Make sure it begins with the id string. Consume the id string + * from the buffer. + */ + for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) + if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) { + debug("Bad key file %.200s.", filename); + buffer_free(&buffer); + return 0; + } + /* Read cipher type. */ + cipher_type = buffer_get_char(&buffer); + (void) buffer_get_int(&buffer); /* Reserved data. */ + + /* Read the public key from the buffer. */ + buffer_get_int(&buffer); + prv->n = BN_new(); + buffer_get_bignum(&buffer, prv->n); + prv->e = BN_new(); + buffer_get_bignum(&buffer, prv->e); + if (comment_return) + *comment_return = buffer_get_string(&buffer, NULL); + else + xfree(buffer_get_string(&buffer, NULL)); + + /* Check that it is a supported cipher. */ + if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) & + (1 << cipher_type)) == 0) { + debug("Unsupported cipher %.100s used in key file %.200s.", + cipher_name(cipher_type), filename); + buffer_free(&buffer); + goto fail; + } + /* Initialize space for decrypted data. */ + buffer_init(&decrypted); + buffer_append_space(&decrypted, &cp, buffer_len(&buffer)); + + /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ + cipher_set_key_string(&cipher, cipher_type, passphrase, 0); + cipher_decrypt(&cipher, (unsigned char *) cp, + (unsigned char *) buffer_ptr(&buffer), + buffer_len(&buffer)); + buffer_free(&buffer); - return 0; - } + + check1 = buffer_get_char(&decrypted); + check2 = buffer_get_char(&decrypted); + if (check1 != buffer_get_char(&decrypted) || + check2 != buffer_get_char(&decrypted)) { + if (strcmp(passphrase, "") != 0) + debug("Bad passphrase supplied for key file %.200s.", filename); + /* Bad passphrase. */ + buffer_free(&decrypted); +fail: + BN_clear_free(prv->n); + BN_clear_free(prv->e); + if (comment_return) + xfree(*comment_return); + return 0; + } + /* Read the rest of the private key. */ + prv->d = BN_new(); + buffer_get_bignum(&decrypted, prv->d); + prv->iqmp = BN_new(); + buffer_get_bignum(&decrypted, prv->iqmp); /* u */ + /* in SSL and SSH p and q are exchanged */ + prv->q = BN_new(); + buffer_get_bignum(&decrypted, prv->q); /* p */ + prv->p = BN_new(); + buffer_get_bignum(&decrypted, prv->p); /* q */ + + ctx = BN_CTX_new(); + aux = BN_new(); + + BN_sub(aux, prv->q, BN_value_one()); + prv->dmq1 = BN_new(); + BN_mod(prv->dmq1, prv->d, aux, ctx); + + BN_sub(aux, prv->p, BN_value_one()); + prv->dmp1 = BN_new(); + BN_mod(prv->dmp1, prv->d, aux, ctx); + + BN_clear_free(aux); + BN_CTX_free(ctx); - /* Read cipher type. */ - cipher_type = buffer_get_char(&buffer); - (void)buffer_get_int(&buffer); /* Reserved data. */ - - /* Read the public key from the buffer. */ - buffer_get_int(&buffer); - prv->n = BN_new(); - buffer_get_bignum(&buffer, prv->n); - prv->e = BN_new(); - buffer_get_bignum(&buffer, prv->e); - if (comment_return) - *comment_return = buffer_get_string(&buffer, NULL); - else - xfree(buffer_get_string(&buffer, NULL)); - - /* Check that it is a supported cipher. */ - if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) & - (1 << cipher_type)) == 0) - { - debug("Unsupported cipher %.100s used in key file %.200s.", - cipher_name(cipher_type), filename); - buffer_free(&buffer); - goto fail; - } - - /* Initialize space for decrypted data. */ - buffer_init(&decrypted); - buffer_append_space(&decrypted, &cp, buffer_len(&buffer)); - - /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ - cipher_set_key_string(&cipher, cipher_type, passphrase, 0); - cipher_decrypt(&cipher, (unsigned char *)cp, - (unsigned char *)buffer_ptr(&buffer), - buffer_len(&buffer)); - - buffer_free(&buffer); - - check1 = buffer_get_char(&decrypted); - check2 = buffer_get_char(&decrypted); - if (check1 != buffer_get_char(&decrypted) || - check2 != buffer_get_char(&decrypted)) - { - if (strcmp(passphrase, "") != 0) - debug("Bad passphrase supplied for key file %.200s.", filename); - /* Bad passphrase. */ - buffer_free(&decrypted); - fail: - BN_clear_free(prv->n); - BN_clear_free(prv->e); - if (comment_return) - xfree(*comment_return); - return 0; - } - - /* Read the rest of the private key. */ - prv->d = BN_new(); - buffer_get_bignum(&decrypted, prv->d); - prv->iqmp = BN_new(); - buffer_get_bignum(&decrypted, prv->iqmp); /* u */ - /* in SSL and SSH p and q are exchanged */ - prv->q = BN_new(); - buffer_get_bignum(&decrypted, prv->q); /* p */ - prv->p = BN_new(); - buffer_get_bignum(&decrypted, prv->p); /* q */ - - ctx = BN_CTX_new(); - aux = BN_new(); - - BN_sub(aux, prv->q, BN_value_one()); - prv->dmq1 = BN_new(); - BN_mod(prv->dmq1, prv->d, aux, ctx); - - BN_sub(aux, prv->p, BN_value_one()); - prv->dmp1 = BN_new(); - BN_mod(prv->dmp1, prv->d, aux, ctx); - - BN_clear_free(aux); - BN_CTX_free(ctx); - - buffer_free(&decrypted); + buffer_free(&decrypted); - return 1; + return 1; } Index: usr.bin/ssh/bf_enc.c =================================================================== RCS file: bf_enc.c diff -N bf_enc.c --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsnRBiD31367 Wed Dec 8 12:42:02 1999 @@ -0,0 +1,241 @@ +/* crypto/bf/bf_enc.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include "blowfish.h" +#include "bf_locl.h" + +/* Blowfish as implemented from 'Blowfish: Springer-Verlag paper' + * (From LECTURE NOTES IN COIMPUTER SCIENCE 809, FAST SOFTWARE ENCRYPTION, + * CAMBRIDGE SECURITY WORKSHOP, CAMBRIDGE, U.K., DECEMBER 9-11, 1993) + */ + +#if (BF_ROUNDS != 16) && (BF_ROUNDS != 20) +If you set BF_ROUNDS to some value other than 16 or 20, you will have +to modify the code. +#endif + +void BF_encrypt(data,key) +BF_LONG *data; +BF_KEY *key; + { + register BF_LONG l,r,*p,*s; + + p=key->P; + s= &(key->S[0]); + l=data[0]; + r=data[1]; + + l^=p[0]; + BF_ENC(r,l,s,p[ 1]); + BF_ENC(l,r,s,p[ 2]); + BF_ENC(r,l,s,p[ 3]); + BF_ENC(l,r,s,p[ 4]); + BF_ENC(r,l,s,p[ 5]); + BF_ENC(l,r,s,p[ 6]); + BF_ENC(r,l,s,p[ 7]); + BF_ENC(l,r,s,p[ 8]); + BF_ENC(r,l,s,p[ 9]); + BF_ENC(l,r,s,p[10]); + BF_ENC(r,l,s,p[11]); + BF_ENC(l,r,s,p[12]); + BF_ENC(r,l,s,p[13]); + BF_ENC(l,r,s,p[14]); + BF_ENC(r,l,s,p[15]); + BF_ENC(l,r,s,p[16]); +#if BF_ROUNDS == 20 + BF_ENC(r,l,s,p[17]); + BF_ENC(l,r,s,p[18]); + BF_ENC(r,l,s,p[19]); + BF_ENC(l,r,s,p[20]); +#endif + r^=p[BF_ROUNDS+1]; + + data[1]=l&0xffffffffL; + data[0]=r&0xffffffffL; + } + +#ifndef BF_DEFAULT_OPTIONS + +void BF_decrypt(data,key) +BF_LONG *data; +BF_KEY *key; + { + register BF_LONG l,r,*p,*s; + + p=key->P; + s= &(key->S[0]); + l=data[0]; + r=data[1]; + + l^=p[BF_ROUNDS+1]; +#if BF_ROUNDS == 20 + BF_ENC(r,l,s,p[20]); + BF_ENC(l,r,s,p[19]); + BF_ENC(r,l,s,p[18]); + BF_ENC(l,r,s,p[17]); +#endif + BF_ENC(r,l,s,p[16]); + BF_ENC(l,r,s,p[15]); + BF_ENC(r,l,s,p[14]); + BF_ENC(l,r,s,p[13]); + BF_ENC(r,l,s,p[12]); + BF_ENC(l,r,s,p[11]); + BF_ENC(r,l,s,p[10]); + BF_ENC(l,r,s,p[ 9]); + BF_ENC(r,l,s,p[ 8]); + BF_ENC(l,r,s,p[ 7]); + BF_ENC(r,l,s,p[ 6]); + BF_ENC(l,r,s,p[ 5]); + BF_ENC(r,l,s,p[ 4]); + BF_ENC(l,r,s,p[ 3]); + BF_ENC(r,l,s,p[ 2]); + BF_ENC(l,r,s,p[ 1]); + r^=p[0]; + + data[1]=l&0xffffffffL; + data[0]=r&0xffffffffL; + } + +void BF_cbc_encrypt(in, out, length, ks, iv, encrypt) +unsigned char *in; +unsigned char *out; +long length; +BF_KEY *ks; +unsigned char *iv; +int encrypt; + { + register BF_LONG tin0,tin1; + register BF_LONG tout0,tout1,xor0,xor1; + register long l=length; + BF_LONG tin[2]; + + if (encrypt) + { + n2l(iv,tout0); + n2l(iv,tout1); + iv-=8; + for (l-=8; l>=0; l-=8) + { + n2l(in,tin0); + n2l(in,tin1); + tin0^=tout0; + tin1^=tout1; + tin[0]=tin0; + tin[1]=tin1; + BF_encrypt(tin,ks); + tout0=tin[0]; + tout1=tin[1]; + l2n(tout0,out); + l2n(tout1,out); + } + if (l != -8) + { + n2ln(in,tin0,tin1,l+8); + tin0^=tout0; + tin1^=tout1; + tin[0]=tin0; + tin[1]=tin1; + BF_encrypt(tin,ks); + tout0=tin[0]; + tout1=tin[1]; + l2n(tout0,out); + l2n(tout1,out); + } + l2n(tout0,iv); + l2n(tout1,iv); + } + else + { + n2l(iv,xor0); + n2l(iv,xor1); + iv-=8; + for (l-=8; l>=0; l-=8) + { + n2l(in,tin0); + n2l(in,tin1); + tin[0]=tin0; + tin[1]=tin1; + BF_decrypt(tin,ks); + tout0=tin[0]^xor0; + tout1=tin[1]^xor1; + l2n(tout0,out); + l2n(tout1,out); + xor0=tin0; + xor1=tin1; + } + if (l != -8) + { + n2l(in,tin0); + n2l(in,tin1); + tin[0]=tin0; + tin[1]=tin1; + BF_decrypt(tin,ks); + tout0=tin[0]^xor0; + tout1=tin[1]^xor1; + l2nn(tout0,tout1,out,l+8); + xor0=tin0; + xor1=tin1; + } + l2n(xor0,iv); + l2n(xor1,iv); + } + tin0=tin1=tout0=tout1=xor0=xor1=0; + tin[0]=tin[1]=0; + } + +#endif Index: usr.bin/ssh/bf_locl.h =================================================================== RCS file: bf_locl.h diff -N bf_locl.h --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsvQmjj31367 Wed Dec 8 12:42:04 1999 @@ -0,0 +1,242 @@ +/* crypto/bf/bf_locl.org */ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * Always modify bf_locl.org since bf_locl.h is automatically generated from + * it during SSLeay configuration. + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + */ + +/* Special defines which change the way the code is built depending on the + CPU and OS. For SGI machines you can use _MIPS_SZLONG (32 or 64) to find + even newer MIPS CPU's, but at the moment one size fits all for + optimization options. Older Sparc's work better with only UNROLL, but + there's no way to tell at compile time what it is you're running on */ + +#if defined( sun ) /* Newer Sparc's */ +# define BF_PTR +#elif defined( __ultrix ) /* Older MIPS */ +# define BF_PTR +#elif defined( __osf1__ ) /* Alpha */ + /* None */ +#elif defined ( _AIX ) /* RS6000 */ + /* Unknown */ +#elif defined( __hpux ) /* HP-PA */ + /* None */ +#elif defined( __aux ) /* 68K */ + /* Unknown */ +#elif defined( __dgux ) /* 88K (but P6 in latest boxes) */ + /* Unknown */ +#elif defined( __sgi ) /* Newer MIPS */ +# define BF_PTR +#elif defined( i386 ) /* x86 boxes, should be gcc */ +#elif defined( _MSC_VER ) /* x86 boxes, Visual C */ +#endif /* Systems-specific speed defines */ + +#undef c2l +#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \ + l|=((unsigned long)(*((c)++)))<< 8L, \ + l|=((unsigned long)(*((c)++)))<<16L, \ + l|=((unsigned long)(*((c)++)))<<24L) + +/* NOTE - c is not incremented as per c2l */ +#undef c2ln +#define c2ln(c,l1,l2,n) { \ + c+=n; \ + l1=l2=0; \ + switch (n) { \ + case 8: l2 =((unsigned long)(*(--(c))))<<24L; \ + case 7: l2|=((unsigned long)(*(--(c))))<<16L; \ + case 6: l2|=((unsigned long)(*(--(c))))<< 8L; \ + case 5: l2|=((unsigned long)(*(--(c)))); \ + case 4: l1 =((unsigned long)(*(--(c))))<<24L; \ + case 3: l1|=((unsigned long)(*(--(c))))<<16L; \ + case 2: l1|=((unsigned long)(*(--(c))))<< 8L; \ + case 1: l1|=((unsigned long)(*(--(c)))); \ + } \ + } + +#undef l2c +#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24L)&0xff)) + +/* NOTE - c is not incremented as per l2c */ +#undef l2cn +#define l2cn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2)>>24L)&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>>16L)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>> 8L)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1)>>24L)&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>>16L)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>> 8L)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ + } \ + } + +/* NOTE - c is not incremented as per n2l */ +#define n2ln(c,l1,l2,n) { \ + c+=n; \ + l1=l2=0; \ + switch (n) { \ + case 8: l2 =((unsigned long)(*(--(c)))) ; \ + case 7: l2|=((unsigned long)(*(--(c))))<< 8; \ + case 6: l2|=((unsigned long)(*(--(c))))<<16; \ + case 5: l2|=((unsigned long)(*(--(c))))<<24; \ + case 4: l1 =((unsigned long)(*(--(c)))) ; \ + case 3: l1|=((unsigned long)(*(--(c))))<< 8; \ + case 2: l1|=((unsigned long)(*(--(c))))<<16; \ + case 1: l1|=((unsigned long)(*(--(c))))<<24; \ + } \ + } + +/* NOTE - c is not incremented as per l2n */ +#define l2nn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1) )&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \ + } \ + } + +#undef n2l +#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24L, \ + l|=((unsigned long)(*((c)++)))<<16L, \ + l|=((unsigned long)(*((c)++)))<< 8L, \ + l|=((unsigned long)(*((c)++)))) + +#undef l2n +#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24L)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16L)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +/* This is actually a big endian algorithm, the most significate byte + * is used to lookup array 0 */ + +/* use BF_PTR2 for intel boxes, + * BF_PTR for sparc and MIPS/SGI + * use nothing for Alpha and HP. + */ +#if !defined(BF_PTR) && !defined(BF_PTR2) +#undef BF_PTR +#endif + +#define BF_M 0x3fc +#define BF_0 22L +#define BF_1 14L +#define BF_2 6L +#define BF_3 2L /* left shift */ + +#if defined(BF_PTR2) + +/* This is basically a special pentium verson */ +#define BF_ENC(LL,R,S,P) \ + { \ + BF_LONG t,u,v; \ + u=R>>BF_0; \ + v=R>>BF_1; \ + u&=BF_M; \ + v&=BF_M; \ + t= *(BF_LONG *)((unsigned char *)&(S[ 0])+u); \ + u=R>>BF_2; \ + t+= *(BF_LONG *)((unsigned char *)&(S[256])+v); \ + v=R<>BF_0)&BF_M))+ \ + *(BF_LONG *)((unsigned char *)&(S[256])+((R>>BF_1)&BF_M)))^ \ + *(BF_LONG *)((unsigned char *)&(S[512])+((R>>BF_2)&BF_M)))+ \ + *(BF_LONG *)((unsigned char *)&(S[768])+((R<>24L) ] + \ + S[0x0100+((int)(R>>16L)&0xff)])^ \ + S[0x0200+((int)(R>> 8L)&0xff)])+ \ + S[0x0300+((int)(R )&0xff)])&0xffffffffL; +#endif Index: usr.bin/ssh/bf_pi.h =================================================================== RCS file: bf_pi.h diff -N bf_pi.h --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsgpEFI31367 Wed Dec 8 12:42:04 1999 @@ -0,0 +1,325 @@ +/* crypto/bf/bf_pi.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +static BF_KEY bf_init= { + { + 0x243f6a88L, 0x85a308d3L, 0x13198a2eL, 0x03707344L, + 0xa4093822L, 0x299f31d0L, 0x082efa98L, 0xec4e6c89L, + 0x452821e6L, 0x38d01377L, 0xbe5466cfL, 0x34e90c6cL, + 0xc0ac29b7L, 0xc97c50ddL, 0x3f84d5b5L, 0xb5470917L, + 0x9216d5d9L, 0x8979fb1b + },{ + 0xd1310ba6L, 0x98dfb5acL, 0x2ffd72dbL, 0xd01adfb7L, + 0xb8e1afedL, 0x6a267e96L, 0xba7c9045L, 0xf12c7f99L, + 0x24a19947L, 0xb3916cf7L, 0x0801f2e2L, 0x858efc16L, + 0x636920d8L, 0x71574e69L, 0xa458fea3L, 0xf4933d7eL, + 0x0d95748fL, 0x728eb658L, 0x718bcd58L, 0x82154aeeL, + 0x7b54a41dL, 0xc25a59b5L, 0x9c30d539L, 0x2af26013L, + 0xc5d1b023L, 0x286085f0L, 0xca417918L, 0xb8db38efL, + 0x8e79dcb0L, 0x603a180eL, 0x6c9e0e8bL, 0xb01e8a3eL, + 0xd71577c1L, 0xbd314b27L, 0x78af2fdaL, 0x55605c60L, + 0xe65525f3L, 0xaa55ab94L, 0x57489862L, 0x63e81440L, + 0x55ca396aL, 0x2aab10b6L, 0xb4cc5c34L, 0x1141e8ceL, + 0xa15486afL, 0x7c72e993L, 0xb3ee1411L, 0x636fbc2aL, + 0x2ba9c55dL, 0x741831f6L, 0xce5c3e16L, 0x9b87931eL, + 0xafd6ba33L, 0x6c24cf5cL, 0x7a325381L, 0x28958677L, + 0x3b8f4898L, 0x6b4bb9afL, 0xc4bfe81bL, 0x66282193L, + 0x61d809ccL, 0xfb21a991L, 0x487cac60L, 0x5dec8032L, + 0xef845d5dL, 0xe98575b1L, 0xdc262302L, 0xeb651b88L, + 0x23893e81L, 0xd396acc5L, 0x0f6d6ff3L, 0x83f44239L, + 0x2e0b4482L, 0xa4842004L, 0x69c8f04aL, 0x9e1f9b5eL, + 0x21c66842L, 0xf6e96c9aL, 0x670c9c61L, 0xabd388f0L, + 0x6a51a0d2L, 0xd8542f68L, 0x960fa728L, 0xab5133a3L, + 0x6eef0b6cL, 0x137a3be4L, 0xba3bf050L, 0x7efb2a98L, + 0xa1f1651dL, 0x39af0176L, 0x66ca593eL, 0x82430e88L, + 0x8cee8619L, 0x456f9fb4L, 0x7d84a5c3L, 0x3b8b5ebeL, + 0xe06f75d8L, 0x85c12073L, 0x401a449fL, 0x56c16aa6L, + 0x4ed3aa62L, 0x363f7706L, 0x1bfedf72L, 0x429b023dL, + 0x37d0d724L, 0xd00a1248L, 0xdb0fead3L, 0x49f1c09bL, + 0x075372c9L, 0x80991b7bL, 0x25d479d8L, 0xf6e8def7L, + 0xe3fe501aL, 0xb6794c3bL, 0x976ce0bdL, 0x04c006baL, + 0xc1a94fb6L, 0x409f60c4L, 0x5e5c9ec2L, 0x196a2463L, + 0x68fb6fafL, 0x3e6c53b5L, 0x1339b2ebL, 0x3b52ec6fL, + 0x6dfc511fL, 0x9b30952cL, 0xcc814544L, 0xaf5ebd09L, + 0xbee3d004L, 0xde334afdL, 0x660f2807L, 0x192e4bb3L, + 0xc0cba857L, 0x45c8740fL, 0xd20b5f39L, 0xb9d3fbdbL, + 0x5579c0bdL, 0x1a60320aL, 0xd6a100c6L, 0x402c7279L, + 0x679f25feL, 0xfb1fa3ccL, 0x8ea5e9f8L, 0xdb3222f8L, + 0x3c7516dfL, 0xfd616b15L, 0x2f501ec8L, 0xad0552abL, + 0x323db5faL, 0xfd238760L, 0x53317b48L, 0x3e00df82L, + 0x9e5c57bbL, 0xca6f8ca0L, 0x1a87562eL, 0xdf1769dbL, + 0xd542a8f6L, 0x287effc3L, 0xac6732c6L, 0x8c4f5573L, + 0x695b27b0L, 0xbbca58c8L, 0xe1ffa35dL, 0xb8f011a0L, + 0x10fa3d98L, 0xfd2183b8L, 0x4afcb56cL, 0x2dd1d35bL, + 0x9a53e479L, 0xb6f84565L, 0xd28e49bcL, 0x4bfb9790L, + 0xe1ddf2daL, 0xa4cb7e33L, 0x62fb1341L, 0xcee4c6e8L, + 0xef20cadaL, 0x36774c01L, 0xd07e9efeL, 0x2bf11fb4L, + 0x95dbda4dL, 0xae909198L, 0xeaad8e71L, 0x6b93d5a0L, + 0xd08ed1d0L, 0xafc725e0L, 0x8e3c5b2fL, 0x8e7594b7L, + 0x8ff6e2fbL, 0xf2122b64L, 0x8888b812L, 0x900df01cL, + 0x4fad5ea0L, 0x688fc31cL, 0xd1cff191L, 0xb3a8c1adL, + 0x2f2f2218L, 0xbe0e1777L, 0xea752dfeL, 0x8b021fa1L, + 0xe5a0cc0fL, 0xb56f74e8L, 0x18acf3d6L, 0xce89e299L, + 0xb4a84fe0L, 0xfd13e0b7L, 0x7cc43b81L, 0xd2ada8d9L, + 0x165fa266L, 0x80957705L, 0x93cc7314L, 0x211a1477L, + 0xe6ad2065L, 0x77b5fa86L, 0xc75442f5L, 0xfb9d35cfL, + 0xebcdaf0cL, 0x7b3e89a0L, 0xd6411bd3L, 0xae1e7e49L, + 0x00250e2dL, 0x2071b35eL, 0x226800bbL, 0x57b8e0afL, + 0x2464369bL, 0xf009b91eL, 0x5563911dL, 0x59dfa6aaL, + 0x78c14389L, 0xd95a537fL, 0x207d5ba2L, 0x02e5b9c5L, + 0x83260376L, 0x6295cfa9L, 0x11c81968L, 0x4e734a41L, + 0xb3472dcaL, 0x7b14a94aL, 0x1b510052L, 0x9a532915L, + 0xd60f573fL, 0xbc9bc6e4L, 0x2b60a476L, 0x81e67400L, + 0x08ba6fb5L, 0x571be91fL, 0xf296ec6bL, 0x2a0dd915L, + 0xb6636521L, 0xe7b9f9b6L, 0xff34052eL, 0xc5855664L, + 0x53b02d5dL, 0xa99f8fa1L, 0x08ba4799L, 0x6e85076aL, + 0x4b7a70e9L, 0xb5b32944L, 0xdb75092eL, 0xc4192623L, + 0xad6ea6b0L, 0x49a7df7dL, 0x9cee60b8L, 0x8fedb266L, + 0xecaa8c71L, 0x699a17ffL, 0x5664526cL, 0xc2b19ee1L, + 0x193602a5L, 0x75094c29L, 0xa0591340L, 0xe4183a3eL, + 0x3f54989aL, 0x5b429d65L, 0x6b8fe4d6L, 0x99f73fd6L, + 0xa1d29c07L, 0xefe830f5L, 0x4d2d38e6L, 0xf0255dc1L, + 0x4cdd2086L, 0x8470eb26L, 0x6382e9c6L, 0x021ecc5eL, + 0x09686b3fL, 0x3ebaefc9L, 0x3c971814L, 0x6b6a70a1L, + 0x687f3584L, 0x52a0e286L, 0xb79c5305L, 0xaa500737L, + 0x3e07841cL, 0x7fdeae5cL, 0x8e7d44ecL, 0x5716f2b8L, + 0xb03ada37L, 0xf0500c0dL, 0xf01c1f04L, 0x0200b3ffL, + 0xae0cf51aL, 0x3cb574b2L, 0x25837a58L, 0xdc0921bdL, + 0xd19113f9L, 0x7ca92ff6L, 0x94324773L, 0x22f54701L, + 0x3ae5e581L, 0x37c2dadcL, 0xc8b57634L, 0x9af3dda7L, + 0xa9446146L, 0x0fd0030eL, 0xecc8c73eL, 0xa4751e41L, + 0xe238cd99L, 0x3bea0e2fL, 0x3280bba1L, 0x183eb331L, + 0x4e548b38L, 0x4f6db908L, 0x6f420d03L, 0xf60a04bfL, + 0x2cb81290L, 0x24977c79L, 0x5679b072L, 0xbcaf89afL, + 0xde9a771fL, 0xd9930810L, 0xb38bae12L, 0xdccf3f2eL, + 0x5512721fL, 0x2e6b7124L, 0x501adde6L, 0x9f84cd87L, + 0x7a584718L, 0x7408da17L, 0xbc9f9abcL, 0xe94b7d8cL, + 0xec7aec3aL, 0xdb851dfaL, 0x63094366L, 0xc464c3d2L, + 0xef1c1847L, 0x3215d908L, 0xdd433b37L, 0x24c2ba16L, + 0x12a14d43L, 0x2a65c451L, 0x50940002L, 0x133ae4ddL, + 0x71dff89eL, 0x10314e55L, 0x81ac77d6L, 0x5f11199bL, + 0x043556f1L, 0xd7a3c76bL, 0x3c11183bL, 0x5924a509L, + 0xf28fe6edL, 0x97f1fbfaL, 0x9ebabf2cL, 0x1e153c6eL, + 0x86e34570L, 0xeae96fb1L, 0x860e5e0aL, 0x5a3e2ab3L, + 0x771fe71cL, 0x4e3d06faL, 0x2965dcb9L, 0x99e71d0fL, + 0x803e89d6L, 0x5266c825L, 0x2e4cc978L, 0x9c10b36aL, + 0xc6150ebaL, 0x94e2ea78L, 0xa5fc3c53L, 0x1e0a2df4L, + 0xf2f74ea7L, 0x361d2b3dL, 0x1939260fL, 0x19c27960L, + 0x5223a708L, 0xf71312b6L, 0xebadfe6eL, 0xeac31f66L, + 0xe3bc4595L, 0xa67bc883L, 0xb17f37d1L, 0x018cff28L, + 0xc332ddefL, 0xbe6c5aa5L, 0x65582185L, 0x68ab9802L, + 0xeecea50fL, 0xdb2f953bL, 0x2aef7dadL, 0x5b6e2f84L, + 0x1521b628L, 0x29076170L, 0xecdd4775L, 0x619f1510L, + 0x13cca830L, 0xeb61bd96L, 0x0334fe1eL, 0xaa0363cfL, + 0xb5735c90L, 0x4c70a239L, 0xd59e9e0bL, 0xcbaade14L, + 0xeecc86bcL, 0x60622ca7L, 0x9cab5cabL, 0xb2f3846eL, + 0x648b1eafL, 0x19bdf0caL, 0xa02369b9L, 0x655abb50L, + 0x40685a32L, 0x3c2ab4b3L, 0x319ee9d5L, 0xc021b8f7L, + 0x9b540b19L, 0x875fa099L, 0x95f7997eL, 0x623d7da8L, + 0xf837889aL, 0x97e32d77L, 0x11ed935fL, 0x16681281L, + 0x0e358829L, 0xc7e61fd6L, 0x96dedfa1L, 0x7858ba99L, + 0x57f584a5L, 0x1b227263L, 0x9b83c3ffL, 0x1ac24696L, + 0xcdb30aebL, 0x532e3054L, 0x8fd948e4L, 0x6dbc3128L, + 0x58ebf2efL, 0x34c6ffeaL, 0xfe28ed61L, 0xee7c3c73L, + 0x5d4a14d9L, 0xe864b7e3L, 0x42105d14L, 0x203e13e0L, + 0x45eee2b6L, 0xa3aaabeaL, 0xdb6c4f15L, 0xfacb4fd0L, + 0xc742f442L, 0xef6abbb5L, 0x654f3b1dL, 0x41cd2105L, + 0xd81e799eL, 0x86854dc7L, 0xe44b476aL, 0x3d816250L, + 0xcf62a1f2L, 0x5b8d2646L, 0xfc8883a0L, 0xc1c7b6a3L, + 0x7f1524c3L, 0x69cb7492L, 0x47848a0bL, 0x5692b285L, + 0x095bbf00L, 0xad19489dL, 0x1462b174L, 0x23820e00L, + 0x58428d2aL, 0x0c55f5eaL, 0x1dadf43eL, 0x233f7061L, + 0x3372f092L, 0x8d937e41L, 0xd65fecf1L, 0x6c223bdbL, + 0x7cde3759L, 0xcbee7460L, 0x4085f2a7L, 0xce77326eL, + 0xa6078084L, 0x19f8509eL, 0xe8efd855L, 0x61d99735L, + 0xa969a7aaL, 0xc50c06c2L, 0x5a04abfcL, 0x800bcadcL, + 0x9e447a2eL, 0xc3453484L, 0xfdd56705L, 0x0e1e9ec9L, + 0xdb73dbd3L, 0x105588cdL, 0x675fda79L, 0xe3674340L, + 0xc5c43465L, 0x713e38d8L, 0x3d28f89eL, 0xf16dff20L, + 0x153e21e7L, 0x8fb03d4aL, 0xe6e39f2bL, 0xdb83adf7L, + 0xe93d5a68L, 0x948140f7L, 0xf64c261cL, 0x94692934L, + 0x411520f7L, 0x7602d4f7L, 0xbcf46b2eL, 0xd4a20068L, + 0xd4082471L, 0x3320f46aL, 0x43b7d4b7L, 0x500061afL, + 0x1e39f62eL, 0x97244546L, 0x14214f74L, 0xbf8b8840L, + 0x4d95fc1dL, 0x96b591afL, 0x70f4ddd3L, 0x66a02f45L, + 0xbfbc09ecL, 0x03bd9785L, 0x7fac6dd0L, 0x31cb8504L, + 0x96eb27b3L, 0x55fd3941L, 0xda2547e6L, 0xabca0a9aL, + 0x28507825L, 0x530429f4L, 0x0a2c86daL, 0xe9b66dfbL, + 0x68dc1462L, 0xd7486900L, 0x680ec0a4L, 0x27a18deeL, + 0x4f3ffea2L, 0xe887ad8cL, 0xb58ce006L, 0x7af4d6b6L, + 0xaace1e7cL, 0xd3375fecL, 0xce78a399L, 0x406b2a42L, + 0x20fe9e35L, 0xd9f385b9L, 0xee39d7abL, 0x3b124e8bL, + 0x1dc9faf7L, 0x4b6d1856L, 0x26a36631L, 0xeae397b2L, + 0x3a6efa74L, 0xdd5b4332L, 0x6841e7f7L, 0xca7820fbL, + 0xfb0af54eL, 0xd8feb397L, 0x454056acL, 0xba489527L, + 0x55533a3aL, 0x20838d87L, 0xfe6ba9b7L, 0xd096954bL, + 0x55a867bcL, 0xa1159a58L, 0xcca92963L, 0x99e1db33L, + 0xa62a4a56L, 0x3f3125f9L, 0x5ef47e1cL, 0x9029317cL, + 0xfdf8e802L, 0x04272f70L, 0x80bb155cL, 0x05282ce3L, + 0x95c11548L, 0xe4c66d22L, 0x48c1133fL, 0xc70f86dcL, + 0x07f9c9eeL, 0x41041f0fL, 0x404779a4L, 0x5d886e17L, + 0x325f51ebL, 0xd59bc0d1L, 0xf2bcc18fL, 0x41113564L, + 0x257b7834L, 0x602a9c60L, 0xdff8e8a3L, 0x1f636c1bL, + 0x0e12b4c2L, 0x02e1329eL, 0xaf664fd1L, 0xcad18115L, + 0x6b2395e0L, 0x333e92e1L, 0x3b240b62L, 0xeebeb922L, + 0x85b2a20eL, 0xe6ba0d99L, 0xde720c8cL, 0x2da2f728L, + 0xd0127845L, 0x95b794fdL, 0x647d0862L, 0xe7ccf5f0L, + 0x5449a36fL, 0x877d48faL, 0xc39dfd27L, 0xf33e8d1eL, + 0x0a476341L, 0x992eff74L, 0x3a6f6eabL, 0xf4f8fd37L, + 0xa812dc60L, 0xa1ebddf8L, 0x991be14cL, 0xdb6e6b0dL, + 0xc67b5510L, 0x6d672c37L, 0x2765d43bL, 0xdcd0e804L, + 0xf1290dc7L, 0xcc00ffa3L, 0xb5390f92L, 0x690fed0bL, + 0x667b9ffbL, 0xcedb7d9cL, 0xa091cf0bL, 0xd9155ea3L, + 0xbb132f88L, 0x515bad24L, 0x7b9479bfL, 0x763bd6ebL, + 0x37392eb3L, 0xcc115979L, 0x8026e297L, 0xf42e312dL, + 0x6842ada7L, 0xc66a2b3bL, 0x12754cccL, 0x782ef11cL, + 0x6a124237L, 0xb79251e7L, 0x06a1bbe6L, 0x4bfb6350L, + 0x1a6b1018L, 0x11caedfaL, 0x3d25bdd8L, 0xe2e1c3c9L, + 0x44421659L, 0x0a121386L, 0xd90cec6eL, 0xd5abea2aL, + 0x64af674eL, 0xda86a85fL, 0xbebfe988L, 0x64e4c3feL, + 0x9dbc8057L, 0xf0f7c086L, 0x60787bf8L, 0x6003604dL, + 0xd1fd8346L, 0xf6381fb0L, 0x7745ae04L, 0xd736fcccL, + 0x83426b33L, 0xf01eab71L, 0xb0804187L, 0x3c005e5fL, + 0x77a057beL, 0xbde8ae24L, 0x55464299L, 0xbf582e61L, + 0x4e58f48fL, 0xf2ddfda2L, 0xf474ef38L, 0x8789bdc2L, + 0x5366f9c3L, 0xc8b38e74L, 0xb475f255L, 0x46fcd9b9L, + 0x7aeb2661L, 0x8b1ddf84L, 0x846a0e79L, 0x915f95e2L, + 0x466e598eL, 0x20b45770L, 0x8cd55591L, 0xc902de4cL, + 0xb90bace1L, 0xbb8205d0L, 0x11a86248L, 0x7574a99eL, + 0xb77f19b6L, 0xe0a9dc09L, 0x662d09a1L, 0xc4324633L, + 0xe85a1f02L, 0x09f0be8cL, 0x4a99a025L, 0x1d6efe10L, + 0x1ab93d1dL, 0x0ba5a4dfL, 0xa186f20fL, 0x2868f169L, + 0xdcb7da83L, 0x573906feL, 0xa1e2ce9bL, 0x4fcd7f52L, + 0x50115e01L, 0xa70683faL, 0xa002b5c4L, 0x0de6d027L, + 0x9af88c27L, 0x773f8641L, 0xc3604c06L, 0x61a806b5L, + 0xf0177a28L, 0xc0f586e0L, 0x006058aaL, 0x30dc7d62L, + 0x11e69ed7L, 0x2338ea63L, 0x53c2dd94L, 0xc2c21634L, + 0xbbcbee56L, 0x90bcb6deL, 0xebfc7da1L, 0xce591d76L, + 0x6f05e409L, 0x4b7c0188L, 0x39720a3dL, 0x7c927c24L, + 0x86e3725fL, 0x724d9db9L, 0x1ac15bb4L, 0xd39eb8fcL, + 0xed545578L, 0x08fca5b5L, 0xd83d7cd3L, 0x4dad0fc4L, + 0x1e50ef5eL, 0xb161e6f8L, 0xa28514d9L, 0x6c51133cL, + 0x6fd5c7e7L, 0x56e14ec4L, 0x362abfceL, 0xddc6c837L, + 0xd79a3234L, 0x92638212L, 0x670efa8eL, 0x406000e0L, + 0x3a39ce37L, 0xd3faf5cfL, 0xabc27737L, 0x5ac52d1bL, + 0x5cb0679eL, 0x4fa33742L, 0xd3822740L, 0x99bc9bbeL, + 0xd5118e9dL, 0xbf0f7315L, 0xd62d1c7eL, 0xc700c47bL, + 0xb78c1b6bL, 0x21a19045L, 0xb26eb1beL, 0x6a366eb4L, + 0x5748ab2fL, 0xbc946e79L, 0xc6a376d2L, 0x6549c2c8L, + 0x530ff8eeL, 0x468dde7dL, 0xd5730a1dL, 0x4cd04dc6L, + 0x2939bbdbL, 0xa9ba4650L, 0xac9526e8L, 0xbe5ee304L, + 0xa1fad5f0L, 0x6a2d519aL, 0x63ef8ce2L, 0x9a86ee22L, + 0xc089c2b8L, 0x43242ef6L, 0xa51e03aaL, 0x9cf2d0a4L, + 0x83c061baL, 0x9be96a4dL, 0x8fe51550L, 0xba645bd6L, + 0x2826a2f9L, 0xa73a3ae1L, 0x4ba99586L, 0xef5562e9L, + 0xc72fefd3L, 0xf752f7daL, 0x3f046f69L, 0x77fa0a59L, + 0x80e4a915L, 0x87b08601L, 0x9b09e6adL, 0x3b3ee593L, + 0xe990fd5aL, 0x9e34d797L, 0x2cf0b7d9L, 0x022b8b51L, + 0x96d5ac3aL, 0x017da67dL, 0xd1cf3ed6L, 0x7c7d2d28L, + 0x1f9f25cfL, 0xadf2b89bL, 0x5ad6b472L, 0x5a88f54cL, + 0xe029ac71L, 0xe019a5e6L, 0x47b0acfdL, 0xed93fa9bL, + 0xe8d3c48dL, 0x283b57ccL, 0xf8d56629L, 0x79132e28L, + 0x785f0191L, 0xed756055L, 0xf7960e44L, 0xe3d35e8cL, + 0x15056dd4L, 0x88f46dbaL, 0x03a16125L, 0x0564f0bdL, + 0xc3eb9e15L, 0x3c9057a2L, 0x97271aecL, 0xa93a072aL, + 0x1b3f6d9bL, 0x1e6321f5L, 0xf59c66fbL, 0x26dcf319L, + 0x7533d928L, 0xb155fdf5L, 0x03563482L, 0x8aba3cbbL, + 0x28517711L, 0xc20ad9f8L, 0xabcc5167L, 0xccad925fL, + 0x4de81751L, 0x3830dc8eL, 0x379d5862L, 0x9320f991L, + 0xea7a90c2L, 0xfb3e7bceL, 0x5121ce64L, 0x774fbe32L, + 0xa8b6e37eL, 0xc3293d46L, 0x48de5369L, 0x6413e680L, + 0xa2ae0810L, 0xdd6db224L, 0x69852dfdL, 0x09072166L, + 0xb39a460aL, 0x6445c0ddL, 0x586cdecfL, 0x1c20c8aeL, + 0x5bbef7ddL, 0x1b588d40L, 0xccd2017fL, 0x6bb4e3bbL, + 0xdda26a7eL, 0x3a59ff45L, 0x3e350a44L, 0xbcb4cdd5L, + 0x72eacea8L, 0xfa6484bbL, 0x8d6612aeL, 0xbf3c6f47L, + 0xd29be463L, 0x542f5d9eL, 0xaec2771bL, 0xf64e6370L, + 0x740e0d8dL, 0xe75b1357L, 0xf8721671L, 0xaf537d5dL, + 0x4040cb08L, 0x4eb4e2ccL, 0x34d2466aL, 0x0115af84L, + 0xe1b00428L, 0x95983a1dL, 0x06b89fb4L, 0xce6ea048L, + 0x6f3f3b82L, 0x3520ab82L, 0x011a1d4bL, 0x277227f8L, + 0x611560b1L, 0xe7933fdcL, 0xbb3a792bL, 0x344525bdL, + 0xa08839e1L, 0x51ce794bL, 0x2f32c9b7L, 0xa01fbac9L, + 0xe01cc87eL, 0xbcc7d1f6L, 0xcf0111c3L, 0xa1e8aac7L, + 0x1a908749L, 0xd44fbd9aL, 0xd0dadecbL, 0xd50ada38L, + 0x0339c32aL, 0xc6913667L, 0x8df9317cL, 0xe0b12b4fL, + 0xf79e59b7L, 0x43f5bb3aL, 0xf2d519ffL, 0x27d9459cL, + 0xbf97222cL, 0x15e6fc2aL, 0x0f91fc71L, 0x9b941525L, + 0xfae59361L, 0xceb69cebL, 0xc2a86459L, 0x12baa8d1L, + 0xb6c1075eL, 0xe3056a0cL, 0x10d25065L, 0xcb03a442L, + 0xe0ec6e0eL, 0x1698db3bL, 0x4c98a0beL, 0x3278e964L, + 0x9f1f9532L, 0xe0d392dfL, 0xd3a0342bL, 0x8971f21eL, + 0x1b0a7441L, 0x4ba3348cL, 0xc5be7120L, 0xc37632d8L, + 0xdf359f8dL, 0x9b992f2eL, 0xe60b6f47L, 0x0fe3f11dL, + 0xe54cda54L, 0x1edad891L, 0xce6279cfL, 0xcd3e7e6fL, + 0x1618b166L, 0xfd2c1d05L, 0x848fd2c5L, 0xf6fb2299L, + 0xf523f357L, 0xa6327623L, 0x93a83531L, 0x56cccd02L, + 0xacf08162L, 0x5a75ebb5L, 0x6e163697L, 0x88d273ccL, + 0xde966292L, 0x81b949d0L, 0x4c50901bL, 0x71c65614L, + 0xe6c6c7bdL, 0x327a140aL, 0x45e1d006L, 0xc3f27b9aL, + 0xc9aa53fdL, 0x62a80f00L, 0xbb25bfe2L, 0x35bdd2f6L, + 0x71126905L, 0xb2040222L, 0xb6cbcf7cL, 0xcd769c2bL, + 0x53113ec0L, 0x1640e3d3L, 0x38abbd60L, 0x2547adf0L, + 0xba38209cL, 0xf746ce76L, 0x77afa1c5L, 0x20756060L, + 0x85cbfe4eL, 0x8ae88dd8L, 0x7aaaf9b0L, 0x4cf9aa7eL, + 0x1948c25cL, 0x02fb8a8cL, 0x01c36ae4L, 0xd6ebe1f9L, + 0x90d4f869L, 0xa65cdea0L, 0x3f09252dL, 0xc208e69fL, + 0xb74e6132L, 0xce77e25bL, 0x578fdfe3L, 0x3ac372e6L, + } + }; + Index: usr.bin/ssh/bf_skey.c =================================================================== RCS file: bf_skey.c diff -N bf_skey.c --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsKvpna31367 Wed Dec 8 12:42:04 1999 @@ -0,0 +1,119 @@ +/* crypto/bf/bf_skey.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include "blowfish.h" +#include "bf_locl.h" +#include "bf_pi.h" + +void BF_set_key(key,len,data) +BF_KEY *key; +int len; +unsigned char *data; + { + int i; + BF_LONG *p,ri,in[2]; + unsigned char *d,*end; + + + memcpy((char *)key,(char *)&bf_init,sizeof(BF_KEY)); + p=key->P; + + if (len > ((BF_ROUNDS+2)*4)) len=(BF_ROUNDS+2)*4; + + d=data; + end= &(data[len]); + for (i=0; i<(BF_ROUNDS+2); i++) + { + ri= *(d++); + if (d >= end) d=data; + + ri<<=8; + ri|= *(d++); + if (d >= end) d=data; + + ri<<=8; + ri|= *(d++); + if (d >= end) d=data; + + ri<<=8; + ri|= *(d++); + if (d >= end) d=data; + + p[i]^=ri; + } + + in[0]=0L; + in[1]=0L; + for (i=0; i<(BF_ROUNDS+2); i+=2) + { + BF_encrypt(in,key); + p[i ]=in[0]; + p[i+1]=in[1]; + } + + p=key->S; + for (i=0; i<4*256; i+=2) + { + BF_encrypt(in,key); + p[i ]=in[0]; + p[i+1]=in[1]; + } + } + Index: usr.bin/ssh/blowfish.h =================================================================== RCS file: blowfish.h diff -N blowfish.h --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsHlbEx31367 Wed Dec 8 12:42:04 1999 @@ -0,0 +1,116 @@ +/* crypto/bf/blowfish.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_BLOWFISH_H +#define HEADER_BLOWFISH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BF_ENCRYPT 1 +#define BF_DECRYPT 0 + +/* If you make this 'unsigned int' the pointer variants will work on + * the Alpha, otherwise they will not. Strangly using the '8 byte' + * BF_LONG and the default 'non-pointer' inner loop is the best configuration + * for the Alpha */ +#define BF_LONG unsigned long + +#define BF_ROUNDS 16 +#define BF_BLOCK 8 + +typedef struct bf_key_st + { + BF_LONG P[BF_ROUNDS+2]; + BF_LONG S[4*256]; + } BF_KEY; + +#ifndef NOPROTO + +void BF_set_key(BF_KEY *key, int len, unsigned char *data); +void BF_ecb_encrypt(unsigned char *in,unsigned char *out,BF_KEY *key, + int enc); +void BF_encrypt(BF_LONG *data,BF_KEY *key); +void BF_decrypt(BF_LONG *data,BF_KEY *key); +void BF_cbc_encrypt(unsigned char *in, unsigned char *out, long length, + BF_KEY *ks, unsigned char *iv, int enc); +void BF_cfb64_encrypt(unsigned char *in, unsigned char *out, long length, + BF_KEY *schedule, unsigned char *ivec, int *num, int enc); +void BF_ofb64_encrypt(unsigned char *in, unsigned char *out, long length, + BF_KEY *schedule, unsigned char *ivec, int *num); +char *BF_options(void); + +#else + +void BF_set_key(); +void BF_ecb_encrypt(); +void BF_encrypt(); +void BF_decrypt(); +void BF_cbc_encrypt(); +void BF_cfb64_encrypt(); +void BF_ofb64_encrypt(); +char *BF_options(); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif Index: usr.bin/ssh/bufaux.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/bufaux.c,v retrieving revision 1.2 retrieving revision 1.7 diff -u -r1.2 -r1.7 --- usr.bin/ssh/bufaux.c 1999/09/28 04:45:36 1.2 +++ usr.bin/ssh/bufaux.c 1999/11/24 19:53:44 1.7 @@ -1,141 +1,158 @@ /* + * + * bufaux.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Wed Mar 29 02:24:47 1995 ylo + * + * Auxiliary functions for storing and retrieving various data types to/from + * Buffers. + * + */ -bufaux.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Wed Mar 29 02:24:47 1995 ylo - -Auxiliary functions for storing and retrieving various data types to/from -Buffers. - -*/ - #include "includes.h" -RCSID("$Id: bufaux.c,v 1.2 1999/09/28 04:45:36 provos Exp $"); +RCSID("$Id: bufaux.c,v 1.7 1999/11/24 19:53:44 markus Exp $"); #include "ssh.h" #include #include "bufaux.h" #include "xmalloc.h" #include "getput.h" - -/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed - by (bits+7)/8 bytes of binary data, msb first. */ +/* + * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed + * by (bits+7)/8 bytes of binary data, msb first. + */ void buffer_put_bignum(Buffer *buffer, BIGNUM *value) { - int bits = BN_num_bits(value); - int bin_size = (bits + 7) / 8; - char *buf = xmalloc(bin_size); - int oi; - char msg[2]; - - /* Get the value of in binary */ - oi = BN_bn2bin(value, buf); - assert(oi == bin_size); - - /* Store the number of bits in the buffer in two bytes, msb first. */ - PUT_16BIT(msg, bits); - buffer_append(buffer, msg, 2); - /* Store the binary data. */ - buffer_append(buffer, buf, oi); - /* Clear the temporary data. */ - memset(buf, 0, bin_size); - xfree(buf); -} - -/* Retrieves an BIGNUM from the buffer. */ - + int bits = BN_num_bits(value); + int bin_size = (bits + 7) / 8; + char *buf = xmalloc(bin_size); + int oi; + char msg[2]; + + /* Get the value of in binary */ + oi = BN_bn2bin(value, buf); + if (oi != bin_size) + fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d", + oi, bin_size); + + /* Store the number of bits in the buffer in two bytes, msb first. */ + PUT_16BIT(msg, bits); + buffer_append(buffer, msg, 2); + /* Store the binary data. */ + buffer_append(buffer, buf, oi); + + memset(buf, 0, bin_size); + xfree(buf); +} + +/* + * Retrieves an BIGNUM from the buffer. + */ int buffer_get_bignum(Buffer *buffer, BIGNUM *value) -{ - int bits, bytes; - unsigned char buf[2], *bin; - - /* Get the number for bits. */ - buffer_get(buffer, (char *)buf, 2); - bits = GET_16BIT(buf); - /* Compute the number of binary bytes that follow. */ - bytes = (bits + 7) / 8; - bin = xmalloc(bytes); - buffer_get(buffer, bin, bytes); - BN_bin2bn(bin, bytes, value); - xfree(bin); - - return 2 + bytes; -} - -/* Returns an integer from the buffer (4 bytes, msb first). */ - -unsigned int buffer_get_int(Buffer *buffer) -{ - unsigned char buf[4]; - buffer_get(buffer, (char *)buf, 4); - return GET_32BIT(buf); -} - -/* Stores an integer in the buffer in 4 bytes, msb first. */ - -void buffer_put_int(Buffer *buffer, unsigned int value) { - char buf[4]; - PUT_32BIT(buf, value); - buffer_append(buffer, buf, 4); -} - -/* Returns an arbitrary binary string from the buffer. The string cannot - be longer than 256k. The returned value points to memory allocated - with xmalloc; it is the responsibility of the calling function to free - the data. If length_ptr is non-NULL, the length of the returned data - will be stored there. A null character will be automatically appended - to the returned string, and is not counted in length. */ - -char *buffer_get_string(Buffer *buffer, unsigned int *length_ptr) -{ - unsigned int len; - char *value; - /* Get the length. */ - len = buffer_get_int(buffer); - if (len > 256*1024) - fatal("Received packet with bad string length %d", len); - /* Allocate space for the string. Add one byte for a null character. */ - value = xmalloc(len + 1); - /* Get the string. */ - buffer_get(buffer, value, len); - /* Append a null character to make processing easier. */ - value[len] = 0; - /* Optionally return the length of the string. */ - if (length_ptr) - *length_ptr = len; - return value; -} - -/* Stores and arbitrary binary string in the buffer. */ - -void buffer_put_string(Buffer *buffer, const void *buf, unsigned int len) -{ - buffer_put_int(buffer, len); - buffer_append(buffer, buf, len); -} - -/* Returns a character from the buffer (0 - 255). */ - -int buffer_get_char(Buffer *buffer) -{ - char ch; - buffer_get(buffer, &ch, 1); - return (unsigned char)ch; -} - -/* Stores a character in the buffer. */ + int bits, bytes; + unsigned char buf[2], *bin; -void buffer_put_char(Buffer *buffer, int value) + /* Get the number for bits. */ + buffer_get(buffer, (char *) buf, 2); + bits = GET_16BIT(buf); + /* Compute the number of binary bytes that follow. */ + bytes = (bits + 7) / 8; + if (buffer_len(buffer) < bytes) + fatal("buffer_get_bignum: input buffer too small"); + bin = buffer_ptr(buffer); + BN_bin2bn(bin, bytes, value); + buffer_consume(buffer, bytes); + + return 2 + bytes; +} + +/* + * Returns an integer from the buffer (4 bytes, msb first). + */ +unsigned int +buffer_get_int(Buffer *buffer) +{ + unsigned char buf[4]; + buffer_get(buffer, (char *) buf, 4); + return GET_32BIT(buf); +} + +/* + * Stores an integer in the buffer in 4 bytes, msb first. + */ +void +buffer_put_int(Buffer *buffer, unsigned int value) +{ + char buf[4]; + PUT_32BIT(buf, value); + buffer_append(buffer, buf, 4); +} + +/* + * Returns an arbitrary binary string from the buffer. The string cannot + * be longer than 256k. The returned value points to memory allocated + * with xmalloc; it is the responsibility of the calling function to free + * the data. If length_ptr is non-NULL, the length of the returned data + * will be stored there. A null character will be automatically appended + * to the returned string, and is not counted in length. + */ +char * +buffer_get_string(Buffer *buffer, unsigned int *length_ptr) +{ + unsigned int len; + char *value; + /* Get the length. */ + len = buffer_get_int(buffer); + if (len > 256 * 1024) + fatal("Received packet with bad string length %d", len); + /* Allocate space for the string. Add one byte for a null character. */ + value = xmalloc(len + 1); + /* Get the string. */ + buffer_get(buffer, value, len); + /* Append a null character to make processing easier. */ + value[len] = 0; + /* Optionally return the length of the string. */ + if (length_ptr) + *length_ptr = len; + return value; +} + +/* + * Stores and arbitrary binary string in the buffer. + */ +void +buffer_put_string(Buffer *buffer, const void *buf, unsigned int len) +{ + buffer_put_int(buffer, len); + buffer_append(buffer, buf, len); +} + +/* + * Returns a character from the buffer (0 - 255). + */ +int +buffer_get_char(Buffer *buffer) +{ + char ch; + buffer_get(buffer, &ch, 1); + return (unsigned char) ch; +} + +/* + * Stores a character in the buffer. + */ +void +buffer_put_char(Buffer *buffer, int value) { - char ch = value; - buffer_append(buffer, &ch, 1); + char ch = value; + buffer_append(buffer, &ch, 1); } Index: usr.bin/ssh/bufaux.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/bufaux.h,v retrieving revision 1.2 retrieving revision 1.4 diff -u -r1.2 -r1.4 --- usr.bin/ssh/bufaux.h 1999/09/28 04:45:36 1.2 +++ usr.bin/ssh/bufaux.h 1999/11/24 19:53:44 1.4 @@ -1,51 +1,55 @@ /* + * + * bufaux.h + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Wed Mar 29 02:18:23 1995 ylo + * + */ -bufaux.h +/* RCSID("$Id: bufaux.h,v 1.4 1999/11/24 19:53:44 markus Exp $"); */ -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Wed Mar 29 02:18:23 1995 ylo - -*/ - -/* RCSID("$Id: bufaux.h,v 1.2 1999/09/28 04:45:36 provos Exp $"); */ - #ifndef BUFAUX_H #define BUFAUX_H #include "buffer.h" -/* Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed - by (bits+7)/8 bytes of binary data, msb first. */ -void buffer_put_bignum(Buffer *buffer, BIGNUM *value); +/* + * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed + * by (bits+7)/8 bytes of binary data, msb first. + */ +void buffer_put_bignum(Buffer * buffer, BIGNUM * value); /* Retrieves an BIGNUM from the buffer. */ -int buffer_get_bignum(Buffer *buffer, BIGNUM *value); +int buffer_get_bignum(Buffer * buffer, BIGNUM * value); /* Returns an integer from the buffer (4 bytes, msb first). */ -unsigned int buffer_get_int(Buffer *buffer); +unsigned int buffer_get_int(Buffer * buffer); /* Stores an integer in the buffer in 4 bytes, msb first. */ -void buffer_put_int(Buffer *buffer, unsigned int value); +void buffer_put_int(Buffer * buffer, unsigned int value); /* Returns a character from the buffer (0 - 255). */ -int buffer_get_char(Buffer *buffer); +int buffer_get_char(Buffer * buffer); /* Stores a character in the buffer. */ -void buffer_put_char(Buffer *buffer, int value); +void buffer_put_char(Buffer * buffer, int value); -/* Returns an arbitrary binary string from the buffer. The string cannot - be longer than 256k. The returned value points to memory allocated - with xmalloc; it is the responsibility of the calling function to free - the data. If length_ptr is non-NULL, the length of the returned data - will be stored there. A null character will be automatically appended - to the returned string, and is not counted in length. */ -char *buffer_get_string(Buffer *buffer, unsigned int *length_ptr); +/* + * Returns an arbitrary binary string from the buffer. The string cannot be + * longer than 256k. The returned value points to memory allocated with + * xmalloc; it is the responsibility of the calling function to free the + * data. If length_ptr is non-NULL, the length of the returned data will be + * stored there. A null character will be automatically appended to the + * returned string, and is not counted in length. + */ +char *buffer_get_string(Buffer * buffer, unsigned int *length_ptr); /* Stores and arbitrary binary string in the buffer. */ -void buffer_put_string(Buffer *buffer, const void *buf, unsigned int len); +void buffer_put_string(Buffer * buffer, const void *buf, unsigned int len); -#endif /* BUFAUX_H */ +#endif /* BUFAUX_H */ Index: usr.bin/ssh/buffer.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/buffer.c,v retrieving revision 1.1 retrieving revision 1.4 diff -u -r1.1 -r1.4 --- usr.bin/ssh/buffer.c 1999/09/26 20:53:34 1.1 +++ usr.bin/ssh/buffer.c 1999/11/24 19:53:44 1.4 @@ -1,20 +1,20 @@ /* + * + * buffer.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Sat Mar 18 04:15:33 1995 ylo + * + * Functions for manipulating fifo buffers (that can grow if needed). + * + */ -buffer.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Sat Mar 18 04:15:33 1995 ylo - -Functions for manipulating fifo buffers (that can grow if needed). - -*/ - #include "includes.h" -RCSID("$Id: buffer.c,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); +RCSID("$Id: buffer.c,v 1.4 1999/11/24 19:53:44 markus Exp $"); #include "xmalloc.h" #include "buffer.h" @@ -22,129 +22,140 @@ /* Initializes the buffer structure. */ -void buffer_init(Buffer *buffer) +void +buffer_init(Buffer *buffer) { - buffer->alloc = 4096; - buffer->buf = xmalloc(buffer->alloc); - buffer->offset = 0; - buffer->end = 0; + buffer->alloc = 4096; + buffer->buf = xmalloc(buffer->alloc); + buffer->offset = 0; + buffer->end = 0; } /* Frees any memory used for the buffer. */ -void buffer_free(Buffer *buffer) +void +buffer_free(Buffer *buffer) { - memset(buffer->buf, 0, buffer->alloc); - xfree(buffer->buf); + memset(buffer->buf, 0, buffer->alloc); + xfree(buffer->buf); } -/* Clears any data from the buffer, making it empty. This does not actually - zero the memory. */ +/* + * Clears any data from the buffer, making it empty. This does not actually + * zero the memory. + */ -void buffer_clear(Buffer *buffer) +void +buffer_clear(Buffer *buffer) { - buffer->offset = 0; - buffer->end = 0; + buffer->offset = 0; + buffer->end = 0; } /* Appends data to the buffer, expanding it if necessary. */ -void buffer_append(Buffer *buffer, const char *data, unsigned int len) +void +buffer_append(Buffer *buffer, const char *data, unsigned int len) { - char *cp; - buffer_append_space(buffer, &cp, len); - memcpy(cp, data, len); -} - -/* Appends space to the buffer, expanding the buffer if necessary. - This does not actually copy the data into the buffer, but instead - returns a pointer to the allocated region. */ - -void buffer_append_space(Buffer *buffer, char **datap, unsigned int len) -{ - /* If the buffer is empty, start using it from the beginning. */ - if (buffer->offset == buffer->end) - { - buffer->offset = 0; - buffer->end = 0; - } - - restart: - /* If there is enough space to store all data, store it now. */ - if (buffer->end + len < buffer->alloc) - { - *datap = buffer->buf + buffer->end; - buffer->end += len; - return; - } - - /* If the buffer is quite empty, but all data is at the end, move the - data to the beginning and retry. */ - if (buffer->offset > buffer->alloc / 2) - { - memmove(buffer->buf, buffer->buf + buffer->offset, - buffer->end - buffer->offset); - buffer->end -= buffer->offset; - buffer->offset = 0; - goto restart; - } - - /* Increase the size of the buffer and retry. */ - buffer->alloc += len + 32768; - buffer->buf = xrealloc(buffer->buf, buffer->alloc); - goto restart; + char *cp; + buffer_append_space(buffer, &cp, len); + memcpy(cp, data, len); +} + +/* + * Appends space to the buffer, expanding the buffer if necessary. This does + * not actually copy the data into the buffer, but instead returns a pointer + * to the allocated region. + */ + +void +buffer_append_space(Buffer *buffer, char **datap, unsigned int len) +{ + /* If the buffer is empty, start using it from the beginning. */ + if (buffer->offset == buffer->end) { + buffer->offset = 0; + buffer->end = 0; + } +restart: + /* If there is enough space to store all data, store it now. */ + if (buffer->end + len < buffer->alloc) { + *datap = buffer->buf + buffer->end; + buffer->end += len; + return; + } + /* + * If the buffer is quite empty, but all data is at the end, move the + * data to the beginning and retry. + */ + if (buffer->offset > buffer->alloc / 2) { + memmove(buffer->buf, buffer->buf + buffer->offset, + buffer->end - buffer->offset); + buffer->end -= buffer->offset; + buffer->offset = 0; + goto restart; + } + /* Increase the size of the buffer and retry. */ + buffer->alloc += len + 32768; + buffer->buf = xrealloc(buffer->buf, buffer->alloc); + goto restart; } /* Returns the number of bytes of data in the buffer. */ -unsigned int buffer_len(Buffer *buffer) +unsigned int +buffer_len(Buffer *buffer) { - return buffer->end - buffer->offset; + return buffer->end - buffer->offset; } /* Gets data from the beginning of the buffer. */ -void buffer_get(Buffer *buffer, char *buf, unsigned int len) +void +buffer_get(Buffer *buffer, char *buf, unsigned int len) { - if (len > buffer->end - buffer->offset) - fatal("buffer_get trying to get more bytes than in buffer"); - memcpy(buf, buffer->buf + buffer->offset, len); - buffer->offset += len; + if (len > buffer->end - buffer->offset) + fatal("buffer_get trying to get more bytes than in buffer"); + memcpy(buf, buffer->buf + buffer->offset, len); + buffer->offset += len; } /* Consumes the given number of bytes from the beginning of the buffer. */ -void buffer_consume(Buffer *buffer, unsigned int bytes) +void +buffer_consume(Buffer *buffer, unsigned int bytes) { - if (bytes > buffer->end - buffer->offset) - fatal("buffer_get trying to get more bytes than in buffer"); - buffer->offset += bytes; -} + if (bytes > buffer->end - buffer->offset) + fatal("buffer_get trying to get more bytes than in buffer"); + buffer->offset += bytes; +} /* Consumes the given number of bytes from the end of the buffer. */ -void buffer_consume_end(Buffer *buffer, unsigned int bytes) +void +buffer_consume_end(Buffer *buffer, unsigned int bytes) { - if (bytes > buffer->end - buffer->offset) - fatal("buffer_get trying to get more bytes than in buffer"); - buffer->end -= bytes; -} + if (bytes > buffer->end - buffer->offset) + fatal("buffer_get trying to get more bytes than in buffer"); + buffer->end -= bytes; +} /* Returns a pointer to the first used byte in the buffer. */ -char *buffer_ptr(Buffer *buffer) +char * +buffer_ptr(Buffer *buffer) { - return buffer->buf + buffer->offset; + return buffer->buf + buffer->offset; } /* Dumps the contents of the buffer to stderr. */ -void buffer_dump(Buffer *buffer) +void +buffer_dump(Buffer *buffer) { - int i; - unsigned char *ucp = (unsigned char *)buffer->buf; - - for (i = buffer->offset; i < buffer->end; i++) - fprintf(stderr, " %02x", ucp[i]); - fprintf(stderr, "\n"); + int i; + unsigned char *ucp = (unsigned char *) buffer->buf; + + for (i = buffer->offset; i < buffer->end; i++) + fprintf(stderr, " %02x", ucp[i]); + fprintf(stderr, "\n"); } Index: usr.bin/ssh/buffer.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/buffer.h,v retrieving revision 1.1 retrieving revision 1.3 diff -u -r1.1 -r1.3 --- usr.bin/ssh/buffer.h 1999/09/26 20:53:34 1.1 +++ usr.bin/ssh/buffer.h 1999/11/24 19:53:44 1.3 @@ -1,66 +1,68 @@ /* + * + * buffer.h + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Sat Mar 18 04:12:25 1995 ylo + * + * Code for manipulating FIFO buffers. + * + */ -buffer.h +/* RCSID("$Id: buffer.h,v 1.3 1999/11/24 19:53:44 markus Exp $"); */ -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Sat Mar 18 04:12:25 1995 ylo - -Code for manipulating FIFO buffers. - -*/ - -/* RCSID("$Id: buffer.h,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); */ - #ifndef BUFFER_H #define BUFFER_H - -typedef struct -{ - char *buf; /* Buffer for data. */ - unsigned int alloc; /* Number of bytes allocated for data. */ - unsigned int offset; /* Offset of first byte containing data. */ - unsigned int end; /* Offset of last byte containing data. */ -} Buffer; +typedef struct { + char *buf; /* Buffer for data. */ + unsigned int alloc; /* Number of bytes allocated for data. */ + unsigned int offset; /* Offset of first byte containing data. */ + unsigned int end; /* Offset of last byte containing data. */ +} Buffer; /* Initializes the buffer structure. */ -void buffer_init(Buffer *buffer); +void buffer_init(Buffer * buffer); /* Frees any memory used for the buffer. */ -void buffer_free(Buffer *buffer); +void buffer_free(Buffer * buffer); /* Clears any data from the buffer, making it empty. This does not actually zero the memory. */ -void buffer_clear(Buffer *buffer); +void buffer_clear(Buffer * buffer); /* Appends data to the buffer, expanding it if necessary. */ -void buffer_append(Buffer *buffer, const char *data, unsigned int len); +void buffer_append(Buffer * buffer, const char *data, unsigned int len); -/* Appends space to the buffer, expanding the buffer if necessary. - This does not actually copy the data into the buffer, but instead - returns a pointer to the allocated region. */ -void buffer_append_space(Buffer *buffer, char **datap, unsigned int len); +/* + * Appends space to the buffer, expanding the buffer if necessary. This does + * not actually copy the data into the buffer, but instead returns a pointer + * to the allocated region. + */ +void buffer_append_space(Buffer * buffer, char **datap, unsigned int len); /* Returns the number of bytes of data in the buffer. */ -unsigned int buffer_len(Buffer *buffer); +unsigned int buffer_len(Buffer * buffer); /* Gets data from the beginning of the buffer. */ -void buffer_get(Buffer *buffer, char *buf, unsigned int len); +void buffer_get(Buffer * buffer, char *buf, unsigned int len); /* Consumes the given number of bytes from the beginning of the buffer. */ -void buffer_consume(Buffer *buffer, unsigned int bytes); +void buffer_consume(Buffer * buffer, unsigned int bytes); /* Consumes the given number of bytes from the end of the buffer. */ -void buffer_consume_end(Buffer *buffer, unsigned int bytes); +void buffer_consume_end(Buffer * buffer, unsigned int bytes); /* Returns a pointer to the first used byte in the buffer. */ -char *buffer_ptr(Buffer *buffer); +char *buffer_ptr(Buffer * buffer); -/* Dumps the contents of the buffer to stderr in hex. This intended for - debugging purposes only. */ -void buffer_dump(Buffer *buffer); +/* + * Dumps the contents of the buffer to stderr in hex. This intended for + * debugging purposes only. + */ +void buffer_dump(Buffer * buffer); -#endif /* BUFFER_H */ +#endif /* BUFFER_H */ Index: usr.bin/ssh/canohost.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/canohost.c,v retrieving revision 1.3 retrieving revision 1.8 diff -u -r1.3 -r1.8 --- usr.bin/ssh/canohost.c 1999/09/30 05:53:04 1.3 +++ usr.bin/ssh/canohost.c 1999/11/24 19:53:44 1.8 @@ -1,234 +1,243 @@ /* + * + * canohost.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Sun Jul 2 17:52:22 1995 ylo + * + * Functions for returning the canonical host name of the remote site. + * + */ -canohost.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Sun Jul 2 17:52:22 1995 ylo - -Functions for returning the canonical host name of the remote site. - -*/ - #include "includes.h" -RCSID("$Id: canohost.c,v 1.3 1999/09/30 05:53:04 deraadt Exp $"); +RCSID("$Id: canohost.c,v 1.8 1999/11/24 19:53:44 markus Exp $"); #include "packet.h" #include "xmalloc.h" #include "ssh.h" -/* Return the canonical name of the host at the other end of the socket. - The caller should free the returned string with xfree. */ +/* + * Return the canonical name of the host at the other end of the socket. The + * caller should free the returned string with xfree. + */ -char *get_remote_hostname(int socket) +char * +get_remote_hostname(int socket) { - struct sockaddr_in from; - int fromlen, i; - struct hostent *hp; - char name[MAXHOSTNAMELEN]; - - /* Get IP address of client. */ - fromlen = sizeof(from); - memset(&from, 0, sizeof(from)); - if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0) - { - error("getpeername failed: %.100s", strerror(errno)); - strlcpy(name, "UNKNOWN", sizeof name); - goto check_ip_options; - } - - /* Map the IP address to a host name. */ - hp = gethostbyaddr((char *)&from.sin_addr, sizeof(struct in_addr), - from.sin_family); - if (hp) - { - /* Got host name, find canonic host name. */ - if (strchr(hp->h_name, '.') != 0) - strlcpy(name, hp->h_name, sizeof(name)); - else if (hp->h_aliases != 0 - && hp->h_aliases[0] != 0 - && strchr(hp->h_aliases[0], '.') != 0) - strlcpy(name, hp->h_aliases[0], sizeof(name)); - else - strlcpy(name, hp->h_name, sizeof(name)); - - /* Convert it to all lowercase (which is expected by the rest of this - software). */ - for (i = 0; name[i]; i++) - if (isupper(name[i])) - name[i] = tolower(name[i]); - - /* Map it back to an IP address and check that the given address actually - is an address of this host. This is necessary because anyone with - access to a name server can define arbitrary names for an IP address. - Mapping from name to IP address can be trusted better (but can still - be fooled if the intruder has access to the name server of the - domain). */ - hp = gethostbyname(name); - if (!hp) - { - log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name); - strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); - goto check_ip_options; - } - /* Look for the address from the list of addresses. */ - for (i = 0; hp->h_addr_list[i]; i++) - if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr)) - == 0) - break; - /* If we reached the end of the list, the address was not there. */ - if (!hp->h_addr_list[i]) + struct sockaddr_in from; + int fromlen, i; + struct hostent *hp; + char name[MAXHOSTNAMELEN]; + + /* Get IP address of client. */ + fromlen = sizeof(from); + memset(&from, 0, sizeof(from)); + if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) { + debug("getpeername failed: %.100s", strerror(errno)); + fatal_cleanup(); + } + /* Map the IP address to a host name. */ + hp = gethostbyaddr((char *) &from.sin_addr, sizeof(struct in_addr), + from.sin_family); + if (hp) { + /* Got host name, find canonic host name. */ + if (strchr(hp->h_name, '.') != 0) + strlcpy(name, hp->h_name, sizeof(name)); + else if (hp->h_aliases != 0 + && hp->h_aliases[0] != 0 + && strchr(hp->h_aliases[0], '.') != 0) + strlcpy(name, hp->h_aliases[0], sizeof(name)); + else + strlcpy(name, hp->h_name, sizeof(name)); + + /* + * Convert it to all lowercase (which is expected by the rest + * of this software). + */ + for (i = 0; name[i]; i++) + if (isupper(name[i])) + name[i] = tolower(name[i]); + + /* + * Map it back to an IP address and check that the given + * address actually is an address of this host. This is + * necessary because anyone with access to a name server can + * define arbitrary names for an IP address. Mapping from + * name to IP address can be trusted better (but can still be + * fooled if the intruder has access to the name server of + * the domain). + */ + hp = gethostbyname(name); + if (!hp) { + log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name); + strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); + goto check_ip_options; + } + /* Look for the address from the list of addresses. */ + for (i = 0; hp->h_addr_list[i]; i++) + if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr)) + == 0) + break; + /* + * If we reached the end of the list, the address was not + * there. + */ + if (!hp->h_addr_list[i]) { + /* Address not found for the host name. */ + log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!", + inet_ntoa(from.sin_addr), name); + strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); + goto check_ip_options; + } + /* Address was found for the host name. We accept the host name. */ + } else { + /* Host name not found. Use ascii representation of the address. */ + strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); + log("Could not reverse map address %.100s.", name); + } + +check_ip_options: + + /* + * If IP options are supported, make sure there are none (log and + * disconnect them if any are found). Basically we are worried about + * source routing; it can be used to pretend you are somebody + * (ip-address) you are not. That itself may be "almost acceptable" + * under certain circumstances, but rhosts autentication is useless + * if source routing is accepted. Notice also that if we just dropped + * source routing here, the other side could use IP spoofing to do + * rest of the interaction and could still bypass security. So we + * exit here if we detect any IP options. + */ { - /* Address not found for the host name. */ - log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!", - inet_ntoa(from.sin_addr), name); - strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); - goto check_ip_options; - } - /* Address was found for the host name. We accept the host name. */ - } - else - { - /* Host name not found. Use ascii representation of the address. */ - strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); - log("Could not reverse map address %.100s.", name); - } - - check_ip_options: - - /* If IP options are supported, make sure there are none (log and clear - them if any are found). Basically we are worried about source routing; - it can be used to pretend you are somebody (ip-address) you are not. - That itself may be "almost acceptable" under certain circumstances, - but rhosts autentication is useless if source routing is accepted. - Notice also that if we just dropped source routing here, the other - side could use IP spoofing to do rest of the interaction and could still - bypass security. So we exit here if we detect any IP options. */ - { - unsigned char options[200], *ucp; - char text[1024], *cp; - int option_size, ipproto; - struct protoent *ip; - - if ((ip = getprotobyname("ip")) != NULL) - ipproto = ip->p_proto; - else - ipproto = IPPROTO_IP; - option_size = sizeof(options); - if (getsockopt(0, ipproto, IP_OPTIONS, (char *)options, - &option_size) >= 0 && option_size != 0) - { - cp = text; - /* Note: "text" buffer must be at least 3x as big as options. */ - for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3) - sprintf(cp, " %2.2x", *ucp); - log("Connection from %.100s with IP options:%.800s", - inet_ntoa(from.sin_addr), text); - packet_disconnect("Connection from %.100s with IP options:%.800s", - inet_ntoa(from.sin_addr), text); - } - } + unsigned char options[200], *ucp; + char text[1024], *cp; + int option_size, ipproto; + struct protoent *ip; + + if ((ip = getprotobyname("ip")) != NULL) + ipproto = ip->p_proto; + else + ipproto = IPPROTO_IP; + option_size = sizeof(options); + if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options, + &option_size) >= 0 && option_size != 0) { + cp = text; + /* Note: "text" buffer must be at least 3x as big as options. */ + for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3) + sprintf(cp, " %2.2x", *ucp); + log("Connection from %.100s with IP options:%.800s", + inet_ntoa(from.sin_addr), text); + packet_disconnect("Connection from %.100s with IP options:%.800s", + inet_ntoa(from.sin_addr), text); + } + } - return xstrdup(name); + return xstrdup(name); } static char *canonical_host_name = NULL; static char *canonical_host_ip = NULL; -/* Return the canonical name of the host in the other side of the current - connection. The host name is cached, so it is efficient to call this - several times. */ +/* + * Return the canonical name of the host in the other side of the current + * connection. The host name is cached, so it is efficient to call this + * several times. + */ -const char *get_canonical_hostname() +const char * +get_canonical_hostname() { - /* Check if we have previously retrieved this same name. */ - if (canonical_host_name != NULL) - return canonical_host_name; - - /* Get the real hostname if socket; otherwise return UNKNOWN. */ - if (packet_get_connection_in() == packet_get_connection_out()) - canonical_host_name = get_remote_hostname(packet_get_connection_in()); - else - canonical_host_name = xstrdup("UNKNOWN"); + /* Check if we have previously retrieved this same name. */ + if (canonical_host_name != NULL) + return canonical_host_name; + + /* Get the real hostname if socket; otherwise return UNKNOWN. */ + if (packet_get_connection_in() == packet_get_connection_out()) + canonical_host_name = get_remote_hostname(packet_get_connection_in()); + else + canonical_host_name = xstrdup("UNKNOWN"); - return canonical_host_name; + return canonical_host_name; } -/* Returns the IP-address of the remote host as a string. The returned - string need not be freed. */ +/* + * Returns the IP-address of the remote host as a string. The returned + * string need not be freed. + */ -const char *get_remote_ipaddr() +const char * +get_remote_ipaddr() { - struct sockaddr_in from; - int fromlen, socket; + struct sockaddr_in from; + int fromlen, socket; - /* Check if we have previously retrieved this same name. */ - if (canonical_host_ip != NULL) - return canonical_host_ip; - - /* If not a socket, return UNKNOWN. */ - if (packet_get_connection_in() != packet_get_connection_out()) - { - canonical_host_ip = xstrdup("UNKNOWN"); - return canonical_host_ip; - } - - /* Get client socket. */ - socket = packet_get_connection_in(); - - /* Get IP address of client. */ - fromlen = sizeof(from); - memset(&from, 0, sizeof(from)); - if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0) - { - error("getpeername failed: %.100s", strerror(errno)); - return NULL; - } + /* Check whether we have chached the name. */ + if (canonical_host_ip != NULL) + return canonical_host_ip; + + /* If not a socket, return UNKNOWN. */ + if (packet_get_connection_in() != packet_get_connection_out()) { + canonical_host_ip = xstrdup("UNKNOWN"); + return canonical_host_ip; + } + /* Get client socket. */ + socket = packet_get_connection_in(); - /* Get the IP address in ascii. */ - canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr)); + /* Get IP address of client. */ + fromlen = sizeof(from); + memset(&from, 0, sizeof(from)); + if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) { + debug("getpeername failed: %.100s", strerror(errno)); + fatal_cleanup(); + } + /* Get the IP address in ascii. */ + canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr)); - /* Return ip address string. */ - return canonical_host_ip; + /* Return ip address string. */ + return canonical_host_ip; } /* Returns the port of the peer of the socket. */ -int get_peer_port(int sock) +int +get_peer_port(int sock) { - struct sockaddr_in from; - int fromlen; + struct sockaddr_in from; + int fromlen; - /* Get IP address of client. */ - fromlen = sizeof(from); - memset(&from, 0, sizeof(from)); - if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) - { - error("getpeername failed: %.100s", strerror(errno)); - return 0; - } - - /* Return port number. */ - return ntohs(from.sin_port); + /* Get IP address of client. */ + fromlen = sizeof(from); + memset(&from, 0, sizeof(from)); + if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) { + debug("getpeername failed: %.100s", strerror(errno)); + fatal_cleanup(); + } + /* Return port number. */ + return ntohs(from.sin_port); } /* Returns the port number of the remote host. */ -int get_remote_port() +int +get_remote_port() { - int socket; + int socket; - /* If the connection is not a socket, return 65535. This is intentionally - chosen to be an unprivileged port number. */ - if (packet_get_connection_in() != packet_get_connection_out()) - return 65535; + /* + * If the connection is not a socket, return 65535. This is + * intentionally chosen to be an unprivileged port number. + */ + if (packet_get_connection_in() != packet_get_connection_out()) + return 65535; - /* Get client socket. */ - socket = packet_get_connection_in(); + /* Get client socket. */ + socket = packet_get_connection_in(); - /* Get and return the peer port number. */ - return get_peer_port(socket); + /* Get and return the peer port number. */ + return get_peer_port(socket); } Index: usr.bin/ssh/channels.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/channels.c,v retrieving revision 1.16 retrieving revision 1.32 diff -u -r1.16 -r1.32 --- usr.bin/ssh/channels.c 1999/10/17 16:56:08 1.16 +++ usr.bin/ssh/channels.c 1999/12/06 12:07:21 1.32 @@ -1,22 +1,22 @@ /* + * + * channels.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Fri Mar 24 16:35:24 1995 ylo + * + * This file contains functions for generic socket connection forwarding. + * There is also code for initiating connection forwarding for X11 connections, + * arbitrary tcp/ip connections, and the authentication agent connection. + * + */ -channels.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Fri Mar 24 16:35:24 1995 ylo - -This file contains functions for generic socket connection forwarding. -There is also code for initiating connection forwarding for X11 connections, -arbitrary tcp/ip connections, and the authentication agent connection. - -*/ - #include "includes.h" -RCSID("$Id: channels.c,v 1.16 1999/10/17 16:56:08 markus Exp $"); +RCSID("$Id: channels.c,v 1.32 1999/12/06 12:07:21 deraadt Exp $"); #include "ssh.h" #include "packet.h" @@ -24,6 +24,7 @@ #include "buffer.h" #include "authfd.h" #include "uidswap.h" +#include "readconf.h" #include "servconf.h" #include "channels.h" @@ -36,22 +37,28 @@ /* Max len of agent socket */ #define MAX_SOCKET_NAME 100 -/* Pointer to an array containing all allocated channels. The array is - dynamically extended as needed. */ +/* + * Pointer to an array containing all allocated channels. The array is + * dynamically extended as needed. + */ static Channel *channels = NULL; -/* Size of the channel array. All slots of the array must always be - initialized (at least the type field); unused slots are marked with - type SSH_CHANNEL_FREE. */ +/* + * Size of the channel array. All slots of the array must always be + * initialized (at least the type field); unused slots are marked with type + * SSH_CHANNEL_FREE. + */ static int channels_alloc = 0; -/* Maximum file descriptor value used in any of the channels. This is updated - in channel_allocate. */ +/* + * Maximum file descriptor value used in any of the channels. This is + * updated in channel_allocate. + */ static int channel_max_fd_value = 0; /* Name and directory of socket for authentication agent forwarding. */ static char *channel_forwarded_auth_socket_name = NULL; -static char *channel_forwarded_auth_socket_dir = NULL; +static char *channel_forwarded_auth_socket_dir = NULL; /* Saved X11 authentication protocol name. */ char *x11_saved_proto = NULL; @@ -60,28 +67,33 @@ char *x11_saved_data = NULL; unsigned int x11_saved_data_len = 0; -/* Fake X11 authentication data. This is what the server will be sending - us; we should replace any occurrences of this by the real data. */ +/* + * Fake X11 authentication data. This is what the server will be sending us; + * we should replace any occurrences of this by the real data. + */ char *x11_fake_data = NULL; unsigned int x11_fake_data_len; -/* Data structure for storing which hosts are permitted for forward requests. - The local sides of any remote forwards are stored in this array to prevent - a corrupt remote server from accessing arbitrary TCP/IP ports on our - local network (which might be behind a firewall). */ -typedef struct -{ - char *host; /* Host name. */ - int port; /* Port number. */ +/* + * Data structure for storing which hosts are permitted for forward requests. + * The local sides of any remote forwards are stored in this array to prevent + * a corrupt remote server from accessing arbitrary TCP/IP ports on our local + * network (which might be behind a firewall). + */ +typedef struct { + char *host; /* Host name. */ + u_short port; /* Port number. */ } ForwardPermission; /* List of all permitted host/port pairs to connect. */ static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; /* Number of permitted host/port pairs in the array. */ static int num_permitted_opens = 0; -/* If this is true, all opens are permitted. This is the case on the - server on which we have to trust the client anyway, and the user could - do anything after logging in anyway. */ +/* + * If this is true, all opens are permitted. This is the case on the server + * on which we have to trust the client anyway, and the user could do + * anything after logging in anyway. + */ static int all_opens_permitted = 0; /* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */ @@ -89,1050 +101,1075 @@ /* Sets specific protocol options. */ -void channel_set_options(int hostname_in_open) +void +channel_set_options(int hostname_in_open) { - have_hostname_in_open = hostname_in_open; + have_hostname_in_open = hostname_in_open; } -/* Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually - called by the server, because the user could connect to any port anyway, - and the server has no way to know but to trust the client anyway. */ - -void channel_permit_all_opens() -{ - all_opens_permitted = 1; -} - -/* Allocate a new channel object and set its type and socket. - This will cause remote_name to be freed. */ - -int channel_allocate(int type, int sock, char *remote_name) -{ - int i, old_channels; - - /* Update the maximum file descriptor value. */ - if (sock > channel_max_fd_value) - channel_max_fd_value = sock; - - /* Do initial allocation if this is the first call. */ - if (channels_alloc == 0) - { - channels_alloc = 10; - channels = xmalloc(channels_alloc * sizeof(Channel)); - for (i = 0; i < channels_alloc; i++) - channels[i].type = SSH_CHANNEL_FREE; - - /* Kludge: arrange a call to channel_stop_listening if we terminate - with fatal(). */ - fatal_add_cleanup((void (*)(void *))channel_stop_listening, NULL); - } - - /* Try to find a free slot where to put the new channel. */ - for (i = 0; i < channels_alloc; i++) - if (channels[i].type == SSH_CHANNEL_FREE) - { - /* Found a free slot. Initialize the fields and return its number. */ - buffer_init(&channels[i].input); - buffer_init(&channels[i].output); - channels[i].self = i; - channels[i].type = type; - channels[i].x11 = 0; - channels[i].sock = sock; - channels[i].remote_id = -1; - channels[i].remote_name = remote_name; - chan_init_iostates(&channels[i]); - return i; - } - - /* There are no free slots. Must expand the array. */ - old_channels = channels_alloc; - channels_alloc += 10; - channels = xrealloc(channels, channels_alloc * sizeof(Channel)); - for (i = old_channels; i < channels_alloc; i++) - channels[i].type = SSH_CHANNEL_FREE; - - /* We know that the next one after the old maximum channel number is now - available. Initialize and return its number. */ - buffer_init(&channels[old_channels].input); - buffer_init(&channels[old_channels].output); - channels[old_channels].self = old_channels; - channels[old_channels].type = type; - channels[old_channels].x11 = 0; - channels[old_channels].sock = sock; - channels[old_channels].remote_id = -1; - channels[old_channels].remote_name = remote_name; - chan_init_iostates(&channels[old_channels]); - return old_channels; +/* + * Permits opening to any host/port in SSH_MSG_PORT_OPEN. This is usually + * called by the server, because the user could connect to any port anyway, + * and the server has no way to know but to trust the client anyway. + */ + +void +channel_permit_all_opens() +{ + all_opens_permitted = 1; +} + +/* + * Allocate a new channel object and set its type and socket. This will cause + * remote_name to be freed. + */ + +int +channel_allocate(int type, int sock, char *remote_name) +{ + int i, found; + Channel *c; + + /* Update the maximum file descriptor value. */ + if (sock > channel_max_fd_value) + channel_max_fd_value = sock; + /* XXX set close-on-exec -markus */ + + /* Do initial allocation if this is the first call. */ + if (channels_alloc == 0) { + channels_alloc = 10; + channels = xmalloc(channels_alloc * sizeof(Channel)); + for (i = 0; i < channels_alloc; i++) + channels[i].type = SSH_CHANNEL_FREE; + /* + * Kludge: arrange a call to channel_stop_listening if we + * terminate with fatal(). + */ + fatal_add_cleanup((void (*) (void *)) channel_stop_listening, NULL); + } + /* Try to find a free slot where to put the new channel. */ + for (found = -1, i = 0; i < channels_alloc; i++) + if (channels[i].type == SSH_CHANNEL_FREE) { + /* Found a free slot. */ + found = i; + break; + } + if (found == -1) { + /* There are no free slots. Take last+1 slot and expand the array. */ + found = channels_alloc; + channels_alloc += 10; + debug("channel: expanding %d", channels_alloc); + channels = xrealloc(channels, channels_alloc * sizeof(Channel)); + for (i = found; i < channels_alloc; i++) + channels[i].type = SSH_CHANNEL_FREE; + } + /* Initialize and return new channel number. */ + c = &channels[found]; + buffer_init(&c->input); + buffer_init(&c->output); + chan_init_iostates(c); + c->self = found; + c->type = type; + c->sock = sock; + c->remote_id = -1; + c->remote_name = remote_name; + debug("channel %d: new [%s]", found, remote_name); + return found; } /* Free the channel and close its socket. */ -void channel_free(int channel) +void +channel_free(int channel) { - assert(channel >= 0 && channel < channels_alloc && - channels[channel].type != SSH_CHANNEL_FREE); - if(compat13) - shutdown(channels[channel].sock, SHUT_RDWR); - close(channels[channel].sock); - buffer_free(&channels[channel].input); - buffer_free(&channels[channel].output); - channels[channel].type = SSH_CHANNEL_FREE; - if (channels[channel].remote_name) - { - xfree(channels[channel].remote_name); - channels[channel].remote_name = NULL; - } -} - -/* This is called just before select() to add any bits relevant to - channels in the select bitmasks. */ - -void channel_prepare_select(fd_set *readset, fd_set *writeset) -{ - int i; - Channel *ch; - unsigned char *ucp; - unsigned int proto_len, data_len; - - for (i = 0; i < channels_alloc; i++) - { - ch = &channels[i]; - redo: - switch (ch->type) - { - case SSH_CHANNEL_X11_LISTENER: - case SSH_CHANNEL_PORT_LISTENER: - case SSH_CHANNEL_AUTH_SOCKET: - FD_SET(ch->sock, readset); - break; - - case SSH_CHANNEL_OPEN: - if(compat13){ - if (buffer_len(&ch->input) < 32768) - FD_SET(ch->sock, readset); - if (buffer_len(&ch->output) > 0) - FD_SET(ch->sock, writeset); - break; - } - /* test whether sockets are 'alive' for read/write */ - if (ch->istate == CHAN_INPUT_OPEN) - if (buffer_len(&ch->input) < 32768) - FD_SET(ch->sock, readset); - if (ch->ostate == CHAN_OUTPUT_OPEN || ch->ostate == CHAN_OUTPUT_WAIT_DRAIN){ - if (buffer_len(&ch->output) > 0){ - FD_SET(ch->sock, writeset); - }else if(ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) { - chan_obuf_empty(ch); - } - } - break; - - case SSH_CHANNEL_INPUT_DRAINING: - if (!compat13) - fatal("cannot happen: IN_DRAIN"); - if (buffer_len(&ch->input) == 0) - { - packet_start(SSH_MSG_CHANNEL_CLOSE); - packet_put_int(ch->remote_id); - packet_send(); - ch->type = SSH_CHANNEL_CLOSED; - debug("Closing channel %d after input drain.", i); - break; - } - break; - - case SSH_CHANNEL_OUTPUT_DRAINING: - if (!compat13) - fatal("cannot happen: OUT_DRAIN"); - if (buffer_len(&ch->output) == 0) - { - /* debug("Freeing channel %d after output drain.", i); */ - channel_free(i); - break; - } - FD_SET(ch->sock, writeset); - break; - - case SSH_CHANNEL_X11_OPEN: - /* This is a special state for X11 authentication spoofing. An - opened X11 connection (when authentication spoofing is being - done) remains in this state until the first packet has been - completely read. The authentication data in that packet is - then substituted by the real data if it matches the fake data, - and the channel is put into normal mode. */ - - /* Check if the fixed size part of the packet is in buffer. */ - if (buffer_len(&ch->output) < 12) - break; - - /* Parse the lengths of variable-length fields. */ - ucp = (unsigned char *)buffer_ptr(&ch->output); - if (ucp[0] == 0x42) - { /* Byte order MSB first. */ - proto_len = 256 * ucp[6] + ucp[7]; - data_len = 256 * ucp[8] + ucp[9]; - } - else - if (ucp[0] == 0x6c) - { /* Byte order LSB first. */ - proto_len = ucp[6] + 256 * ucp[7]; - data_len = ucp[8] + 256 * ucp[9]; - } - else - { - debug("Initial X11 packet contains bad byte order byte: 0x%x", - ucp[0]); - ch->type = SSH_CHANNEL_OPEN; - goto reject; - } - - /* Check if the whole packet is in buffer. */ - if (buffer_len(&ch->output) < - 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) - break; - - /* Check if authentication protocol matches. */ - if (proto_len != strlen(x11_saved_proto) || - memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) - { - debug("X11 connection uses different authentication protocol."); - ch->type = SSH_CHANNEL_OPEN; - goto reject; - } - - /* Check if authentication data matches our fake data. */ - if (data_len != x11_fake_data_len || - memcmp(ucp + 12 + ((proto_len + 3) & ~3), - x11_fake_data, x11_fake_data_len) != 0) - { - debug("X11 auth data does not match fake data."); - ch->type = SSH_CHANNEL_OPEN; - goto reject; - } - - /* Received authentication protocol and data match our fake data. - Substitute the fake data with real data. */ - assert(x11_fake_data_len == x11_saved_data_len); - memcpy(ucp + 12 + ((proto_len + 3) & ~3), - x11_saved_data, x11_saved_data_len); - - /* Start normal processing for the channel. */ - ch->type = SSH_CHANNEL_OPEN; - /* Enable X11 Problem FIX */ - ch->x11 = 1; - goto redo; - + if (channel < 0 || channel >= channels_alloc || + channels[channel].type == SSH_CHANNEL_FREE) + packet_disconnect("channel free: bad local channel %d", channel); + + if (compat13) + shutdown(channels[channel].sock, SHUT_RDWR); + close(channels[channel].sock); + buffer_free(&channels[channel].input); + buffer_free(&channels[channel].output); + channels[channel].type = SSH_CHANNEL_FREE; + if (channels[channel].remote_name) { + xfree(channels[channel].remote_name); + channels[channel].remote_name = NULL; + } +} + +/* + * This is called just before select() to add any bits relevant to channels + * in the select bitmasks. + */ + +void +channel_prepare_select(fd_set * readset, fd_set * writeset) +{ + int i; + Channel *ch; + unsigned char *ucp; + unsigned int proto_len, data_len; + + for (i = 0; i < channels_alloc; i++) { + ch = &channels[i]; +redo: + switch (ch->type) { + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_AUTH_SOCKET: + FD_SET(ch->sock, readset); + break; + + case SSH_CHANNEL_OPEN: + if (compat13) { + if (buffer_len(&ch->input) < packet_get_maxsize()) + FD_SET(ch->sock, readset); + if (buffer_len(&ch->output) > 0) + FD_SET(ch->sock, writeset); + break; + } + /* test whether sockets are 'alive' for read/write */ + if (ch->istate == CHAN_INPUT_OPEN) + if (buffer_len(&ch->input) < packet_get_maxsize()) + FD_SET(ch->sock, readset); + if (ch->ostate == CHAN_OUTPUT_OPEN || + ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) { + if (buffer_len(&ch->output) > 0) { + FD_SET(ch->sock, writeset); + } else if (ch->ostate == CHAN_OUTPUT_WAIT_DRAIN) { + chan_obuf_empty(ch); + } + } + break; + + case SSH_CHANNEL_INPUT_DRAINING: + if (!compat13) + fatal("cannot happen: IN_DRAIN"); + if (buffer_len(&ch->input) == 0) { + packet_start(SSH_MSG_CHANNEL_CLOSE); + packet_put_int(ch->remote_id); + packet_send(); + ch->type = SSH_CHANNEL_CLOSED; + debug("Closing channel %d after input drain.", i); + break; + } + break; + + case SSH_CHANNEL_OUTPUT_DRAINING: + if (!compat13) + fatal("cannot happen: OUT_DRAIN"); + if (buffer_len(&ch->output) == 0) { + channel_free(i); + break; + } + FD_SET(ch->sock, writeset); + break; + + case SSH_CHANNEL_X11_OPEN: + /* + * This is a special state for X11 authentication + * spoofing. An opened X11 connection (when + * authentication spoofing is being done) remains in + * this state until the first packet has been + * completely read. The authentication data in that + * packet is then substituted by the real data if it + * matches the fake data, and the channel is put into + * normal mode. + */ + /* Check if the fixed size part of the packet is in buffer. */ + if (buffer_len(&ch->output) < 12) + break; + + /* Parse the lengths of variable-length fields. */ + ucp = (unsigned char *) buffer_ptr(&ch->output); + if (ucp[0] == 0x42) { /* Byte order MSB first. */ + proto_len = 256 * ucp[6] + ucp[7]; + data_len = 256 * ucp[8] + ucp[9]; + } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */ + proto_len = ucp[6] + 256 * ucp[7]; + data_len = ucp[8] + 256 * ucp[9]; + } else { + debug("Initial X11 packet contains bad byte order byte: 0x%x", + ucp[0]); + ch->type = SSH_CHANNEL_OPEN; + goto reject; + } + + /* Check if the whole packet is in buffer. */ + if (buffer_len(&ch->output) < + 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) + break; + + /* Check if authentication protocol matches. */ + if (proto_len != strlen(x11_saved_proto) || + memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { + debug("X11 connection uses different authentication protocol."); + ch->type = SSH_CHANNEL_OPEN; + goto reject; + } + /* Check if authentication data matches our fake data. */ + if (data_len != x11_fake_data_len || + memcmp(ucp + 12 + ((proto_len + 3) & ~3), + x11_fake_data, x11_fake_data_len) != 0) { + debug("X11 auth data does not match fake data."); + ch->type = SSH_CHANNEL_OPEN; + goto reject; + } + /* Check fake data length */ + if (x11_fake_data_len != x11_saved_data_len) { + error("X11 fake_data_len %d != saved_data_len %d", + x11_fake_data_len, x11_saved_data_len); + ch->type = SSH_CHANNEL_OPEN; + goto reject; + } + /* + * Received authentication protocol and data match + * our fake data. Substitute the fake data with real + * data. + */ + memcpy(ucp + 12 + ((proto_len + 3) & ~3), + x11_saved_data, x11_saved_data_len); + + /* Start normal processing for the channel. */ + ch->type = SSH_CHANNEL_OPEN; + goto redo; + reject: - /* We have received an X11 connection that has bad authentication - information. */ - log("X11 connection rejected because of wrong authentication.\r\n"); - buffer_clear(&ch->input); - buffer_clear(&ch->output); - if (compat13) { - close(ch->sock); - ch->sock = -1; - ch->type = SSH_CHANNEL_CLOSED; - packet_start(SSH_MSG_CHANNEL_CLOSE); - packet_put_int(ch->remote_id); - packet_send(); - }else{ - debug("X11 rejected %d 0x%x 0x%x", ch->self, ch->istate, ch->ostate); - chan_read_failed(ch); - chan_write_failed(ch); - debug("X11 rejected %d 0x%x 0x%x", ch->self, ch->istate, ch->ostate); - } - break; - - case SSH_CHANNEL_FREE: - default: - continue; - } - } -} - -/* After select, perform any appropriate operations for channels which - have events pending. */ - -void channel_after_select(fd_set *readset, fd_set *writeset) -{ - struct sockaddr addr; - int addrlen, newsock, i, newch, len; - Channel *ch; - char buf[16384], *remote_hostname; - - /* Loop over all channels... */ - for (i = 0; i < channels_alloc; i++) - { - ch = &channels[i]; - switch (ch->type) - { - case SSH_CHANNEL_X11_LISTENER: - /* This is our fake X11 server socket. */ - if (FD_ISSET(ch->sock, readset)) - { - debug("X11 connection requested."); - addrlen = sizeof(addr); - newsock = accept(ch->sock, &addr, &addrlen); - if (newsock < 0) - { - error("accept: %.100s", strerror(errno)); - break; - } - remote_hostname = get_remote_hostname(newsock); - snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", - remote_hostname, get_peer_port(newsock)); - xfree(remote_hostname); - newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, - xstrdup(buf)); - packet_start(SSH_SMSG_X11_OPEN); - packet_put_int(newch); - if (have_hostname_in_open) - packet_put_string(buf, strlen(buf)); - packet_send(); - } - break; - - case SSH_CHANNEL_PORT_LISTENER: - /* This socket is listening for connections to a forwarded TCP/IP - port. */ - if (FD_ISSET(ch->sock, readset)) - { - debug("Connection to port %d forwarding to %.100s:%d requested.", - ch->listening_port, ch->path, ch->host_port); - addrlen = sizeof(addr); - newsock = accept(ch->sock, &addr, &addrlen); - if (newsock < 0) - { - error("accept: %.100s", strerror(errno)); - break; + /* + * We have received an X11 connection that has bad + * authentication information. + */ + log("X11 connection rejected because of wrong authentication.\r\n"); + buffer_clear(&ch->input); + buffer_clear(&ch->output); + if (compat13) { + close(ch->sock); + ch->sock = -1; + ch->type = SSH_CHANNEL_CLOSED; + packet_start(SSH_MSG_CHANNEL_CLOSE); + packet_put_int(ch->remote_id); + packet_send(); + } else { + debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); + chan_read_failed(ch); + chan_write_failed(ch); + debug("X11 rejected %d i%d/o%d", ch->self, ch->istate, ch->ostate); + } + break; + + case SSH_CHANNEL_FREE: + default: + continue; } - remote_hostname = get_remote_hostname(newsock); - snprintf(buf, sizeof buf, "port %d, connection from %.200s port %d", - ch->listening_port, remote_hostname, - get_peer_port(newsock)); - xfree(remote_hostname); - newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, - xstrdup(buf)); - packet_start(SSH_MSG_PORT_OPEN); - packet_put_int(newch); - packet_put_string(ch->path, strlen(ch->path)); - packet_put_int(ch->host_port); - if (have_hostname_in_open) - packet_put_string(buf, strlen(buf)); - packet_send(); - } - break; - - case SSH_CHANNEL_AUTH_SOCKET: - /* This is the authentication agent socket listening for connections - from clients. */ - if (FD_ISSET(ch->sock, readset)) - { - int nchan; - len = sizeof(addr); - newsock = accept(ch->sock, &addr, &len); - if (newsock < 0) - { - error("accept from auth socket: %.100s", strerror(errno)); - break; - } + } +} - nchan = channel_allocate(SSH_CHANNEL_OPENING, newsock, - xstrdup("accepted auth socket")); - packet_start(SSH_SMSG_AGENT_OPEN); - packet_put_int(nchan); - packet_send(); - } - break; - - case SSH_CHANNEL_OPEN: - /* This is an open two-way communication channel. It is not of - interest to us at this point what kind of data is being - transmitted. */ - - /* Read available incoming data and append it to buffer; - shutdown socket, if read or write failes */ - if (FD_ISSET(ch->sock, readset)) - { - len = read(ch->sock, buf, sizeof(buf)); - if (len <= 0) - { - if (compat13) { - buffer_consume(&ch->output, buffer_len(&ch->output)); - ch->type = SSH_CHANNEL_INPUT_DRAINING; - debug("Channel %d status set to input draining.", i); - }else{ - chan_read_failed(ch); - } - break; +/* + * After select, perform any appropriate operations for channels which have + * events pending. + */ + +void +channel_after_select(fd_set * readset, fd_set * writeset) +{ + struct sockaddr addr; + int addrlen, newsock, i, newch, len; + Channel *ch; + char buf[16384], *remote_hostname; + + /* Loop over all channels... */ + for (i = 0; i < channels_alloc; i++) { + ch = &channels[i]; + switch (ch->type) { + case SSH_CHANNEL_X11_LISTENER: + /* This is our fake X11 server socket. */ + if (FD_ISSET(ch->sock, readset)) { + debug("X11 connection requested."); + addrlen = sizeof(addr); + newsock = accept(ch->sock, &addr, &addrlen); + if (newsock < 0) { + error("accept: %.100s", strerror(errno)); + break; + } + remote_hostname = get_remote_hostname(newsock); + snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", + remote_hostname, get_peer_port(newsock)); + xfree(remote_hostname); + newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, + xstrdup(buf)); + packet_start(SSH_SMSG_X11_OPEN); + packet_put_int(newch); + if (have_hostname_in_open) + packet_put_string(buf, strlen(buf)); + packet_send(); + } + break; + + case SSH_CHANNEL_PORT_LISTENER: + /* + * This socket is listening for connections to a + * forwarded TCP/IP port. + */ + if (FD_ISSET(ch->sock, readset)) { + debug("Connection to port %d forwarding to %.100s:%d requested.", + ch->listening_port, ch->path, ch->host_port); + addrlen = sizeof(addr); + newsock = accept(ch->sock, &addr, &addrlen); + if (newsock < 0) { + error("accept: %.100s", strerror(errno)); + break; + } + remote_hostname = get_remote_hostname(newsock); + snprintf(buf, sizeof buf, "listen port %d:%.100s:%d, connect from %.200s:%d", + ch->listening_port, ch->path, ch->host_port, + remote_hostname, get_peer_port(newsock)); + xfree(remote_hostname); + newch = channel_allocate(SSH_CHANNEL_OPENING, newsock, + xstrdup(buf)); + packet_start(SSH_MSG_PORT_OPEN); + packet_put_int(newch); + packet_put_string(ch->path, strlen(ch->path)); + packet_put_int(ch->host_port); + if (have_hostname_in_open) + packet_put_string(buf, strlen(buf)); + packet_send(); + } + break; + + case SSH_CHANNEL_AUTH_SOCKET: + /* + * This is the authentication agent socket listening + * for connections from clients. + */ + if (FD_ISSET(ch->sock, readset)) { + int nchan; + len = sizeof(addr); + newsock = accept(ch->sock, &addr, &len); + if (newsock < 0) { + error("accept from auth socket: %.100s", strerror(errno)); + break; + } + nchan = channel_allocate(SSH_CHANNEL_OPENING, newsock, + xstrdup("accepted auth socket")); + packet_start(SSH_SMSG_AGENT_OPEN); + packet_put_int(nchan); + packet_send(); + } + break; + + case SSH_CHANNEL_OPEN: + /* + * This is an open two-way communication channel. It + * is not of interest to us at this point what kind + * of data is being transmitted. + */ + + /* + * Read available incoming data and append it to + * buffer; shutdown socket, if read or write failes + */ + if (FD_ISSET(ch->sock, readset)) { + len = read(ch->sock, buf, sizeof(buf)); + if (len <= 0) { + if (compat13) { + buffer_consume(&ch->output, buffer_len(&ch->output)); + ch->type = SSH_CHANNEL_INPUT_DRAINING; + debug("Channel %d status set to input draining.", i); + } else { + chan_read_failed(ch); + } + break; + } + buffer_append(&ch->input, buf, len); + } + /* Send buffered output data to the socket. */ + if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) { + len = write(ch->sock, buffer_ptr(&ch->output), + buffer_len(&ch->output)); + if (len <= 0) { + if (compat13) { + buffer_consume(&ch->output, buffer_len(&ch->output)); + debug("Channel %d status set to input draining.", i); + ch->type = SSH_CHANNEL_INPUT_DRAINING; + } else { + chan_write_failed(ch); + } + break; + } + buffer_consume(&ch->output, len); + } + break; + + case SSH_CHANNEL_OUTPUT_DRAINING: + if (!compat13) + fatal("cannot happen: OUT_DRAIN"); + /* Send buffered output data to the socket. */ + if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) { + len = write(ch->sock, buffer_ptr(&ch->output), + buffer_len(&ch->output)); + if (len <= 0) + buffer_consume(&ch->output, buffer_len(&ch->output)); + else + buffer_consume(&ch->output, len); + } + break; + + case SSH_CHANNEL_X11_OPEN: + case SSH_CHANNEL_FREE: + default: + continue; } - buffer_append(&ch->input, buf, len); - } - /* Send buffered output data to the socket. */ - if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) - { - len = write(ch->sock, buffer_ptr(&ch->output), - buffer_len(&ch->output)); - if (len <= 0) - { - if (compat13) { - buffer_consume(&ch->output, buffer_len(&ch->output)); - debug("Channel %d status set to input draining.", i); - ch->type = SSH_CHANNEL_INPUT_DRAINING; - }else{ - chan_write_failed(ch); - } - break; - } - buffer_consume(&ch->output, len); - } - break; - - case SSH_CHANNEL_OUTPUT_DRAINING: - if (!compat13) - fatal("cannot happen: OUT_DRAIN"); - /* Send buffered output data to the socket. */ - if (FD_ISSET(ch->sock, writeset) && buffer_len(&ch->output) > 0) - { - len = write(ch->sock, buffer_ptr(&ch->output), - buffer_len(&ch->output)); - if (len <= 0) - buffer_consume(&ch->output, buffer_len(&ch->output)); - else - buffer_consume(&ch->output, len); - } - break; - - case SSH_CHANNEL_X11_OPEN: - case SSH_CHANNEL_FREE: - default: - continue; } - } } /* If there is data to send to the connection, send some of it now. */ -void channel_output_poll() +void +channel_output_poll() { - int len, i; - Channel *ch; + int len, i; + Channel *ch; + + for (i = 0; i < channels_alloc; i++) { + ch = &channels[i]; + /* We are only interested in channels that can have buffered incoming data. */ + if (ch->type != SSH_CHANNEL_OPEN && + ch->type != SSH_CHANNEL_INPUT_DRAINING) + continue; + + /* Get the amount of buffered data for this channel. */ + len = buffer_len(&ch->input); + if (len > 0) { + /* Send some data for the other side over the secure connection. */ + if (packet_is_interactive()) { + if (len > 1024) + len = 512; + } else { + /* Keep the packets at reasonable size. */ + if (len > 16384) + len = 16384; + } + packet_start(SSH_MSG_CHANNEL_DATA); + packet_put_int(ch->remote_id); + packet_put_string(buffer_ptr(&ch->input), len); + packet_send(); + buffer_consume(&ch->input, len); + } else if (ch->istate == CHAN_INPUT_WAIT_DRAIN) { + if (compat13) + fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); + /* + * input-buffer is empty and read-socket shutdown: + * tell peer, that we will not send more data: send IEOF + */ + chan_ibuf_empty(ch); + } + } +} - for (i = 0; i < channels_alloc; i++) - { - ch = &channels[i]; - /* We are only interested in channels that can have buffered incoming - data. */ - if (ch->type != SSH_CHANNEL_OPEN && - ch->type != SSH_CHANNEL_INPUT_DRAINING) - continue; - - /* Get the amount of buffered data for this channel. */ - len = buffer_len(&ch->input); - if (len > 0) - { - /* Send some data for the other side over the secure connection. */ - if (packet_is_interactive()) - { - if (len > 1024) - len = 512; - } - else - { - if (len > 16384) - len = 16384; /* Keep the packets at reasonable size. */ - } - packet_start(SSH_MSG_CHANNEL_DATA); - packet_put_int(ch->remote_id); - packet_put_string(buffer_ptr(&ch->input), len); - packet_send(); - buffer_consume(&ch->input, len); - } - else if(ch->istate == CHAN_INPUT_WAIT_DRAIN) - { - if (compat13) - fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); - /* input-buffer is empty and read-socket shutdown: - tell peer, that we will not send more data: send IEOF */ - chan_ibuf_empty(ch); - } - } -} - -/* This is called when a packet of type CHANNEL_DATA has just been received. - The message type has already been consumed, but channel number and data - is still there. */ - -void channel_input_data(int payload_len) -{ - int channel; - char *data; - unsigned int data_len; - - /* Get the channel number and verify it. */ - channel = packet_get_int(); - if (channel < 0 || channel >= channels_alloc || - channels[channel].type == SSH_CHANNEL_FREE) - packet_disconnect("Received data for nonexistent channel %d.", channel); - - /* Ignore any data for non-open channels (might happen on close) */ - if (channels[channel].type != SSH_CHANNEL_OPEN && - channels[channel].type != SSH_CHANNEL_X11_OPEN) - return; - - /* Get the data. */ - data = packet_get_string(&data_len); - packet_integrity_check(payload_len, 4 + 4+data_len, SSH_MSG_CHANNEL_DATA); - buffer_append(&channels[channel].output, data, data_len); - xfree(data); -} - -/* Returns true if no channel has too much buffered data, and false if - one or more channel is overfull. */ - -int channel_not_very_much_buffered_data() -{ - unsigned int i; - Channel *ch; - - for (i = 0; i < channels_alloc; i++) - { - ch = &channels[i]; - switch (ch->type) - { - case SSH_CHANNEL_X11_LISTENER: - case SSH_CHANNEL_PORT_LISTENER: - case SSH_CHANNEL_AUTH_SOCKET: - continue; - case SSH_CHANNEL_OPEN: - if (buffer_len(&ch->input) > 32768) - return 0; - if (buffer_len(&ch->output) > 32768) - return 0; - continue; - case SSH_CHANNEL_INPUT_DRAINING: - case SSH_CHANNEL_OUTPUT_DRAINING: - case SSH_CHANNEL_X11_OPEN: - case SSH_CHANNEL_FREE: - default: - continue; +/* + * This is called when a packet of type CHANNEL_DATA has just been received. + * The message type has already been consumed, but channel number and data is + * still there. + */ + +void +channel_input_data(int payload_len) +{ + int channel; + char *data; + unsigned int data_len; + + /* Get the channel number and verify it. */ + channel = packet_get_int(); + if (channel < 0 || channel >= channels_alloc || + channels[channel].type == SSH_CHANNEL_FREE) + packet_disconnect("Received data for nonexistent channel %d.", channel); + + /* Ignore any data for non-open channels (might happen on close) */ + if (channels[channel].type != SSH_CHANNEL_OPEN && + channels[channel].type != SSH_CHANNEL_X11_OPEN) + return; + + /* Get the data. */ + data = packet_get_string(&data_len); + packet_integrity_check(payload_len, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA); + buffer_append(&channels[channel].output, data, data_len); + xfree(data); +} + +/* + * Returns true if no channel has too much buffered data, and false if one or + * more channel is overfull. + */ + +int +channel_not_very_much_buffered_data() +{ + unsigned int i; + Channel *ch; + + for (i = 0; i < channels_alloc; i++) { + ch = &channels[i]; + switch (ch->type) { + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_AUTH_SOCKET: + continue; + case SSH_CHANNEL_OPEN: + if (buffer_len(&ch->input) > packet_get_maxsize()) + return 0; + if (buffer_len(&ch->output) > packet_get_maxsize()) + return 0; + continue; + case SSH_CHANNEL_INPUT_DRAINING: + case SSH_CHANNEL_OUTPUT_DRAINING: + case SSH_CHANNEL_X11_OPEN: + case SSH_CHANNEL_FREE: + default: + continue; + } } - } - return 1; + return 1; } /* This is called after receiving CHANNEL_CLOSE/IEOF. */ -void channel_input_close() +void +channel_input_close() { - int channel; + int channel; + + /* Get the channel number and verify it. */ + channel = packet_get_int(); + if (channel < 0 || channel >= channels_alloc || + channels[channel].type == SSH_CHANNEL_FREE) + packet_disconnect("Received data for nonexistent channel %d.", channel); + + if (!compat13) { + /* proto version 1.5 overloads CLOSE with IEOF */ + chan_rcvd_ieof(&channels[channel]); + return; + } - /* Get the channel number and verify it. */ - channel = packet_get_int(); - if (channel < 0 || channel >= channels_alloc || - channels[channel].type == SSH_CHANNEL_FREE) - packet_disconnect("Received data for nonexistent channel %d.", channel); - - if(!compat13){ - /* proto version 1.5 overloads CLOSE with IEOF */ - chan_rcvd_ieof(&channels[channel]); - return; - } - - /* Send a confirmation that we have closed the channel and no more data is - coming for it. */ - packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); - packet_put_int(channels[channel].remote_id); - packet_send(); - - /* If the channel is in closed state, we have sent a close request, and - the other side will eventually respond with a confirmation. Thus, - we cannot free the channel here, because then there would be no-one to - receive the confirmation. The channel gets freed when the confirmation - arrives. */ - if (channels[channel].type != SSH_CHANNEL_CLOSED) - { - /* Not a closed channel - mark it as draining, which will cause it to - be freed later. */ - buffer_consume(&channels[channel].input, - buffer_len(&channels[channel].input)); - channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING; - /* debug("Setting status to output draining; output len = %d", - buffer_len(&channels[channel].output)); */ - } + /* + * Send a confirmation that we have closed the channel and no more + * data is coming for it. + */ + packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); + packet_put_int(channels[channel].remote_id); + packet_send(); + + /* + * If the channel is in closed state, we have sent a close request, + * and the other side will eventually respond with a confirmation. + * Thus, we cannot free the channel here, because then there would be + * no-one to receive the confirmation. The channel gets freed when + * the confirmation arrives. + */ + if (channels[channel].type != SSH_CHANNEL_CLOSED) { + /* + * Not a closed channel - mark it as draining, which will + * cause it to be freed later. + */ + buffer_consume(&channels[channel].input, + buffer_len(&channels[channel].input)); + channels[channel].type = SSH_CHANNEL_OUTPUT_DRAINING; + } } /* This is called after receiving CHANNEL_CLOSE_CONFIRMATION/OCLOSE. */ -void channel_input_close_confirmation() +void +channel_input_close_confirmation() { - int channel; + int channel; - /* Get the channel number and verify it. */ - channel = packet_get_int(); - if (channel < 0 || channel >= channels_alloc) - packet_disconnect("Received close confirmation for out-of-range channel %d.", - channel); - - if(!compat13){ - /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ - chan_rcvd_oclose(&channels[channel]); - return; - } - - if (channels[channel].type != SSH_CHANNEL_CLOSED) - packet_disconnect("Received close confirmation for non-closed channel %d (type %d).", - channel, channels[channel].type); + /* Get the channel number and verify it. */ + channel = packet_get_int(); + if (channel < 0 || channel >= channels_alloc) + packet_disconnect("Received close confirmation for out-of-range channel %d.", + channel); + + if (!compat13) { + /* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ + chan_rcvd_oclose(&channels[channel]); + return; + } + if (channels[channel].type != SSH_CHANNEL_CLOSED) + packet_disconnect("Received close confirmation for non-closed channel %d (type %d).", + channel, channels[channel].type); - /* Free the channel. */ - channel_free(channel); + /* Free the channel. */ + channel_free(channel); } /* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */ -void channel_input_open_confirmation() +void +channel_input_open_confirmation() { - int channel, remote_channel; + int channel, remote_channel; - /* Get the channel number and verify it. */ - channel = packet_get_int(); - if (channel < 0 || channel >= channels_alloc || - channels[channel].type != SSH_CHANNEL_OPENING) - packet_disconnect("Received open confirmation for non-opening channel %d.", - channel); - - /* Get remote side's id for this channel. */ - remote_channel = packet_get_int(); - - /* Record the remote channel number and mark that the channel is now open. */ - channels[channel].remote_id = remote_channel; - channels[channel].type = SSH_CHANNEL_OPEN; + /* Get the channel number and verify it. */ + channel = packet_get_int(); + if (channel < 0 || channel >= channels_alloc || + channels[channel].type != SSH_CHANNEL_OPENING) + packet_disconnect("Received open confirmation for non-opening channel %d.", + channel); + + /* Get remote side's id for this channel. */ + remote_channel = packet_get_int(); + + /* Record the remote channel number and mark that the channel is now open. */ + channels[channel].remote_id = remote_channel; + channels[channel].type = SSH_CHANNEL_OPEN; } /* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */ -void channel_input_open_failure() +void +channel_input_open_failure() { - int channel; + int channel; + + /* Get the channel number and verify it. */ + channel = packet_get_int(); + if (channel < 0 || channel >= channels_alloc || + channels[channel].type != SSH_CHANNEL_OPENING) + packet_disconnect("Received open failure for non-opening channel %d.", + channel); + + /* Free the channel. This will also close the socket. */ + channel_free(channel); +} + +/* + * Stops listening for channels, and removes any unix domain sockets that we + * might have. + */ + +void +channel_stop_listening() +{ + int i; + for (i = 0; i < channels_alloc; i++) { + switch (channels[i].type) { + case SSH_CHANNEL_AUTH_SOCKET: + close(channels[i].sock); + remove(channels[i].path); + channel_free(i); + break; + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_X11_LISTENER: + close(channels[i].sock); + channel_free(i); + break; + default: + break; + } + } +} - /* Get the channel number and verify it. */ - channel = packet_get_int(); - if (channel < 0 || channel >= channels_alloc || - channels[channel].type != SSH_CHANNEL_OPENING) - packet_disconnect("Received open failure for non-opening channel %d.", - channel); - - /* Free the channel. This will also close the socket. */ - channel_free(channel); -} - -/* Stops listening for channels, and removes any unix domain sockets that - we might have. */ - -void channel_stop_listening() -{ - int i; - for (i = 0; i < channels_alloc; i++) - { - switch (channels[i].type) - { - case SSH_CHANNEL_AUTH_SOCKET: - close(channels[i].sock); - remove(channels[i].path); - channel_free(i); - break; - case SSH_CHANNEL_PORT_LISTENER: - case SSH_CHANNEL_X11_LISTENER: - close(channels[i].sock); - channel_free(i); - break; - default: - break; - } - } -} - -/* Closes the sockets of all channels. This is used to close extra file - descriptors after a fork. */ - -void channel_close_all() -{ - int i; - for (i = 0; i < channels_alloc; i++) - { - if (channels[i].type != SSH_CHANNEL_FREE) - close(channels[i].sock); - } +/* + * Closes the sockets of all channels. This is used to close extra file + * descriptors after a fork. + */ + +void +channel_close_all() +{ + int i; + for (i = 0; i < channels_alloc; i++) { + if (channels[i].type != SSH_CHANNEL_FREE) + close(channels[i].sock); + } } /* Returns the maximum file descriptor number used by the channels. */ -int channel_max_fd() +int +channel_max_fd() { - return channel_max_fd_value; + return channel_max_fd_value; } /* Returns true if any channel is still open. */ -int channel_still_open() +int +channel_still_open() { - unsigned int i; - for (i = 0; i < channels_alloc; i++) - switch (channels[i].type) - { - case SSH_CHANNEL_FREE: - case SSH_CHANNEL_X11_LISTENER: - case SSH_CHANNEL_PORT_LISTENER: - case SSH_CHANNEL_CLOSED: - case SSH_CHANNEL_AUTH_SOCKET: - continue; - case SSH_CHANNEL_OPENING: - case SSH_CHANNEL_OPEN: - case SSH_CHANNEL_X11_OPEN: - return 1; - case SSH_CHANNEL_INPUT_DRAINING: - case SSH_CHANNEL_OUTPUT_DRAINING: - if (!compat13) - fatal("cannot happen: OUT_DRAIN"); - return 1; - default: - fatal("channel_still_open: bad channel type %d", channels[i].type); - /*NOTREACHED*/ - } - return 0; -} - -/* Returns a message describing the currently open forwarded - connections, suitable for sending to the client. The message - contains crlf pairs for newlines. */ - -char *channel_open_message() -{ - Buffer buffer; - int i; - char buf[512], *cp; - - buffer_init(&buffer); - snprintf(buf, sizeof buf, "The following connections are open:\r\n"); - buffer_append(&buffer, buf, strlen(buf)); - for (i = 0; i < channels_alloc; i++){ - Channel *c=&channels[i]; - switch (c->type) - { - case SSH_CHANNEL_FREE: - case SSH_CHANNEL_X11_LISTENER: - case SSH_CHANNEL_PORT_LISTENER: - case SSH_CHANNEL_CLOSED: - case SSH_CHANNEL_AUTH_SOCKET: - continue; - case SSH_CHANNEL_OPENING: - case SSH_CHANNEL_OPEN: - case SSH_CHANNEL_X11_OPEN: - case SSH_CHANNEL_INPUT_DRAINING: - case SSH_CHANNEL_OUTPUT_DRAINING: - snprintf(buf, sizeof buf, " #%d/%d %.300s\r\n", - c->self,c->type,c->remote_name); + unsigned int i; + for (i = 0; i < channels_alloc; i++) + switch (channels[i].type) { + case SSH_CHANNEL_FREE: + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_CLOSED: + case SSH_CHANNEL_AUTH_SOCKET: + continue; + case SSH_CHANNEL_OPENING: + case SSH_CHANNEL_OPEN: + case SSH_CHANNEL_X11_OPEN: + return 1; + case SSH_CHANNEL_INPUT_DRAINING: + case SSH_CHANNEL_OUTPUT_DRAINING: + if (!compat13) + fatal("cannot happen: OUT_DRAIN"); + return 1; + default: + fatal("channel_still_open: bad channel type %d", channels[i].type); + /* NOTREACHED */ + } + return 0; +} + +/* + * Returns a message describing the currently open forwarded connections, + * suitable for sending to the client. The message contains crlf pairs for + * newlines. + */ + +char * +channel_open_message() +{ + Buffer buffer; + int i; + char buf[512], *cp; + + buffer_init(&buffer); + snprintf(buf, sizeof buf, "The following connections are open:\r\n"); buffer_append(&buffer, buf, strlen(buf)); - continue; - default: - fatal("channel_still_open: bad channel type %d", c->type); - /*NOTREACHED*/ - } - } - buffer_append(&buffer, "\0", 1); - cp = xstrdup(buffer_ptr(&buffer)); - buffer_free(&buffer); - return cp; -} - -/* Initiate forwarding of connections to local port "port" through the secure - channel to host:port from remote side. */ - -void channel_request_local_forwarding(int port, const char *host, - int host_port) -{ - int ch, sock; - struct sockaddr_in sin; - extern Options options; - - if (strlen(host) > sizeof(channels[0].path) - 1) - packet_disconnect("Forward host name too long."); - - /* Create a port to listen for the host. */ - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) - packet_disconnect("socket: %.100s", strerror(errno)); - - /* Initialize socket address. */ - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - if (options.gateway_ports == 1) - sin.sin_addr.s_addr = htonl(INADDR_ANY); - else - sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - sin.sin_port = htons(port); - - /* Bind the socket to the address. */ - if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - packet_disconnect("bind: %.100s", strerror(errno)); - - /* Start listening for connections on the socket. */ - if (listen(sock, 5) < 0) - packet_disconnect("listen: %.100s", strerror(errno)); - - /* Allocate a channel number for the socket. */ - ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock, - xstrdup("port listener")); - strcpy(channels[ch].path, host); /* note: host name stored here */ - channels[ch].host_port = host_port; /* port on host to connect to */ - channels[ch].listening_port = port; /* port being listened */ -} - -/* Initiate forwarding of connections to port "port" on remote host through - the secure channel to host:port from local side. */ - -void channel_request_remote_forwarding(int port, const char *host, - int remote_port) -{ - int payload_len; - /* Record locally that connection to this host/port is permitted. */ - if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) - fatal("channel_request_remote_forwarding: too many forwards"); - permitted_opens[num_permitted_opens].host = xstrdup(host); - permitted_opens[num_permitted_opens].port = remote_port; - num_permitted_opens++; - - /* Send the forward request to the remote side. */ - packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); - packet_put_int(port); - packet_put_string(host, strlen(host)); - packet_put_int(remote_port); - packet_send(); - packet_write_wait(); - - /* Wait for response from the remote side. It will send a disconnect - message on failure, and we will never see it here. */ - packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); -} - -/* This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates - listening for the port, and sends back a success reply (or disconnect - message if there was an error). This never returns if there was an - error. */ - -void channel_input_port_forward_request(int is_root) -{ - int port, host_port; - char *hostname; - - /* Get arguments from the packet. */ - port = packet_get_int(); - hostname = packet_get_string(NULL); - host_port = packet_get_int(); - - /* Port numbers are 16 bit quantities. */ - if ((port & 0xffff) != port) - packet_disconnect("Requested forwarding of nonexistent port %d.", port); - - /* Check that an unprivileged user is not trying to forward a privileged - port. */ - if (port < IPPORT_RESERVED && !is_root) - packet_disconnect("Requested forwarding of port %d but user is not root.", - port); - - /* Initiate forwarding. */ - channel_request_local_forwarding(port, hostname, host_port); - - /* Free the argument string. */ - xfree(hostname); -} - -/* This is called after receiving PORT_OPEN message. This attempts to connect - to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION or - CHANNEL_OPEN_FAILURE. */ - -void channel_input_port_open(int payload_len) -{ - int remote_channel, sock, newch, host_port, i; - struct sockaddr_in sin; - char *host, *originator_string; - struct hostent *hp; - int host_len, originator_len; - - /* Get remote channel number. */ - remote_channel = packet_get_int(); - - /* Get host name to connect to. */ - host = packet_get_string(&host_len); - - /* Get port to connect to. */ - host_port = packet_get_int(); - - /* Get remote originator name. */ - if (have_hostname_in_open) - originator_string = packet_get_string(&originator_len); - else - originator_string = xstrdup("unknown (remote did not supply name)"); - - packet_integrity_check(payload_len, - 4 + 4 + host_len + 4 + 4 + originator_len, - SSH_MSG_PORT_OPEN); - - /* Check if opening that port is permitted. */ - if (!all_opens_permitted) - { - /* Go trough all permitted ports. */ - for (i = 0; i < num_permitted_opens; i++) - if (permitted_opens[i].port == host_port && - strcmp(permitted_opens[i].host, host) == 0) - break; - - /* Check if we found the requested port among those permitted. */ - if (i >= num_permitted_opens) - { - /* The port is not permitted. */ - log("Received request to connect to %.100s:%d, but the request was denied.", - host, host_port); - packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); - packet_put_int(remote_channel); - packet_send(); - } - } - - memset(&sin, 0, sizeof(sin)); - sin.sin_addr.s_addr = inet_addr(host); - if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) - { - /* It was a valid numeric host address. */ - sin.sin_family = AF_INET; - } - else - { - /* Look up the host address from the name servers. */ - hp = gethostbyname(host); - if (!hp) - { - error("%.100s: unknown host.", host); - goto fail; - } - if (!hp->h_addr_list[0]) - { - error("%.100s: host has no IP address.", host); - goto fail; - } - sin.sin_family = hp->h_addrtype; - memcpy(&sin.sin_addr, hp->h_addr_list[0], - sizeof(sin.sin_addr)); - } - sin.sin_port = htons(host_port); - - /* Create the socket. */ - sock = socket(sin.sin_family, SOCK_STREAM, 0); - if (sock < 0) - { - error("socket: %.100s", strerror(errno)); - goto fail; - } - - /* Connect to the host/port. */ - if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - { - error("connect %.100s:%d: %.100s", host, host_port, - strerror(errno)); - close(sock); - goto fail; - } - - /* Successful connection. */ - - /* Allocate a channel for this connection. */ - newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string); - channels[newch].remote_id = remote_channel; - - /* Send a confirmation to the remote host. */ - packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); - packet_put_int(remote_channel); - packet_put_int(newch); - packet_send(); - - /* Free the argument string. */ - xfree(host); - - return; - - fail: - /* Free the argument string. */ - xfree(host); - - /* Send refusal to the remote host. */ - packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); - packet_put_int(remote_channel); - packet_send(); -} - -/* Creates an internet domain socket for listening for X11 connections. - Returns a suitable value for the DISPLAY variable, or NULL if an error - occurs. */ - -char *x11_create_display_inet(int screen_number) -{ - extern ServerOptions options; - int display_number, port, sock; - struct sockaddr_in sin; - char buf[512]; - char hostname[MAXHOSTNAMELEN]; - - for (display_number = options.x11_display_offset; display_number < MAX_DISPLAYS; display_number++) - { - port = 6000 + display_number; - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); - sin.sin_port = htons(port); - - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) - { - error("socket: %.100s", strerror(errno)); - return NULL; - } - - if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - { - debug("bind port %d: %.100s", port, strerror(errno)); - shutdown(sock, SHUT_RDWR); - close(sock); - continue; - } - break; - } - if (display_number >= MAX_DISPLAYS) - { - error("Failed to allocate internet-domain X11 display socket."); - return NULL; - } - - /* Start listening for connections on the socket. */ - if (listen(sock, 5) < 0) - { - error("listen: %.100s", strerror(errno)); - shutdown(sock, SHUT_RDWR); - close(sock); - return NULL; - } - - /* Set up a suitable value for the DISPLAY variable. */ - if (gethostname(hostname, sizeof(hostname)) < 0) - fatal("gethostname: %.100s", strerror(errno)); - snprintf(buf, sizeof buf, "%.400s:%d.%d", hostname, - display_number, screen_number); - - /* Allocate a channel for the socket. */ - (void)channel_allocate(SSH_CHANNEL_X11_LISTENER, sock, - xstrdup("X11 inet listener")); + for (i = 0; i < channels_alloc; i++) { + Channel *c = &channels[i]; + switch (c->type) { + case SSH_CHANNEL_FREE: + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_CLOSED: + case SSH_CHANNEL_AUTH_SOCKET: + continue; + case SSH_CHANNEL_OPENING: + case SSH_CHANNEL_OPEN: + case SSH_CHANNEL_X11_OPEN: + case SSH_CHANNEL_INPUT_DRAINING: + case SSH_CHANNEL_OUTPUT_DRAINING: + snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d o%d)\r\n", + c->self, c->remote_name, + c->type, c->remote_id, c->istate, c->ostate); + buffer_append(&buffer, buf, strlen(buf)); + continue; + default: + fatal("channel_still_open: bad channel type %d", c->type); + /* NOTREACHED */ + } + } + buffer_append(&buffer, "\0", 1); + cp = xstrdup(buffer_ptr(&buffer)); + buffer_free(&buffer); + return cp; +} + +/* + * Initiate forwarding of connections to local port "port" through the secure + * channel to host:port from remote side. + */ + +void +channel_request_local_forwarding(u_short port, const char *host, + u_short host_port) +{ + int ch, sock, on = 1; + struct sockaddr_in sin; + extern Options options; + struct linger linger; + + if (strlen(host) > sizeof(channels[0].path) - 1) + packet_disconnect("Forward host name too long."); + + /* Create a port to listen for the host. */ + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + packet_disconnect("socket: %.100s", strerror(errno)); + + /* Initialize socket address. */ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + if (options.gateway_ports == 1) + sin.sin_addr.s_addr = htonl(INADDR_ANY); + else + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sin.sin_port = htons(port); + + /* + * Set socket options. We would like the socket to disappear as soon + * as it has been closed for whatever reason. + */ + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); + linger.l_onoff = 1; + linger.l_linger = 5; + setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger)); + + /* Bind the socket to the address. */ + if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) + packet_disconnect("bind: %.100s", strerror(errno)); + + /* Start listening for connections on the socket. */ + if (listen(sock, 5) < 0) + packet_disconnect("listen: %.100s", strerror(errno)); + + /* Allocate a channel number for the socket. */ + ch = channel_allocate(SSH_CHANNEL_PORT_LISTENER, sock, + xstrdup("port listener")); + strlcpy(channels[ch].path, host, sizeof(channels[ch].path)); + channels[ch].host_port = host_port; + channels[ch].listening_port = port; +} + +/* + * Initiate forwarding of connections to port "port" on remote host through + * the secure channel to host:port from local side. + */ + +void +channel_request_remote_forwarding(u_short port, const char *host, + u_short remote_port) +{ + int payload_len; + /* Record locally that connection to this host/port is permitted. */ + if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) + fatal("channel_request_remote_forwarding: too many forwards"); + + permitted_opens[num_permitted_opens].host = xstrdup(host); + permitted_opens[num_permitted_opens].port = remote_port; + num_permitted_opens++; + + /* Send the forward request to the remote side. */ + packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); + packet_put_int(port); + packet_put_string(host, strlen(host)); + packet_put_int(remote_port); + packet_send(); + packet_write_wait(); + + /* + * Wait for response from the remote side. It will send a disconnect + * message on failure, and we will never see it here. + */ + packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); +} + +/* + * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates + * listening for the port, and sends back a success reply (or disconnect + * message if there was an error). This never returns if there was an error. + */ + +void +channel_input_port_forward_request(int is_root) +{ + u_short port, host_port; + char *hostname; + + /* Get arguments from the packet. */ + port = packet_get_int(); + hostname = packet_get_string(NULL); + host_port = packet_get_int(); + + /* + * Check that an unprivileged user is not trying to forward a + * privileged port. + */ + if (port < IPPORT_RESERVED && !is_root) + packet_disconnect("Requested forwarding of port %d but user is not root.", + port); + + /* Initiate forwarding. */ + channel_request_local_forwarding(port, hostname, host_port); + + /* Free the argument string. */ + xfree(hostname); +} + +/* + * This is called after receiving PORT_OPEN message. This attempts to + * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION + * or CHANNEL_OPEN_FAILURE. + */ + +void +channel_input_port_open(int payload_len) +{ + int remote_channel, sock, newch, i; + u_short host_port; + struct sockaddr_in sin; + char *host, *originator_string; + struct hostent *hp; + int host_len, originator_len; + + /* Get remote channel number. */ + remote_channel = packet_get_int(); + + /* Get host name to connect to. */ + host = packet_get_string(&host_len); + + /* Get port to connect to. */ + host_port = packet_get_int(); + + /* Get remote originator name. */ + if (have_hostname_in_open) { + originator_string = packet_get_string(&originator_len); + originator_len += 4; /* size of packet_int */ + } else { + originator_string = xstrdup("unknown (remote did not supply name)"); + originator_len = 0; /* no originator supplied */ + } + + packet_integrity_check(payload_len, + 4 + 4 + host_len + 4 + originator_len, + SSH_MSG_PORT_OPEN); + + /* Check if opening that port is permitted. */ + if (!all_opens_permitted) { + /* Go trough all permitted ports. */ + for (i = 0; i < num_permitted_opens; i++) + if (permitted_opens[i].port == host_port && + strcmp(permitted_opens[i].host, host) == 0) + break; + + /* Check if we found the requested port among those permitted. */ + if (i >= num_permitted_opens) { + /* The port is not permitted. */ + log("Received request to connect to %.100s:%d, but the request was denied.", + host, host_port); + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(remote_channel); + packet_send(); + } + } + memset(&sin, 0, sizeof(sin)); + sin.sin_addr.s_addr = inet_addr(host); + if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) { + /* It was a valid numeric host address. */ + sin.sin_family = AF_INET; + } else { + /* Look up the host address from the name servers. */ + hp = gethostbyname(host); + if (!hp) { + error("%.100s: unknown host.", host); + goto fail; + } + if (!hp->h_addr_list[0]) { + error("%.100s: host has no IP address.", host); + goto fail; + } + sin.sin_family = hp->h_addrtype; + memcpy(&sin.sin_addr, hp->h_addr_list[0], + sizeof(sin.sin_addr)); + } + sin.sin_port = htons(host_port); + + /* Create the socket. */ + sock = socket(sin.sin_family, SOCK_STREAM, 0); + if (sock < 0) { + error("socket: %.100s", strerror(errno)); + goto fail; + } + /* Connect to the host/port. */ + if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { + error("connect %.100s:%d: %.100s", host, host_port, + strerror(errno)); + close(sock); + goto fail; + } + /* Successful connection. */ + + /* Allocate a channel for this connection. */ + newch = channel_allocate(SSH_CHANNEL_OPEN, sock, originator_string); + channels[newch].remote_id = remote_channel; + + /* Send a confirmation to the remote host. */ + packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); + packet_put_int(remote_channel); + packet_put_int(newch); + packet_send(); + + /* Free the argument string. */ + xfree(host); + + return; + +fail: + /* Free the argument string. */ + xfree(host); + + /* Send refusal to the remote host. */ + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(remote_channel); + packet_send(); +} + +/* + * Creates an internet domain socket for listening for X11 connections. + * Returns a suitable value for the DISPLAY variable, or NULL if an error + * occurs. + */ + +char * +x11_create_display_inet(int screen_number) +{ + extern ServerOptions options; + int display_number, sock; + u_short port; + struct sockaddr_in sin; + char buf[512]; + char hostname[MAXHOSTNAMELEN]; + + for (display_number = options.x11_display_offset; + display_number < MAX_DISPLAYS; + display_number++) { + port = 6000 + display_number; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons(port); + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + error("socket: %.100s", strerror(errno)); + return NULL; + } + if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { + debug("bind port %d: %.100s", port, strerror(errno)); + shutdown(sock, SHUT_RDWR); + close(sock); + continue; + } + break; + } + if (display_number >= MAX_DISPLAYS) { + error("Failed to allocate internet-domain X11 display socket."); + return NULL; + } + /* Start listening for connections on the socket. */ + if (listen(sock, 5) < 0) { + error("listen: %.100s", strerror(errno)); + shutdown(sock, SHUT_RDWR); + close(sock); + return NULL; + } + /* Set up a suitable value for the DISPLAY variable. */ + if (gethostname(hostname, sizeof(hostname)) < 0) + fatal("gethostname: %.100s", strerror(errno)); + snprintf(buf, sizeof buf, "%.400s:%d.%d", hostname, + display_number, screen_number); + + /* Allocate a channel for the socket. */ + (void) channel_allocate(SSH_CHANNEL_X11_LISTENER, sock, + xstrdup("X11 inet listener")); - /* Return a suitable value for the DISPLAY environment variable. */ - return xstrdup(buf); + /* Return a suitable value for the DISPLAY environment variable. */ + return xstrdup(buf); } #ifndef X_UNIX_PATH @@ -1141,360 +1178,374 @@ static int -connect_local_xsocket(unsigned dnr) +connect_local_xsocket(unsigned int dnr) { - static const char *const x_sockets[] = { - X_UNIX_PATH "%u", - "/var/X/.X11-unix/X" "%u", - "/usr/spool/sockets/X11/" "%u", - NULL - }; - int sock; - struct sockaddr_un addr; - const char *const *path; - - for (path = x_sockets; *path; ++path) - { - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - error("socket: %.100s", strerror(errno)); - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr); - if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) - return sock; - close(sock); - } - error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); - return -1; -} - - -/* This is called when SSH_SMSG_X11_OPEN is received. The packet contains - the remote channel number. We should do whatever we want, and respond - with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. */ - -void x11_input_open(int payload_len) -{ - int remote_channel, display_number, sock, newch; - const char *display; - struct sockaddr_in sin; - char buf[1024], *cp, *remote_host; - struct hostent *hp; - int remote_len; - - /* Get remote channel number. */ - remote_channel = packet_get_int(); - - /* Get remote originator name. */ - if (have_hostname_in_open) - remote_host = packet_get_string(&remote_len); - else - remote_host = xstrdup("unknown (remote did not supply name)"); - - debug("Received X11 open request."); - packet_integrity_check(payload_len, 4 + 4+remote_len, SSH_SMSG_X11_OPEN); - - /* Try to open a socket for the local X server. */ - display = getenv("DISPLAY"); - if (!display) - { - error("DISPLAY not set."); - goto fail; - } - - /* Now we decode the value of the DISPLAY variable and make a connection - to the real X server. */ - - /* Check if it is a unix domain socket. Unix domain displays are in one - of the following formats: unix:d[.s], :d[.s], ::d[.s] */ - if (strncmp(display, "unix:", 5) == 0 || - display[0] == ':') - { - /* Connect to the unix domain socket. */ - if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) - { - error("Could not parse display number from DISPLAY: %.100s", - display); - goto fail; - } - /* Create a socket. */ - sock = connect_local_xsocket(display_number); - if (sock < 0) - goto fail; - - /* OK, we now have a connection to the display. */ - goto success; - } - - /* Connect to an inet socket. The DISPLAY value is supposedly - hostname:d[.s], where hostname may also be numeric IP address. */ - strncpy(buf, display, sizeof(buf)); - buf[sizeof(buf) - 1] = 0; - cp = strchr(buf, ':'); - if (!cp) - { - error("Could not find ':' in DISPLAY: %.100s", display); - goto fail; - } - *cp = 0; - /* buf now contains the host name. But first we parse the display number. */ - if (sscanf(cp + 1, "%d", &display_number) != 1) - { - error("Could not parse display number from DISPLAY: %.100s", - display); - goto fail; - } - - /* Try to parse the host name as a numeric IP address. */ - memset(&sin, 0, sizeof(sin)); - sin.sin_addr.s_addr = inet_addr(buf); - if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) - { - /* It was a valid numeric host address. */ - sin.sin_family = AF_INET; - } - else - { - /* Not a numeric IP address. */ - /* Look up the host address from the name servers. */ - hp = gethostbyname(buf); - if (!hp) - { - error("%.100s: unknown host.", buf); - goto fail; - } - if (!hp->h_addr_list[0]) - { - error("%.100s: host has no IP address.", buf); - goto fail; - } - sin.sin_family = hp->h_addrtype; - memcpy(&sin.sin_addr, hp->h_addr_list[0], - sizeof(sin.sin_addr)); - } - /* Set port number. */ - sin.sin_port = htons(6000 + display_number); - - /* Create a socket. */ - sock = socket(sin.sin_family, SOCK_STREAM, 0); - if (sock < 0) - { - error("socket: %.100s", strerror(errno)); - goto fail; - } - /* Connect it to the display. */ - if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) - { - error("connect %.100s:%d: %.100s", buf, 6000 + display_number, - strerror(errno)); - close(sock); - goto fail; - } - - success: - /* We have successfully obtained a connection to the real X display. */ - - /* Allocate a channel for this connection. */ - if (x11_saved_proto == NULL) - newch = channel_allocate(SSH_CHANNEL_OPEN, sock, remote_host); - else - newch = channel_allocate(SSH_CHANNEL_X11_OPEN, sock, remote_host); - channels[newch].remote_id = remote_channel; - - /* Send a confirmation to the remote host. */ - packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); - packet_put_int(remote_channel); - packet_put_int(newch); - packet_send(); - - return; - - fail: - /* Send refusal to the remote host. */ - packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); - packet_put_int(remote_channel); - packet_send(); -} - -/* Requests forwarding of X11 connections, generates fake authentication - data, and enables authentication spoofing. */ - -void x11_request_forwarding_with_spoofing(const char *proto, const char *data) -{ - unsigned int data_len = (unsigned int)strlen(data) / 2; - unsigned int i, value; - char *new_data; - int screen_number; - const char *cp; - u_int32_t rand = 0; - - cp = getenv("DISPLAY"); - if (cp) - cp = strchr(cp, ':'); - if (cp) - cp = strchr(cp, '.'); - if (cp) - screen_number = atoi(cp + 1); - else - screen_number = 0; - - /* Save protocol name. */ - x11_saved_proto = xstrdup(proto); - - /* Extract real authentication data and generate fake data of the same - length. */ - x11_saved_data = xmalloc(data_len); - x11_fake_data = xmalloc(data_len); - for (i = 0; i < data_len; i++) - { - if (sscanf(data + 2 * i, "%2x", &value) != 1) - fatal("x11_request_forwarding: bad authentication data: %.100s", data); - if (i % 4 == 0) - rand = arc4random(); - x11_saved_data[i] = value; - x11_fake_data[i] = rand & 0xff; - rand >>= 8; - } - x11_saved_data_len = data_len; - x11_fake_data_len = data_len; - - /* Convert the fake data into hex. */ - new_data = xmalloc(2 * data_len + 1); - for (i = 0; i < data_len; i++) - sprintf(new_data + 2 * i, "%02x", (unsigned char)x11_fake_data[i]); - - /* Send the request packet. */ - packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); - packet_put_string(proto, strlen(proto)); - packet_put_string(new_data, strlen(new_data)); - packet_put_int(screen_number); - packet_send(); - packet_write_wait(); - xfree(new_data); + static const char *const x_sockets[] = { + X_UNIX_PATH "%u", + "/var/X/.X11-unix/X" "%u", + "/usr/spool/sockets/X11/" "%u", + NULL + }; + int sock; + struct sockaddr_un addr; + const char *const * path; + + for (path = x_sockets; *path; ++path) { + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + error("socket: %.100s", strerror(errno)); + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof addr.sun_path, *path, dnr); + if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0) + return sock; + close(sock); + } + error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); + return -1; +} + + +/* + * This is called when SSH_SMSG_X11_OPEN is received. The packet contains + * the remote channel number. We should do whatever we want, and respond + * with either SSH_MSG_OPEN_CONFIRMATION or SSH_MSG_OPEN_FAILURE. + */ + +void +x11_input_open(int payload_len) +{ + int remote_channel, display_number, sock, newch; + const char *display; + struct sockaddr_in sin; + char buf[1024], *cp, *remote_host; + struct hostent *hp; + int remote_len; + + /* Get remote channel number. */ + remote_channel = packet_get_int(); + + /* Get remote originator name. */ + if (have_hostname_in_open) { + remote_host = packet_get_string(&remote_len); + remote_len += 4; + } else { + remote_host = xstrdup("unknown (remote did not supply name)"); + remote_len = 0; + } + + debug("Received X11 open request."); + packet_integrity_check(payload_len, 4 + remote_len, SSH_SMSG_X11_OPEN); + + /* Try to open a socket for the local X server. */ + display = getenv("DISPLAY"); + if (!display) { + error("DISPLAY not set."); + goto fail; + } + /* + * Now we decode the value of the DISPLAY variable and make a + * connection to the real X server. + */ + + /* + * Check if it is a unix domain socket. Unix domain displays are in + * one of the following formats: unix:d[.s], :d[.s], ::d[.s] + */ + if (strncmp(display, "unix:", 5) == 0 || + display[0] == ':') { + /* Connect to the unix domain socket. */ + if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) { + error("Could not parse display number from DISPLAY: %.100s", + display); + goto fail; + } + /* Create a socket. */ + sock = connect_local_xsocket(display_number); + if (sock < 0) + goto fail; + + /* OK, we now have a connection to the display. */ + goto success; + } + /* + * Connect to an inet socket. The DISPLAY value is supposedly + * hostname:d[.s], where hostname may also be numeric IP address. + */ + strncpy(buf, display, sizeof(buf)); + buf[sizeof(buf) - 1] = 0; + cp = strchr(buf, ':'); + if (!cp) { + error("Could not find ':' in DISPLAY: %.100s", display); + goto fail; + } + *cp = 0; + /* buf now contains the host name. But first we parse the display number. */ + if (sscanf(cp + 1, "%d", &display_number) != 1) { + error("Could not parse display number from DISPLAY: %.100s", + display); + goto fail; + } + /* Try to parse the host name as a numeric IP address. */ + memset(&sin, 0, sizeof(sin)); + sin.sin_addr.s_addr = inet_addr(buf); + if ((sin.sin_addr.s_addr & 0xffffffff) != 0xffffffff) { + /* It was a valid numeric host address. */ + sin.sin_family = AF_INET; + } else { + /* Not a numeric IP address. */ + /* Look up the host address from the name servers. */ + hp = gethostbyname(buf); + if (!hp) { + error("%.100s: unknown host.", buf); + goto fail; + } + if (!hp->h_addr_list[0]) { + error("%.100s: host has no IP address.", buf); + goto fail; + } + sin.sin_family = hp->h_addrtype; + memcpy(&sin.sin_addr, hp->h_addr_list[0], + sizeof(sin.sin_addr)); + } + /* Set port number. */ + sin.sin_port = htons(6000 + display_number); + + /* Create a socket. */ + sock = socket(sin.sin_family, SOCK_STREAM, 0); + if (sock < 0) { + error("socket: %.100s", strerror(errno)); + goto fail; + } + /* Connect it to the display. */ + if (connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) { + error("connect %.100s:%d: %.100s", buf, 6000 + display_number, + strerror(errno)); + close(sock); + goto fail; + } +success: + /* We have successfully obtained a connection to the real X display. */ + + /* Allocate a channel for this connection. */ + if (x11_saved_proto == NULL) + newch = channel_allocate(SSH_CHANNEL_OPEN, sock, remote_host); + else + newch = channel_allocate(SSH_CHANNEL_X11_OPEN, sock, remote_host); + channels[newch].remote_id = remote_channel; + + /* Send a confirmation to the remote host. */ + packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); + packet_put_int(remote_channel); + packet_put_int(newch); + packet_send(); + + return; + +fail: + /* Send refusal to the remote host. */ + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(remote_channel); + packet_send(); +} + +/* + * Requests forwarding of X11 connections, generates fake authentication + * data, and enables authentication spoofing. + */ + +void +x11_request_forwarding_with_spoofing(const char *proto, const char *data) +{ + unsigned int data_len = (unsigned int) strlen(data) / 2; + unsigned int i, value; + char *new_data; + int screen_number; + const char *cp; + u_int32_t rand = 0; + + cp = getenv("DISPLAY"); + if (cp) + cp = strchr(cp, ':'); + if (cp) + cp = strchr(cp, '.'); + if (cp) + screen_number = atoi(cp + 1); + else + screen_number = 0; + + /* Save protocol name. */ + x11_saved_proto = xstrdup(proto); + + /* + * Extract real authentication data and generate fake data of the + * same length. + */ + x11_saved_data = xmalloc(data_len); + x11_fake_data = xmalloc(data_len); + for (i = 0; i < data_len; i++) { + if (sscanf(data + 2 * i, "%2x", &value) != 1) + fatal("x11_request_forwarding: bad authentication data: %.100s", data); + if (i % 4 == 0) + rand = arc4random(); + x11_saved_data[i] = value; + x11_fake_data[i] = rand & 0xff; + rand >>= 8; + } + x11_saved_data_len = data_len; + x11_fake_data_len = data_len; + + /* Convert the fake data into hex. */ + new_data = xmalloc(2 * data_len + 1); + for (i = 0; i < data_len; i++) + sprintf(new_data + 2 * i, "%02x", (unsigned char) x11_fake_data[i]); + + /* Send the request packet. */ + packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); + packet_put_string(proto, strlen(proto)); + packet_put_string(new_data, strlen(new_data)); + packet_put_int(screen_number); + packet_send(); + packet_write_wait(); + xfree(new_data); } /* Sends a message to the server to request authentication fd forwarding. */ -void auth_request_forwarding() +void +auth_request_forwarding() { - packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); - packet_send(); - packet_write_wait(); + packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); + packet_send(); + packet_write_wait(); } -/* Returns the name of the forwarded authentication socket. Returns NULL - if there is no forwarded authentication socket. The returned value - points to a static buffer. */ +/* + * Returns the name of the forwarded authentication socket. Returns NULL if + * there is no forwarded authentication socket. The returned value points to + * a static buffer. + */ -char *auth_get_socket_name() +char * +auth_get_socket_name() { - return channel_forwarded_auth_socket_name; + return channel_forwarded_auth_socket_name; } /* removes the agent forwarding socket */ + +void +cleanup_socket(void) +{ + remove(channel_forwarded_auth_socket_name); + rmdir(channel_forwarded_auth_socket_dir); +} + +/* + * This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. + * This starts forwarding authentication requests. + */ + +void +auth_input_request_forwarding(struct passwd * pw) +{ + int sock, newch; + struct sockaddr_un sunaddr; + + if (auth_get_socket_name() != NULL) + fatal("Protocol error: authentication forwarding requested twice."); + + /* Temporarily drop privileged uid for mkdir/bind. */ + temporarily_use_uid(pw->pw_uid); -void cleanup_socket(void) { - remove(channel_forwarded_auth_socket_name); - rmdir(channel_forwarded_auth_socket_dir); -} - -/* This if called to process SSH_CMSG_AGENT_REQUEST_FORWARDING on the server. - This starts forwarding authentication requests. */ - -void auth_input_request_forwarding(struct passwd *pw) -{ - int sock, newch; - struct sockaddr_un sunaddr; - - if (auth_get_socket_name() != NULL) - fatal("Protocol error: authentication forwarding requested twice."); - - /* Temporarily drop privileged uid for mkdir/bind. */ - temporarily_use_uid(pw->pw_uid); - - /* Allocate a buffer for the socket name, and format the name. */ - channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME); - channel_forwarded_auth_socket_dir = xmalloc(MAX_SOCKET_NAME); - strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME); - - /* Create private directory for socket */ - if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL) - packet_disconnect("mkdtemp: %.100s", strerror(errno)); - snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME, - "%s/agent.%d", channel_forwarded_auth_socket_dir, (int)getpid()); - - if (atexit(cleanup_socket) < 0) { - int saved=errno; - cleanup_socket(); - packet_disconnect("socket: %.100s", strerror(saved)); - } - - /* Create the socket. */ - sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock < 0) - packet_disconnect("socket: %.100s", strerror(errno)); - - /* Bind it to the name. */ - memset(&sunaddr, 0, sizeof(sunaddr)); - sunaddr.sun_family = AF_UNIX; - strncpy(sunaddr.sun_path, channel_forwarded_auth_socket_name, - sizeof(sunaddr.sun_path)); - - if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) - packet_disconnect("bind: %.100s", strerror(errno)); - - /* Restore the privileged uid. */ - restore_uid(); - - /* Start listening on the socket. */ - if (listen(sock, 5) < 0) - packet_disconnect("listen: %.100s", strerror(errno)); - - /* Allocate a channel for the authentication agent socket. */ - newch = channel_allocate(SSH_CHANNEL_AUTH_SOCKET, sock, - xstrdup("auth socket")); - strcpy(channels[newch].path, channel_forwarded_auth_socket_name); + /* Allocate a buffer for the socket name, and format the name. */ + channel_forwarded_auth_socket_name = xmalloc(MAX_SOCKET_NAME); + channel_forwarded_auth_socket_dir = xmalloc(MAX_SOCKET_NAME); + strlcpy(channel_forwarded_auth_socket_dir, "/tmp/ssh-XXXXXXXX", MAX_SOCKET_NAME); + + /* Create private directory for socket */ + if (mkdtemp(channel_forwarded_auth_socket_dir) == NULL) + packet_disconnect("mkdtemp: %.100s", strerror(errno)); + snprintf(channel_forwarded_auth_socket_name, MAX_SOCKET_NAME, "%s/agent.%d", + channel_forwarded_auth_socket_dir, (int) getpid()); + + if (atexit(cleanup_socket) < 0) { + int saved = errno; + cleanup_socket(); + packet_disconnect("socket: %.100s", strerror(saved)); + } + /* Create the socket. */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + packet_disconnect("socket: %.100s", strerror(errno)); + + /* Bind it to the name. */ + memset(&sunaddr, 0, sizeof(sunaddr)); + sunaddr.sun_family = AF_UNIX; + strncpy(sunaddr.sun_path, channel_forwarded_auth_socket_name, + sizeof(sunaddr.sun_path)); + + if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) + packet_disconnect("bind: %.100s", strerror(errno)); + + /* Restore the privileged uid. */ + restore_uid(); + + /* Start listening on the socket. */ + if (listen(sock, 5) < 0) + packet_disconnect("listen: %.100s", strerror(errno)); + + /* Allocate a channel for the authentication agent socket. */ + newch = channel_allocate(SSH_CHANNEL_AUTH_SOCKET, sock, + xstrdup("auth socket")); + strlcpy(channels[newch].path, channel_forwarded_auth_socket_name, + sizeof(channels[newch].path)); } /* This is called to process an SSH_SMSG_AGENT_OPEN message. */ -void auth_input_open_request() +void +auth_input_open_request() { - int remch, sock, newch; - char *dummyname; + int remch, sock, newch; + char *dummyname; + + /* Read the remote channel number from the message. */ + remch = packet_get_int(); + + /* + * Get a connection to the local authentication agent (this may again + * get forwarded). + */ + sock = ssh_get_authentication_socket(); + + /* + * If we could not connect the agent, send an error message back to + * the server. This should never happen unless the agent dies, + * because authentication forwarding is only enabled if we have an + * agent. + */ + if (sock < 0) { + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(remch); + packet_send(); + return; + } + debug("Forwarding authentication connection."); - /* Read the remote channel number from the message. */ - remch = packet_get_int(); - - /* Get a connection to the local authentication agent (this may again get - forwarded). */ - sock = ssh_get_authentication_socket(); - - /* If we could not connect the agent, send an error message back to - the server. This should never happen unless the agent - dies, because authentication forwarding is only enabled if we have an - agent. */ - if (sock < 0){ - packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); - packet_put_int(remch); - packet_send(); - return; - } - - debug("Forwarding authentication connection."); - - /* Dummy host name. This will be freed when the channel is freed; it will - still be valid in the packet_put_string below since the channel cannot - yet be freed at that point. */ - dummyname = xstrdup("authentication agent connection"); - - newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname); - channels[newch].remote_id = remch; - - /* Send a confirmation to the remote host. */ - packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); - packet_put_int(remch); - packet_put_int(newch); - packet_send(); + /* + * Dummy host name. This will be freed when the channel is freed; it + * will still be valid in the packet_put_string below since the + * channel cannot yet be freed at that point. + */ + dummyname = xstrdup("authentication agent connection"); + + newch = channel_allocate(SSH_CHANNEL_OPEN, sock, dummyname); + channels[newch].remote_id = remch; + + /* Send a confirmation to the remote host. */ + packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); + packet_put_int(remch); + packet_put_int(newch); + packet_send(); } Index: usr.bin/ssh/channels.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/channels.h,v retrieving revision 1.3 retrieving revision 1.6 diff -u -r1.3 -r1.6 --- usr.bin/ssh/channels.h 1999/10/17 16:56:09 1.3 +++ usr.bin/ssh/channels.h 1999/11/24 19:53:45 1.6 @@ -1,41 +1,43 @@ -/* RCSID("$Id: channels.h,v 1.3 1999/10/17 16:56:09 markus Exp $"); */ +/* RCSID("$Id: channels.h,v 1.6 1999/11/24 19:53:45 markus Exp $"); */ #ifndef CHANNELS_H #define CHANNELS_H /* Definitions for channel types. */ -#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */ -#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */ -#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */ -#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */ -#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */ -#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */ -/* SSH_CHANNEL_AUTH_FD 6 authentication fd */ -#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */ -/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */ -#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */ -#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */ -#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */ +#define SSH_CHANNEL_FREE 0 /* This channel is free (unused). */ +#define SSH_CHANNEL_X11_LISTENER 1 /* Listening for inet X11 conn. */ +#define SSH_CHANNEL_PORT_LISTENER 2 /* Listening on a port. */ +#define SSH_CHANNEL_OPENING 3 /* waiting for confirmation */ +#define SSH_CHANNEL_OPEN 4 /* normal open two-way channel */ +#define SSH_CHANNEL_CLOSED 5 /* waiting for close confirmation */ +/* SSH_CHANNEL_AUTH_FD 6 authentication fd */ +#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */ +/* SSH_CHANNEL_AUTH_SOCKET_FD 8 connection to auth socket */ +#define SSH_CHANNEL_X11_OPEN 9 /* reading first X11 packet */ +#define SSH_CHANNEL_INPUT_DRAINING 10 /* sending remaining data to conn */ +#define SSH_CHANNEL_OUTPUT_DRAINING 11 /* sending remaining data to app */ -/* Data structure for channel data. This is iniailized in channel_allocate - and cleared in channel_free. */ +/* + * Data structure for channel data. This is iniailized in channel_allocate + * and cleared in channel_free. + */ -typedef struct Channel -{ - int type; /* channel type/state */ - int self; /* my own channel identifier */ - int remote_id; /* channel identifier for remote peer */ - /* peer can be reached over encrypted connection, via packet-sent */ - int istate; - int ostate; - int x11; - int sock; /* data socket, linked to this channel */ - Buffer input; /* data read from socket, to be sent over encrypted connection */ - Buffer output; /* data received over encrypted connection for send on socket */ - char path[200]; /* path for unix domain sockets, or host name for forwards */ - int listening_port; /* port being listened for forwards */ - int host_port; /* remote port to connect for forwards */ - char *remote_name; /* remote hostname */ -} Channel; - +typedef struct Channel { + int type; /* channel type/state */ + int self; /* my own channel identifier */ + int remote_id; /* channel identifier for remote peer */ + /* peer can be reached over encrypted connection, via packet-sent */ + int istate; /* input from channel (state of receive half) */ + int ostate; /* output to channel (state of transmit half) */ + int sock; /* data socket, linked to this channel */ + Buffer input; /* data read from socket, to be sent over + * encrypted connection */ + Buffer output; /* data received over encrypted connection for + * send on socket */ + char path[200]; /* path for unix domain sockets, or host name + * for forwards */ + int listening_port; /* port being listened for forwards */ + int host_port; /* remote port to connect for forwards */ + char *remote_name; /* remote hostname */ +} Channel; #endif Index: usr.bin/ssh/check-fds.c =================================================================== RCS file: check-fds.c diff -N check-fds.c --- /dev/null Wed Dec 8 12:40:35 1999 +++ /tmp/cvsmpvYQ31367 Wed Dec 8 12:42:05 1999 @@ -0,0 +1,43 @@ +/* + +check-fds.c + +Author: Tatu Ylonen + +Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + All rights reserved + +Created: Sat Apr 8 00:25:04 1995 ylo + +*/ + +#include +RCSID("$Id: check-fds.c,v 1.2 1999/09/26 23:17:24 deraadt dead $"); + +#include +#include +#include + +int main(int ac, char **av) +{ + int i, dummy; + struct stat st; + + for (i = 0; i < 1024; i++) + if (fcntl(i, F_GETFL, &dummy) >= 0) + { + printf("Descriptor %d is open.\n", i); + if (fstat(i, &st) < 0) + perror("fstat"); + else + { + printf("st_mode 0x%x, st_dev 0x%x, st_rdev 0x%x, st_ino 0x%x, st_size 0x%lx\n", + st.st_mode, st.st_dev, st.st_rdev, st.st_ino, + (long)st.st_size); + if (ttyname(i)) + printf("ttyname: %.100s\n", ttyname(i)); + } + } + exit(0); +} + Index: usr.bin/ssh/cipher.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/cipher.c,v retrieving revision 1.11 retrieving revision 1.18 diff -u -r1.11 -r1.18 --- usr.bin/ssh/cipher.c 1999/09/30 22:12:16 1.11 +++ usr.bin/ssh/cipher.c 1999/11/24 19:53:45 1.18 @@ -1,23 +1,23 @@ /* - -cipher.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Wed Apr 19 17:41:39 1995 ylo - -*/ + * + * cipher.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Wed Apr 19 17:41:39 1995 ylo + * + */ #include "includes.h" -RCSID("$Id: cipher.c,v 1.11 1999/09/30 22:12:16 provos Exp $"); +RCSID("$Id: cipher.c,v 1.18 1999/11/24 19:53:45 markus Exp $"); #include "ssh.h" #include "cipher.h" -#include +#include /* * What kind of tripple DES are these 2 routines? @@ -33,272 +33,288 @@ */ void SSH_3CBC_ENCRYPT(des_key_schedule ks1, - des_key_schedule ks2, des_cblock *iv2, - des_key_schedule ks3, des_cblock *iv3, + des_key_schedule ks2, des_cblock * iv2, + des_key_schedule ks3, des_cblock * iv3, void *dest, void *src, unsigned int len) { - des_cblock iv1; + des_cblock iv1; - memcpy(&iv1, iv2, 8); + memcpy(&iv1, iv2, 8); - des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT); - memcpy(&iv1, dest + len - 8, 8); + des_cbc_encrypt(src, dest, len, ks1, &iv1, DES_ENCRYPT); + memcpy(&iv1, dest + len - 8, 8); - des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT); - memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */ + des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_DECRYPT); + memcpy(iv2, &iv1, 8); /* Note how iv1 == iv2 on entry and exit. */ - des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT); - memcpy(iv3, dest + len - 8, 8); + des_cbc_encrypt(dest, dest, len, ks3, iv3, DES_ENCRYPT); + memcpy(iv3, dest + len - 8, 8); } void SSH_3CBC_DECRYPT(des_key_schedule ks1, - des_key_schedule ks2, des_cblock *iv2, - des_key_schedule ks3, des_cblock *iv3, + des_key_schedule ks2, des_cblock * iv2, + des_key_schedule ks3, des_cblock * iv3, void *dest, void *src, unsigned int len) { - des_cblock iv1; + des_cblock iv1; - memcpy(&iv1, iv2, 8); + memcpy(&iv1, iv2, 8); - des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT); - memcpy(iv3, src + len - 8, 8); + des_cbc_encrypt(src, dest, len, ks3, iv3, DES_DECRYPT); + memcpy(iv3, src + len - 8, 8); - des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT); - memcpy(iv2, dest + len - 8, 8); + des_cbc_encrypt(dest, dest, len, ks2, iv2, DES_ENCRYPT); + memcpy(iv2, dest + len - 8, 8); - des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT); - /* memcpy(&iv1, iv2, 8); */ /* Note how iv1 == iv2 on entry and exit. */ + des_cbc_encrypt(dest, dest, len, ks1, &iv1, DES_DECRYPT); + /* memcpy(&iv1, iv2, 8); */ + /* Note how iv1 == iv2 on entry and exit. */ } /* * SSH uses a variation on Blowfish, all bytes must be swapped before * and after encryption/decryption. Thus the swap_bytes stuff (yuk). */ -static -void +static void swap_bytes(const unsigned char *src, unsigned char *dst_, int n) { - u_int32_t *dst = (u_int32_t *)dst_; /* dst must be properly aligned. */ - union { - u_int32_t i; - char c[4]; - } t; - - /* assert((n & 7) == 0); */ - - /* Process 8 bytes every lap. */ - for (n = n / 8; n > 0; n--) - { - t.c[3] = *src++; - t.c[2] = *src++; - t.c[1] = *src++; - t.c[0] = *src++; - *dst++ = t.i; - - t.c[3] = *src++; - t.c[2] = *src++; - t.c[1] = *src++; - t.c[0] = *src++; - *dst++ = t.i; - } + /* dst must be properly aligned. */ + u_int32_t *dst = (u_int32_t *) dst_; + union { + u_int32_t i; + char c[4]; + } t; + + /* Process 8 bytes every lap. */ + for (n = n / 8; n > 0; n--) { + t.c[3] = *src++; + t.c[2] = *src++; + t.c[1] = *src++; + t.c[0] = *src++; + *dst++ = t.i; + + t.c[3] = *src++; + t.c[2] = *src++; + t.c[1] = *src++; + t.c[0] = *src++; + *dst++ = t.i; + } } -void (*cipher_attack_detected)(const char *fmt, ...) = fatal; +void (*cipher_attack_detected) (const char *fmt,...) = fatal; -static inline -void +static inline void detect_cbc_attack(const unsigned char *src, unsigned int len) { - return; - - log("CRC-32 CBC insertion attack detected"); - cipher_attack_detected("CRC-32 CBC insertion attack detected"); + return; + + log("CRC-32 CBC insertion attack detected"); + cipher_attack_detected("CRC-32 CBC insertion attack detected"); } -/* Names of all encryption algorithms. These must match the numbers defined - int cipher.h. */ +/* + * Names of all encryption algorithms. + * These must match the numbers defined in cipher.h. + */ static char *cipher_names[] = { - "none", - "idea", - "des", - "3des", - "tss", - "rc4", - "blowfish" + "none", + "idea", + "des", + "3des", + "tss", + "rc4", + "blowfish" }; -/* Returns a bit mask indicating which ciphers are supported by this - implementation. The bit mask has the corresponding bit set of each - supported cipher. */ - -unsigned int cipher_mask() -{ - unsigned int mask = 0; - mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ - mask |= 1 << SSH_CIPHER_BLOWFISH; - return mask; +/* + * Returns a bit mask indicating which ciphers are supported by this + * implementation. The bit mask has the corresponding bit set of each + * supported cipher. + */ + +unsigned int +cipher_mask() +{ + unsigned int mask = 0; + mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ + mask |= 1 << SSH_CIPHER_BLOWFISH; + return mask; } /* Returns the name of the cipher. */ -const -char *cipher_name(int cipher) +const char * +cipher_name(int cipher) { - if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) || - cipher_names[cipher] == NULL) - fatal("cipher_name: bad cipher number: %d", cipher); - return cipher_names[cipher]; + if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0]) || + cipher_names[cipher] == NULL) + fatal("cipher_name: bad cipher number: %d", cipher); + return cipher_names[cipher]; } -/* Parses the name of the cipher. Returns the number of the corresponding - cipher, or -1 on error. */ +/* + * Parses the name of the cipher. Returns the number of the corresponding + * cipher, or -1 on error. + */ int cipher_number(const char *name) { - int i; - for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++) - if (strcmp(cipher_names[i], name) == 0 && - (cipher_mask() & (1 << i))) - return i; - return -1; + int i; + for (i = 0; i < sizeof(cipher_names) / sizeof(cipher_names[0]); i++) + if (strcmp(cipher_names[i], name) == 0 && + (cipher_mask() & (1 << i))) + return i; + return -1; } -/* Selects the cipher, and keys if by computing the MD5 checksum of the - passphrase and using the resulting 16 bytes as the key. */ +/* + * Selects the cipher, and keys if by computing the MD5 checksum of the + * passphrase and using the resulting 16 bytes as the key. + */ -void cipher_set_key_string(CipherContext *context, int cipher, - const char *passphrase, int for_encryption) +void +cipher_set_key_string(CipherContext *context, int cipher, + const char *passphrase, int for_encryption) { - MD5_CTX md; - unsigned char digest[16]; - - MD5Init(&md); - MD5Update(&md, (const unsigned char *)passphrase, strlen(passphrase)); - MD5Final(digest, &md); - - cipher_set_key(context, cipher, digest, 16, for_encryption); - - memset(digest, 0, sizeof(digest)); - memset(&md, 0, sizeof(md)); -} + MD5_CTX md; + unsigned char digest[16]; -/* Selects the cipher to use and sets the key. */ + MD5_Init(&md); + MD5_Update(&md, (const unsigned char *) passphrase, strlen(passphrase)); + MD5_Final(digest, &md); -void cipher_set_key(CipherContext *context, int cipher, - const unsigned char *key, int keylen, int for_encryption) -{ - unsigned char padded[32]; + cipher_set_key(context, cipher, digest, 16, for_encryption); - /* Set cipher type. */ - context->type = cipher; + memset(digest, 0, sizeof(digest)); + memset(&md, 0, sizeof(md)); +} - /* Get 32 bytes of key data. Pad if necessary. (So that code below does - not need to worry about key size). */ - memset(padded, 0, sizeof(padded)); - memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded)); - - /* Initialize the initialization vector. */ - switch (cipher) - { - case SSH_CIPHER_NONE: - /* Has to stay for authfile saving of private key with no passphrase */ - break; - - case SSH_CIPHER_3DES: - /* Note: the least significant bit of each byte of key is parity, - and must be ignored by the implementation. 16 bytes of key are - used (first and last keys are the same). */ - if (keylen < 16) - error("Key length %d is insufficient for 3DES.", keylen); - des_set_key((void*)padded, context->u.des3.key1); - des_set_key((void*)(padded + 8), context->u.des3.key2); - if (keylen <= 16) - des_set_key((void*)padded, context->u.des3.key3); - else - des_set_key((void*)(padded + 16), context->u.des3.key3); - memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2)); - memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3)); - break; - - case SSH_CIPHER_BLOWFISH: - BF_set_key(&context->u.bf.key, keylen, padded); - memset(context->u.bf.iv, 0, 8); - break; - - default: - fatal("cipher_set_key: unknown cipher: %d", cipher); - } - memset(padded, 0, sizeof(padded)); +/* Selects the cipher to use and sets the key. */ + +void +cipher_set_key(CipherContext *context, int cipher, + const unsigned char *key, int keylen, int for_encryption) +{ + unsigned char padded[32]; + + /* Set cipher type. */ + context->type = cipher; + + /* Get 32 bytes of key data. Pad if necessary. (So that code + below does not need to worry about key size). */ + memset(padded, 0, sizeof(padded)); + memcpy(padded, key, keylen < sizeof(padded) ? keylen : sizeof(padded)); + + /* Initialize the initialization vector. */ + switch (cipher) { + case SSH_CIPHER_NONE: + /* + * Has to stay for authfile saving of private key with no + * passphrase + */ + break; + + case SSH_CIPHER_3DES: + /* + * Note: the least significant bit of each byte of key is + * parity, and must be ignored by the implementation. 16 + * bytes of key are used (first and last keys are the same). + */ + if (keylen < 16) + error("Key length %d is insufficient for 3DES.", keylen); + des_set_key((void *) padded, context->u.des3.key1); + des_set_key((void *) (padded + 8), context->u.des3.key2); + if (keylen <= 16) + des_set_key((void *) padded, context->u.des3.key3); + else + des_set_key((void *) (padded + 16), context->u.des3.key3); + memset(context->u.des3.iv2, 0, sizeof(context->u.des3.iv2)); + memset(context->u.des3.iv3, 0, sizeof(context->u.des3.iv3)); + break; + + case SSH_CIPHER_BLOWFISH: + BF_set_key(&context->u.bf.key, keylen, padded); + memset(context->u.bf.iv, 0, 8); + break; + + default: + fatal("cipher_set_key: unknown cipher: %s", cipher_name(cipher)); + } + memset(padded, 0, sizeof(padded)); } /* Encrypts data using the cipher. */ - -void cipher_encrypt(CipherContext *context, unsigned char *dest, - const unsigned char *src, unsigned int len) -{ - assert((len & 7) == 0); - switch (context->type) - { - case SSH_CIPHER_NONE: - memcpy(dest, src, len); - break; - - case SSH_CIPHER_3DES: - SSH_3CBC_ENCRYPT(context->u.des3.key1, - context->u.des3.key2, &context->u.des3.iv2, - context->u.des3.key3, &context->u.des3.iv3, - dest, (void*)src, len); - break; - - case SSH_CIPHER_BLOWFISH: - swap_bytes(src, dest, len); - BF_cbc_encrypt(dest, dest, len, - &context->u.bf.key, context->u.bf.iv, BF_ENCRYPT); - swap_bytes(dest, dest, len); - break; - - default: - fatal("cipher_encrypt: unknown cipher: %d", context->type); - } +void +cipher_encrypt(CipherContext *context, unsigned char *dest, + const unsigned char *src, unsigned int len) +{ + if ((len & 7) != 0) + fatal("cipher_encrypt: bad plaintext length %d", len); + + switch (context->type) { + case SSH_CIPHER_NONE: + memcpy(dest, src, len); + break; + + case SSH_CIPHER_3DES: + SSH_3CBC_ENCRYPT(context->u.des3.key1, + context->u.des3.key2, &context->u.des3.iv2, + context->u.des3.key3, &context->u.des3.iv3, + dest, (void *) src, len); + break; + + case SSH_CIPHER_BLOWFISH: + swap_bytes(src, dest, len); + BF_cbc_encrypt(dest, dest, len, + &context->u.bf.key, context->u.bf.iv, + BF_ENCRYPT); + swap_bytes(dest, dest, len); + break; + + default: + fatal("cipher_encrypt: unknown cipher: %s", cipher_name(context->type)); + } } - -/* Decrypts data using the cipher. */ -void cipher_decrypt(CipherContext *context, unsigned char *dest, - const unsigned char *src, unsigned int len) -{ - assert((len & 7) == 0); +/* Decrypts data using the cipher. */ - switch (context->type) - { - case SSH_CIPHER_NONE: - memcpy(dest, src, len); - break; - - case SSH_CIPHER_3DES: - /* CRC-32 attack? */ - SSH_3CBC_DECRYPT(context->u.des3.key1, - context->u.des3.key2, &context->u.des3.iv2, - context->u.des3.key3, &context->u.des3.iv3, - dest, (void*)src, len); - break; - - case SSH_CIPHER_BLOWFISH: - detect_cbc_attack(src, len); - swap_bytes(src, dest, len); - BF_cbc_encrypt((void*)dest, dest, len, - &context->u.bf.key, context->u.bf.iv, BF_DECRYPT); - swap_bytes(dest, dest, len); - break; - - default: - fatal("cipher_decrypt: unknown cipher: %d", context->type); - } +void +cipher_decrypt(CipherContext *context, unsigned char *dest, + const unsigned char *src, unsigned int len) +{ + if ((len & 7) != 0) + fatal("cipher_decrypt: bad ciphertext length %d", len); + + switch (context->type) { + case SSH_CIPHER_NONE: + memcpy(dest, src, len); + break; + + case SSH_CIPHER_3DES: + /* CRC-32 attack? */ + SSH_3CBC_DECRYPT(context->u.des3.key1, + context->u.des3.key2, &context->u.des3.iv2, + context->u.des3.key3, &context->u.des3.iv3, + dest, (void *) src, len); + break; + + case SSH_CIPHER_BLOWFISH: + detect_cbc_attack(src, len); + swap_bytes(src, dest, len); + BF_cbc_encrypt((void *) dest, dest, len, + &context->u.bf.key, context->u.bf.iv, + BF_DECRYPT); + swap_bytes(dest, dest, len); + break; + + default: + fatal("cipher_decrypt: unknown cipher: %s", cipher_name(context->type)); + } } Index: usr.bin/ssh/cipher.h =================================================================== RCS file: /cvs/src/usr.bin/ssh/cipher.h,v retrieving revision 1.7 retrieving revision 1.10 diff -u -r1.7 -r1.10 --- usr.bin/ssh/cipher.h 1999/10/02 19:14:54 1.7 +++ usr.bin/ssh/cipher.h 1999/11/24 19:53:46 1.10 @@ -1,84 +1,97 @@ /* + * + * cipher.h + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * Created: Wed Apr 19 16:50:42 1995 ylo + * + */ -cipher.h +/* RCSID("$Id: cipher.h,v 1.10 1999/11/24 19:53:46 markus Exp $"); */ -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Wed Apr 19 16:50:42 1995 ylo - -*/ - -/* RCSID("$Id: cipher.h,v 1.7 1999/10/02 19:14:54 deraadt Exp $"); */ - #ifndef CIPHER_H #define CIPHER_H -#include +#include #include /* Cipher types. New types can be added, but old types should not be removed for compatibility. The maximum allowed value is 31. */ -#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */ -#define SSH_CIPHER_NONE 0 /* no encryption */ -#define SSH_CIPHER_IDEA 1 /* IDEA CFB */ -#define SSH_CIPHER_DES 2 /* DES CBC */ -#define SSH_CIPHER_3DES 3 /* 3DES CBC */ -#define SSH_CIPHER_TSS 4 /* TRI's Simple Stream encryption CBC */ -#define SSH_CIPHER_RC4 5 /* Alleged RC4 */ +#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */ +#define SSH_CIPHER_NONE 0 /* no encryption */ +#define SSH_CIPHER_IDEA 1 /* IDEA CFB */ +#define SSH_CIPHER_DES 2 /* DES CBC */ +#define SSH_CIPHER_3DES 3 /* 3DES CBC */ +#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */ +#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */ #define SSH_CIPHER_BLOWFISH 6 typedef struct { - unsigned int type; - union { - struct { - des_key_schedule key1; - des_key_schedule key2; - des_cblock iv2; - des_key_schedule key3; - des_cblock iv3; - } des3; - struct { - struct bf_key_st key; - unsigned char iv[8]; - } bf; - } u; -} CipherContext; - -/* Returns a bit mask indicating which ciphers are supported by this - implementation. The bit mask has the corresponding bit set of each - supported cipher. */ + unsigned int type; + union { + struct { + des_key_schedule key1; + des_key_schedule key2; + des_cblock iv2; + des_key_schedule key3; + des_cblock iv3; + } des3; + struct { + struct bf_key_st key; + unsigned char iv[8]; + } bf; + } u; +} CipherContext; +/* + * Returns a bit mask indicating which ciphers are supported by this + * implementation. The bit mask has the corresponding bit set of each + * supported cipher. + */ unsigned int cipher_mask(); /* Returns the name of the cipher. */ const char *cipher_name(int cipher); -/* Parses the name of the cipher. Returns the number of the corresponding - cipher, or -1 on error. */ -int cipher_number(const char *name); - -/* Selects the cipher to use and sets the key. If for_encryption is true, - the key is setup for encryption; otherwise it is setup for decryption. */ -void cipher_set_key(CipherContext *context, int cipher, - const unsigned char *key, int keylen, int for_encryption); - -/* Sets key for the cipher by computing the MD5 checksum of the passphrase, - and using the resulting 16 bytes as the key. */ -void cipher_set_key_string(CipherContext *context, int cipher, - const char *passphrase, int for_encryption); +/* + * Parses the name of the cipher. Returns the number of the corresponding + * cipher, or -1 on error. + */ +int cipher_number(const char *name); + +/* + * Selects the cipher to use and sets the key. If for_encryption is true, + * the key is setup for encryption; otherwise it is setup for decryption. + */ +void +cipher_set_key(CipherContext * context, int cipher, + const unsigned char *key, int keylen, int for_encryption); + +/* + * Sets key for the cipher by computing the MD5 checksum of the passphrase, + * and using the resulting 16 bytes as the key. + */ +void +cipher_set_key_string(CipherContext * context, int cipher, + const char *passphrase, int for_encryption); /* Encrypts data using the cipher. */ -void cipher_encrypt(CipherContext *context, unsigned char *dest, - const unsigned char *src, unsigned int len); +void +cipher_encrypt(CipherContext * context, unsigned char *dest, + const unsigned char *src, unsigned int len); /* Decrypts data using the cipher. */ -void cipher_decrypt(CipherContext *context, unsigned char *dest, - const unsigned char *src, unsigned int len); - -/* If and CRC-32 attack is detected this function is called. Defaults - * to fatal, changed to packet_disconnect in sshd and ssh. */ -extern void (*cipher_attack_detected)(const char *fmt, ...); +void +cipher_decrypt(CipherContext * context, unsigned char *dest, + const unsigned char *src, unsigned int len); + +/* + * If and CRC-32 attack is detected this function is called. Defaults to + * fatal, changed to packet_disconnect in sshd and ssh. + */ +extern void (*cipher_attack_detected) (const char *fmt, ...); -#endif /* CIPHER_H */ +#endif /* CIPHER_H */ Index: usr.bin/ssh/clientloop.c =================================================================== RCS file: /cvs/src/usr.bin/ssh/clientloop.c,v retrieving revision 1.7 retrieving revision 1.14 diff -u -r1.7 -r1.14 --- usr.bin/ssh/clientloop.c 1999/10/16 20:57:52 1.7 +++ usr.bin/ssh/clientloop.c 1999/12/06 20:15:26 1.14 @@ -1,646 +1,667 @@ /* + * + * clientloop.c + * + * Author: Tatu Ylonen + * + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * + * Created: Sat Sep 23 12:23:57 1995 ylo + * + * The main loop for the interactive session (client side). + * + */ -clientloop.c - -Author: Tatu Ylonen - -Copyright (c) 1995 Tatu Ylonen , Espoo, Finland - All rights reserved - - -Created: Sat Sep 23 12:23:57 1995 ylo - -The main loop for the interactive session (client side). - -*/ - #include "includes.h" -RCSID("$Id: clientloop.c,v 1.7 1999/10/16 20:57:52 deraadt Exp $"); +RCSID("$Id: clientloop.c,v 1.14 1999/12/06 20:15:26 deraadt Exp $"); #include "xmalloc.h" #include "ssh.h" #include "packet.h" #include "buffer.h" #include "authfd.h" - -/* Flag indicating whether quiet mode is on. */ -extern int quiet_flag; +#include "readconf.h" /* Flag indicating that stdin should be redirected from /dev/null. */ extern int stdin_null_flag; -/* Name of the host we are connecting to. This is the name given on the - command line, or the HostName specified for the user-supplied name - in a configuration file. */ +/* + * Name of the host we are connecting to. This is the name given on the + * command line, or the HostName specified for the user-supplied name in a + * configuration file. + */ extern char *host; -/* Flag to indicate that we have received a window change signal which has - not yet been processed. This will cause a message indicating the new - window size to be sent to the server a little later. This is volatile - because this is updated in a signal handler. */ +/* + * Flag to indicate that we have received a window change signal which has + * not yet been processed. This will cause a message indicating the new + * window size to be sent to the server a little later. This is volatile + * because this is updated in a signal handler. + */ static volatile int received_window_change_signal = 0; /* Terminal modes, as saved by enter_raw_mode. */ static struct termios saved_tio; -/* Flag indicating whether we are in raw mode. This is used by enter_raw_mode - and leave_raw_mode. */ +/* + * Flag indicating whether we are in raw mode. This is used by + * enter_raw_mode and leave_raw_mode. + */ static int in_raw_mode = 0; /* Flag indicating whether the user\'s terminal is in non-blocking mode. */ static int in_non_blocking_mode = 0; /* Common data for the client loop code. */ -static int escape_pending; /* Last character was the escape character */ -static int last_was_cr; /* Last character was a newline. */ -static int exit_status; /* Used to store the exit status of the command. */ -static int stdin_eof; /* EOF has been encountered on standard error. */ -static Buffer stdin_buffer; /* Buffer for stdin data. */ -static Buffer stdout_buffer; /* Buffer for stdout data. */ -static Buffer stderr_buffer; /* Buffer for stderr data. */ -static unsigned int buffer_high; /* Soft max buffer size. */ -static int max_fd; /* Maximum file descriptor number in select(). */ -static int connection_in; /* Connection to server (input). */ -static int connection_out; /* Connection to server (output). */ +static int escape_pending; /* Last character was the escape character */ +static int last_was_cr; /* Last character was a newline. */ +static int exit_status; /* Used to store the exit status of the command. */ +static int stdin_eof; /* EOF has been encountered on standard error. */ +static Buffer stdin_buffer; /* Buffer for stdin data. */ +static Buffer stdout_buffer; /* Buffer for stdout data. */ +static Buffer stderr_buffer; /* Buffer for stderr data. */ +static unsigned int buffer_high;/* Soft max buffer size. */ +static int max_fd; /* Maximum file descriptor number in select(). */ +static int connection_in; /* Connection to server (input). */ +static int connection_out; /* Connection to server (output). */ static unsigned long stdin_bytes, stdout_bytes, stderr_bytes; -static int quit_pending; /* Set to non-zero to quit the client loop. */ -static int escape_char; /* Escape character. */ +static int quit_pending; /* Set to non-zero to quit the client loop. */ +static int escape_char; /* Escape character. */ -/* Returns the user\'s terminal to normal mode if it had been put in raw - mode. */ +/* Returns the user\'s terminal to normal mode if it had been put in raw mode. */ -void leave_raw_mode() +void +leave_raw_mode() { - if (!in_raw_mode) - return; - in_raw_mode = 0; - if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0) - perror("tcsetattr"); + if (!in_raw_mode) + return; + in_raw_mode = 0; + if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0) + perror("tcsetattr"); - fatal_remove_cleanup((void (*)(void *))leave_raw_mode, NULL); + fatal_remove_cleanup((void (*) (void *)) leave_raw_mode, NULL); } /* Puts the user\'s terminal in raw mode. */ -void enter_raw_mode() +void +enter_raw_mode() { - struct termios tio; + struct termios tio; - if (tcgetattr(fileno(stdin), &tio) < 0) - perror("tcgetattr"); - saved_tio = tio; - tio.c_iflag |= IGNPAR; - tio.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF); - tio.c_lflag &= ~(ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHONL); + if (tcgetattr(fileno(stdin), &tio) < 0) + perror("tcgetattr"); + saved_tio = tio; + tio.c_iflag |= IGNPAR; + tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); + tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL); #ifdef IEXTEN - tio.c_lflag &= ~IEXTEN; -#endif /* IEXTEN */ - tio.c_oflag &= ~OPOST; - tio.c_cc[VMIN] = 1; - tio.c_cc[VTIME] = 0; - if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0) - perror("tcsetattr"); - in_raw_mode = 1; + tio.c_lflag &= ~IEXTEN; +#endif /* IEXTEN */ + tio.c_oflag &= ~OPOST; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0) + perror("tcsetattr"); + in_raw_mode = 1; + + fatal_add_cleanup((void (*) (void *)) leave_raw_mode, NULL); +} - fatal_add_cleanup((void (*)(void *))leave_raw_mode, NULL); -} +/* Restores stdin to blocking mode. */ +void +leave_non_blocking() +{ + if (in_non_blocking_mode) { + (void) fcntl(fileno(stdin), F_SETFL, 0); + in_non_blocking_mode = 0; + fatal_remove_cleanup((void (*) (void *)) leave_non_blocking, NULL); + } +} + /* Puts stdin terminal in non-blocking mode. */ -/* Restores stdin to blocking mode. */ +void +enter_non_blocking() +{ + in_non_blocking_mode = 1; + (void) fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); + fatal_add_cleanup((void (*) (void *)) leave_non_blocking, NULL); +} + +/* + * Signal handler for the window change signal (SIGWINCH). This just sets a + * flag indicating that the window has changed. + */ + +void +window_change_handler(int sig) +{ + received_window_change_signal = 1; + signal(SIGWINCH, window_change_handler); +} + +/* + * Signal handler for signals that cause the program to terminate. These + * signals must be trapped to restore terminal modes. + */ + +void +signal_handler(int sig) +{ + if (in_raw_mode) + leave_raw_mode(); + if (in_non_blocking_mode) + leave_non_blocking(); + channel_stop_listening(); + packet_close(); + fatal("Killed by signal %d.", sig); +} + +/* + * Returns current time in seconds from Jan 1, 1970 with the maximum + * available resolution. + */ + +double +get_current_time() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; +} + +/* + * This is called when the interactive is entered. This checks if there is + * an EOF coming on stdin. We must check this explicitly, as select() does + * not appear to wake up when redirecting from /dev/null. + */ + +void +client_check_initial_eof_on_stdin() +{ + int len; + char buf[1]; + + /* + * If standard input is to be "redirected from /dev/null", we simply + * mark that we have seen an EOF and send an EOF message to the + * server. Otherwise, we try to read a single character; it appears + * that for some files, such /dev/null, select() never wakes up for + * read for this descriptor, which means that we never get EOF. This + * way we will get the EOF if stdin comes from /dev/null or similar. + */ + if (stdin_null_flag) { + /* Fake EOF on stdin. */ + debug("Sending eof."); + stdin_eof = 1; + packet_start(SSH_CMSG_EOF); + packet_send(); + } else { + enter_non_blocking(); + + /* Check for immediate EOF on stdin. */ + len = read(fileno(stdin), buf, 1); + if (len == 0) { + /* EOF. Record that we have seen it and send EOF to server. */ + debug("Sending eof."); + stdin_eof = 1; + packet_start(SSH_CMSG_EOF); + packet_send(); + } else if (len > 0) { + /* + * Got data. We must store the data in the buffer, + * and also process it as an escape character if + * appropriate. + */ + if ((unsigned char) buf[0] == escape_char) + escape_pending = 1; + else { + buffer_append(&stdin_buffer, buf, 1); + stdin_bytes += 1; + } + } + leave_non_blocking(); + } +} + +/* + * Get packets from the connection input buffer, and process them as long as + * there are packets available. + */ + +void +client_process_buffered_input_packets() +{ + int type; + char *data; + unsigned int data_len; + int payload_len; + + /* Process any buffered packets from the server. */ + while (!quit_pending && + (type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) { + switch (type) { + + case SSH_SMSG_STDOUT_DATA: + data = packet_get_string(&data_len); + packet_integrity_check(payload_len, 4 + data_len, type); + buffer_append(&stdout_buffer, data, data_len); + stdout_bytes += data_len; + memset(data, 0, data_len); + xfree(data); + break; + + case SSH_SMSG_STDERR_DATA: + data = packet_get_string(&data_len); + packet_integrity_check(payload_len, 4 + data_len, type); + buffer_append(&stderr_buffer, data, data_len); + stdout_bytes += data_len; + memset(data, 0, data_len); + xfree(data); + break; + + case SSH_SMSG_EXITSTATUS: + packet_integrity_check(payload_len, 4, type); + exit_status = packet_get_int(); + /* Acknowledge the exit. */ + packet_start(SSH_CMSG_EXIT_CONFIRMATION); + packet_send(); + /* + * Must wait for packet to be sent since we are + * exiting the loop. + */ + packet_write_wait(); + /* Flag that we want to exit. */ + quit_pending = 1; + break; + + case SSH_SMSG_X11_OPEN: + x11_input_open(payload_len); + break; + + case SSH_MSG_PORT_OPEN: + channel_input_port_open(payload_len); + break; + + case SSH_SMSG_AGENT_OPEN: + packet_integrity_check(payload_len, 4, type); + auth_input_open_request(); + break; + + case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: + packet_integrity_check(payload_len, 4 + 4, type); + channel_input_open_confirmation(); + break; + + case SSH_MSG_CHANNEL_OPEN_FAILURE: + packet_integrity_check(payload_len, 4, type); + channel_input_open_failure(); + break; + + case SSH_MSG_CHANNEL_DATA: + channel_input_data(payload_len); + break; + + case SSH_MSG_CHANNEL_CLOSE: + packet_integrity_check(payload_len, 4, type); + channel_input_close(); + break; + + case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION: + packet_integrity_check(payload_len, 4, type); + channel_input_close_confirmation(); + break; + + default: + /* + * Any unknown packets received during the actual + * session cause the session to terminate. This is + * intended to make debugging easier since no + * confirmations are sent. Any compatible protocol + * extensions must be negotiated during the + * preparatory phase. + */ + packet_disconnect("Protocol error during session: type %d", + type); + } + } +} + +/* + * Make packets from buffered stdin data, and buffer them for sending to the + * connection. + */ + +void +client_make_packets_from_stdin_data() +{ + unsigned int len; + + /* Send buffered stdin data to the server. */ + while (buffer_len(&stdin_buffer) > 0 && + packet_not_very_much_data_to_write()) { + len = buffer_len(&stdin_buffer); + /* Keep the packets at reasonable size. */ + if (len > packet_get_maxsize()) + len = packet_get_maxsize(); + packet_start(SSH_CMSG_STDIN_DATA); + packet_put_string(buffer_ptr(&stdin_buffer), len); + packet_send(); + buffer_consume(&stdin_buffer, len); + /* If we have a pending EOF, send it now. */ + if (stdin_eof && buffer_len(&stdin_buffer) == 0) { + packet_start(SSH_CMSG_EOF); + packet_send(); + } + } +} + +/* + * Checks if the client window has changed, and sends a packet about it to + * the server if so. The actual change is detected elsewhere (by a software + * interrupt on Unix); this just checks the flag and sends a message if + * appropriate. + */ + +void +client_check_window_change() +{ + /* Send possible window change message to the server. */ + if (received_window_change_signal) { + struct winsize ws; + + /* Clear the window change indicator. */ + received_window_change_signal = 0; + + /* Read new window size. */ + if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) { + /* Successful, send the packet now. */ + packet_start(SSH_CMSG_WINDOW_SIZE); + packet_put_int(ws.ws_row); + packet_put_int(ws.ws_col); + packet_put_int(ws.ws_xpixel); + packet_put_int(ws.ws_ypixel); + packet_send(); + } + } +} + +/* + * Waits until the client can do something (some data becomes available on + * one of the file descriptors). + */ + +void +client_wait_until_can_do_something(fd_set * readset, fd_set * writeset) +{ + /* Initialize select masks. */ + FD_ZERO(readset); + + /* Read from the connection, unless our buffers are full. */ + if (buffer_len(&stdout_buffer) < buffer_high && + buffer_len(&stderr_buffer) < buffer_high && + channel_not_very_much_buffered_data()) + FD_SET(connection_in, readset); + + /* + * Read from stdin, unless we have seen EOF or have very much + * buffered data to send to the server. + */ + if (!stdin_eof && packet_not_very_much_data_to_write()) + FD_SET(fileno(stdin), readset); + + FD_ZERO(writeset); + + /* Add any selections by the channel mechanism. */ + channel_prepare_select(readset, writeset); + + /* Select server connection if have data to write to the server. */ + if (packet_have_data_to_write()) + FD_SET(connection_out, writeset); + + /* Select stdout if have data in buffer. */ + if (buffer_len(&stdout_buffer) > 0) + FD_SET(fileno(stdout), writeset); + + /* Select stderr if have data in buffer. */ + if (buffer_len(&stderr_buffer) > 0) + FD_SET(fileno(stderr), writeset); + + /* Update maximum file descriptor number, if appropriate. */ + if (channel_max_fd() > max_fd) + max_fd = channel_max_fd(); + + /* + * Wait for something to happen. This will suspend the process until + * some selected descriptor can be read, written, or has some other + * event pending. Note: if you want to implement SSH_MSG_IGNORE + * messages to fool traffic analysis, this might be the place to do + * it: just have a random timeout for the select, and send a random + * SSH_MSG_IGNORE packet when the timeout expires. + */ + + if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) { + char buf[100]; + /* Some systems fail to clear these automatically. */ + FD_ZERO(readset); + FD_ZERO(writeset); + if (errno == EINTR) + return; + /* Note: we might still have data in the buffers. */ + snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); + buffer_append(&stderr_buffer, buf, strlen(buf)); + stderr_bytes += strlen(buf); + quit_pending = 1; + } +} -void leave_non_blocking() +void +client_suspend_self() { - if (in_non_blocking_mode) - { - (void)fcntl(fileno(stdin), F_SETFL, 0); - in_non_blocking_mode = 0; - fatal_remove_cleanup((void (*)(void *))leave_non_blocking, NULL); - } -} - -void enter_non_blocking() -{ - in_non_blocking_mode = 1; - (void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); - fatal_add_cleanup((void (*)(void *))leave_non_blocking, NULL); -} - -/* Signal handler for the window change signal (SIGWINCH). This just - sets a flag indicating that the window has changed. */ - -void window_change_handler(int sig) -{ - received_window_change_signal = 1; - signal(SIGWINCH, window_change_handler); -} - -/* Signal handler for signals that cause the program to terminate. These - signals must be trapped to restore terminal modes. */ - -void signal_handler(int sig) -{ - if (in_raw_mode) - leave_raw_mode(); - if (in_non_blocking_mode) - leave_non_blocking(); - channel_stop_listening(); - packet_close(); - fatal("Killed by signal %d.", sig); -} - -/* Returns current time in seconds from Jan 1, 1970 with the maximum available - resolution. */ - -double get_current_time() -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; -} - -/* This is called when the interactive is entered. This checks if there - is an EOF coming on stdin. We must check this explicitly, as select() - does not appear to wake up when redirecting from /dev/null. */ - -void client_check_initial_eof_on_stdin() -{ - int len; - char buf[1]; - - /* If standard input is to be "redirected from /dev/null", we simply - mark that we have seen an EOF and send an EOF message to the server. - Otherwise, we try to read a single character; it appears that for some - files, such /dev/null, select() never wakes up for read for this - descriptor, which means that we never get EOF. This way we will get - the EOF if stdin comes from /dev/null or similar. */ - if (stdin_null_flag) - { - /* Fake EOF on stdin. */ - debug("Sending eof."); - stdin_eof = 1; - packet_start(SSH_CMSG_EOF); - packet_send(); - } - else - { - /* Enter non-blocking mode for stdin. */ - enter_non_blocking(); - - /* Check for immediate EOF on stdin. */ - len = read(fileno(stdin), buf, 1); - if (len == 0) - { - /* EOF. Record that we have seen it and send EOF to server. */ - debug("Sending eof."); - stdin_eof = 1; - packet_start(SSH_CMSG_EOF); - packet_send(); - } - else - if (len > 0) - { - /* Got data. We must store the data in the buffer, and also - process it as an escape character if appropriate. */ - if ((unsigned char)buf[0] == escape_char) - escape_pending = 1; - else - { - buffer_append(&stdin_buffer, buf, 1); - stdin_bytes += 1; - } - } - - /* Leave non-blocking mode. */ - leave_non_blocking(); - } -} - -/* Get packets from the connection input buffer, and process them as long - as there are packets available. */ - -void client_process_buffered_input_packets() -{ - int type; - char *data; - unsigned int data_len; - int payload_len; - - /* Process any buffered packets from the server. */ - while (!quit_pending && (type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) - { - switch (type) - { - - case SSH_SMSG_STDOUT_DATA: - data = packet_get_string(&data_len); - packet_integrity_check(payload_len, 4 + data_len, type); - buffer_append(&stdout_buffer, data, data_len); - stdout_bytes += data_len; - memset(data, 0, data_len); - xfree(data); - break; - - case SSH_SMSG_STDERR_DATA: - data = packet_get_string(&data_len); - packet_integrity_check(payload_len, 4 + data_len, type); - buffer_append(&stderr_buffer, data, data_len); - stdout_bytes += data_len; - memset(data, 0, data_len); - xfree(data); - break; - - case SSH_SMSG_EXITSTATUS: - packet_integrity_check(payload_len, 4, type); - exit_status = packet_get_int(); - /* Acknowledge the exit. */ - packet_start(SSH_CMSG_EXIT_CONFIRMATION); - packet_send(); - /* Must wait for packet to be sent since we are exiting the - loop. */ - packet_write_wait(); - /* Flag that we want to exit. */ - quit_pending = 1; - break; - - case SSH_SMSG_X11_OPEN: - x11_input_open(payload_len); - break; - - case SSH_MSG_PORT_OPEN: - channel_input_port_open(payload_len); - break; - - case SSH_SMSG_AGENT_OPEN: - packet_integrity_check(payload_len, 4, type); - auth_input_open_request(); - break; - - case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: - packet_integrity_check(payload_len, 4 + 4, type); - channel_input_open_confirmation(); - break; - - case SSH_MSG_CHANNEL_OPEN_FAILURE: - packet_integrity_check(payload_len, 4, type); - channel_input_open_failure(); - break; - - case SSH_MSG_CHANNEL_DATA: - channel_input_data(payload_len); - break; - - case SSH_MSG_CHANNEL_CLOSE: - packet_integrity_check(payload_len, 4, type); - channel_input_close(); - break; - - case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION: - packet_integrity_check(payload_len, 4, type); - channel_input_close_confirmation(); - break; - - default: - /* Any unknown packets received during the actual session - cause the session to terminate. This is intended to make - debugging easier since no confirmations are sent. Any - compatible protocol extensions must be negotiated during - the preparatory phase. */ - packet_disconnect("Protocol error during session: type %d", - type); - } - } -} - -/* Make packets from buffered stdin data, and buffer them for sending to - the connection. */ - -void client_make_packets_from_stdin_data() -{ - unsigned int len; - - /* Send buffered stdin data to the server. */ - while (buffer_len(&stdin_buffer) > 0 && - packet_not_very_much_data_to_write()) - { - len = buffer_len(&stdin_buffer); - if (len > 32768) - len = 32768; /* Keep the packets at reasonable size. */ - packet_start(SSH_CMSG_STDIN_DATA); - packet_put_string(buffer_ptr(&stdin_buffer), len); - packet_send(); - buffer_consume(&stdin_buffer, len); - /* If we have a pending EOF, send it now. */ - if (stdin_eof && buffer_len(&stdin_buffer) == 0) - { - packet_start(SSH_CMSG_EOF); - packet_send(); - } - } -} - -/* Checks if the client window has changed, and sends a packet about it to - the server if so. The actual change is detected elsewhere (by a software - interrupt on Unix); this just checks the flag and sends a message if - appropriate. */ - -void client_check_window_change() -{ - /* Send possible window change message to the server. */ - if (received_window_change_signal) - { - struct winsize ws; - - /* Clear the window change indicator. */ - received_window_change_signal = 0; - - /* Read new window size. */ - if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) >= 0) - { - /* Successful, send the packet now. */ - packet_start(SSH_CMSG_WINDOW_SIZE); - packet_put_int(ws.ws_row); - packet_put_int(ws.ws_col); - packet_put_int(ws.ws_xpixel); - packet_put_int(ws.ws_ypixel); - packet_send(); - } - } -} - -/* Waits until the client can do something (some data becomes available on - one of the file descriptors). */ - -void client_wait_until_can_do_something(fd_set *readset, fd_set *writeset) -{ - /* Initialize select masks. */ - FD_ZERO(readset); - - /* Read from the connection, unless our buffers are full. */ - if (buffer_len(&stdout_buffer) < buffer_high && - buffer_len(&stderr_buffer) < buffer_high && - channel_not_very_much_buffered_data()) - FD_SET(connection_in, readset); - - /* Read from stdin, unless we have seen EOF or have very much buffered - data to send to the server. */ - if (!stdin_eof && packet_not_very_much_data_to_write()) - FD_SET(fileno(stdin), readset); - - FD_ZERO(writeset); - - /* Add any selections by the channel mechanism. */ - channel_prepare_select(readset, writeset); - - /* Select server connection if have data to write to the server. */ - if (packet_have_data_to_write()) - FD_SET(connection_out, writeset); - - /* Select stdout if have data in buffer. */ - if (buffer_len(&stdout_buffer) > 0) - FD_SET(fileno(stdout), writeset); - - /* Select stderr if have data in buffer. */ - if (buffer_len(&stderr_buffer) > 0) - FD_SET(fileno(stderr), writeset); - - /* Update maximum file descriptor number, if appropriate. */ - if (channel_max_fd() > max_fd) - max_fd = channel_max_fd(); - - /* Wait for something to happen. This will suspend the process until - some selected descriptor can be read, written, or has some other - event pending. Note: if you want to implement SSH_MSG_IGNORE - messages to fool traffic analysis, this might be the place to do - it: just have a random timeout for the select, and send a random - SSH_MSG_IGNORE packet when the timeout expires. */ - if (select(max_fd + 1, readset, writeset, NULL, NULL) < 0) - { - char buf[100]; - /* Some systems fail to clear these automatically. */ - FD_ZERO(readset); - FD_ZERO(writeset); - if (errno == EINTR) - return; - /* Note: we might still have data in the buffers. */ - snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); - buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); - quit_pending = 1; - } -} - -void client_suspend_self() -{ - struct winsize oldws, newws; - - /* Flush stdout and stderr buffers. */ - if (buffer_len(&stdout_buffer) > 0) - write(fileno(stdout), - buffer_ptr(&stdout_buffer), - buffer_len(&stdout_buffer)); - if (buffer_len(&stderr_buffer) > 0) - write(fileno(stderr), - buffer_ptr(&stderr_buffer), - buffer_len(&stderr_buffer)); - - /* Leave raw mode. */ - leave_raw_mode(); - - /* Free (and clear) the buffer to reduce the - amount of data that gets written to swap. */ - buffer_free(&stdin_buffer); - buffer_free(&stdout_buffer); - buffer_free(&stderr_buffer); - - /* Save old window size. */ - ioctl(fileno(stdin), TIOCGWINSZ, &oldws); - - /* Send the suspend signal to the program - itself. */ - kill(getpid(), SIGTSTP); - - /* Check if the window size has changed. */ - if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 && - (oldws.ws_row != newws.ws_row || oldws.ws_col != newws.ws_col || - oldws.ws_xpixel != newws.ws_xpixel || - oldws.ws_ypixel != newws.ws_ypixel)) - received_window_change_signal = 1; - - /* OK, we have been continued by the user. - Reinitialize buffers. */ - buffer_init(&stdin_buffer); - buffer_init(&stdout_buffer); - buffer_init(&stderr_buffer); - - /* Re-enter raw mode. */ - enter_raw_mode(); -} - -void client_process_input(fd_set *readset) -{ - int len, pid; - char buf[8192], *s; - - /* Read input from the server, and add any such data to the buffer of the - packet subsystem. */ - if (FD_ISSET(connection_in, readset)) - { - /* Read as much as possible. */ - len = read(connection_in, buf, sizeof(buf)); - if (len == 0) - { - /* Received EOF. The remote host has closed the connection. */ - snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", - host); - buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); - quit_pending = 1; - return; - } - - /* There is a kernel bug on Solaris that causes select to sometimes - wake up even though there is no data available. */ - if (len < 0 && errno == EAGAIN) - len = 0; - - if (len < 0) - { - /* An error has encountered. Perhaps there is a network - problem. */ - snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", - host, strerror(errno)); - buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); - quit_pending = 1; - return; - } - packet_process_incoming(buf, len); - } - - /* Read input from stdin. */ - if (FD_ISSET(fileno(stdin), readset)) - { - /* Read as much as possible. */ - len = read(fileno(stdin), buf, sizeof(buf)); - if (len <= 0) - { - /* Received EOF or error. They are treated similarly, - except that an error message is printed if it was - an error condition. */ - if (len < 0) - { - snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); - buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); - } - /* Mark that we have seen EOF. */ - stdin_eof = 1; - /* Send an EOF message to the server unless there is data - in the buffer. If there is data in the buffer, no message - will be sent now. Code elsewhere will send the EOF - when the buffer becomes empty if stdin_eof is set. */ - if (buffer_len(&stdin_buffer) == 0) - { - packet_start(SSH_CMSG_EOF); - packet_send(); - } - } - else - if (escape_char == -1) - { - /* Normal successful read, and no escape character. Just - append the data to buffer. */ - buffer_append(&stdin_buffer, buf, len); - stdin_bytes += len; - } - else - { - /* Normal, successful read. But we have an escape character - and have to process the characters one by one. */ - unsigned int i; - for (i = 0; i < len; i++) - { - unsigned char ch; - /* Get one character at a time. */ - ch = buf[i]; - - /* Check if we have a pending escape character. */ - if (escape_pending) - { - /* We have previously seen an escape character. */ - /* Clear the flag now. */ - escape_pending = 0; - /* Process the escaped character. */ - switch (ch) - { - case '.': - /* Terminate the connection. */ - snprintf(buf, sizeof buf, "%c.\r\n", escape_char); + struct winsize oldws, newws; + + /* Flush stdout and stderr buffers. */ + if (buffer_len(&stdout_buffer) > 0) + atomicio(write, fileno(stdout), buffer_ptr(&stdout_buffer), + buffer_len(&stdout_buffer)); + if (buffer_len(&stderr_buffer) > 0) + atomicio(write, fileno(stderr), buffer_ptr(&stderr_buffer), + buffer_len(&stderr_buffer)); + + leave_raw_mode(); + + /* + * Free (and clear) the buffer to reduce the amount of data that gets + * written to swap. + */ + buffer_free(&stdin_buffer); + buffer_free(&stdout_buffer); + buffer_free(&stderr_buffer); + + /* Save old window size. */ + ioctl(fileno(stdin), TIOCGWINSZ, &oldws); + + /* Send the suspend signal to the program itself. */ + kill(getpid(), SIGTSTP); + + /* Check if the window size has changed. */ + if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 && + (oldws.ws_row != newws.ws_row || + oldws.ws_col != newws.ws_col || + oldws.ws_xpixel != newws.ws_xpixel || + oldws.ws_ypixel != newws.ws_ypixel)) + received_window_change_signal = 1; + + /* OK, we have been continued by the user. Reinitialize buffers. */ + buffer_init(&stdin_buffer); + buffer_init(&stdout_buffer); + buffer_init(&stderr_buffer); + + enter_raw_mode(); +} + +void +client_process_input(fd_set * readset) +{ + int len, pid; + char buf[8192], *s; + + /* + * Read input from the server, and add any such data to the buffer of + * the packet subsystem. + */ + if (FD_ISSET(connection_in, readset)) { + /* Read as much as possible. */ + len = read(connection_in, buf, sizeof(buf)); + if (len == 0) { + /* Received EOF. The remote host has closed the connection. */ + snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", + host); buffer_append(&stderr_buffer, buf, strlen(buf)); stderr_bytes += strlen(buf); quit_pending = 1; return; - - case 'Z' - 64: - /* Suspend the program. */ - /* Print a message to that effect to the user. */ - snprintf(buf, sizeof buf, "%c^Z\r\n", escape_char); - buffer_append(&stderr_buffer, buf, strlen(buf)); - stderr_bytes += strlen(buf); - - /* Restore terminal modes and suspend. */ - client_suspend_self(); - - /* We have been continued. */ - continue; - - case '&': - /* Detach the program (continue to serve connections, - but put in background and no more new - connections). */ - if (!stdin_eof) - { - /* Sending SSH_CMSG_EOF alone does not always - appear to be enough. So we try to send an - EOF character first. */ - packet_start(SSH_CMSG_STDIN_DATA); - packet_put_string("\004", 1); - packet_send(); - /* Close stdin. */ - stdin_eof = 1; - if (buffer_len(&stdin_buffer) == 0) - { + } + /* + * There is a kernel bug on Solaris that causes select to + * sometimes wake up even though there is no data available. + */ + if (len < 0 && errno == EAGAIN) + len = 0; + + if (len < 0) { + /* An error has encountered. Perhaps there is a network problem. */ + snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", + host, strerror(errno)); + buffer_append(&stderr_buffer, buf, strlen(buf)); + stderr_bytes += strlen(buf); + quit_pending = 1; + return; + } + packet_process_incoming(buf, len); + } + /* Read input from stdin. */ + if (FD_ISSET(fileno(stdin), readset)) { + /* Read as much as possible. */ + len = read(fileno(stdin), buf, sizeof(buf)); + if (len <= 0) { + /* + * Received EOF or error. They are treated + * similarly, except that an error message is printed + * if it was an error condition. + */ + if (len < 0) { + snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); + buffer_append(&stderr_buffer, buf, strlen(buf)); + stderr_bytes += strlen(buf); + } + /* Mark that we have seen EOF. */ + stdin_eof = 1; + /* + * Send an EOF message to the server unless there is + * data in the buffer. If there is data in the + * buffer, no message will be sent now. Code + * elsewhere will send the EOF when the buffer + * becomes empty if stdin_eof is set. + */ + if (buffer_len(&stdin_buffer) == 0) { packet_start(SSH_CMSG_EOF); packet_send(); - } - } - /* Restore tty modes. */ - leave_raw_mode(); - - /* Stop listening for new connections. */ - channel_stop_listening(); - - printf("%c& [backgrounded]\n", escape_char); - - /* Fork into background. */ - pid = fork(); - if (pid < 0) - { - error("fork: %.100s", strerror(errno)); - continue; - } - if (pid != 0) - { /* This is the parent. */ - /* The parent just exits. */ - exit(0); - } - - /* The child continues serving connections. */ - continue; - - case '?': - snprintf(buf, sizeof buf, "%c?\r\n\ + } + } else if (escape_char == -1) { + /* + * Normal successful read, and no escape character. + * Just append the data to buffer. + */ + buffer_append(&stdin_buffer, buf, len); + stdin_bytes += len; + } else { + /* + * Normal, successful read. But we have an escape character + * and have to process the characters one by one. + */ + unsigned int i; + for (i = 0; i < len; i++) { + unsigned char ch; + /* Get one character at a time. */ + ch = buf[i]; + + if (escape_pending) { + /* We have previously seen an escape character. */ + /* Clear the flag now. */ + escape_pending = 0; + /* Process the escaped character. */ + switch (ch) { + case '.': + /* Terminate the connection. */ + snprintf(buf, sizeof buf, "%c.\r\n", escape_char); + buffer_append(&stderr_buffer, buf, strlen(buf)); + stderr_bytes += strlen(buf); + quit_pending = 1; + return; + + case 'Z' - 64: + /* Suspend the program. */ + /* Print a message to that effect to