diff options
106 files changed, 44172 insertions, 0 deletions
diff --git a/usr.bin/ssh/COPYING.Ylonen b/usr.bin/ssh/COPYING.Ylonen new file mode 100644 index 00000000000..73d3ecaa7b1 --- /dev/null +++ b/usr.bin/ssh/COPYING.Ylonen @@ -0,0 +1,220 @@ +This file is part of the ssh software, Copyright (c) 1995 Tatu Ylonen, Finland + + +COPYING POLICY AND OTHER LEGAL ISSUES + +As far as I am concerned, the code I have written for this software +can be used freely for any purpose. Any derived versions of this +software must be clearly marked as such, and if the derived work is +incompatible with the protocol description in the RFC file, it must be +called by a name other than "ssh" or "Secure Shell". + +However, I am not implying to give any licenses to any patents or +copyrights held by third parties, and the software includes parts that +are not under my direct control. As far as I know, all included +source code is used in accordance with the relevant license agreements +and can be used freely for any purpose (the GNU license being the most +restrictive); see below for details. + +[ IDEA is now *only* included if configured with --with-rsa. ] +The RSA algorithm and even the concept of public key encryption are +claimed to patented in the United States. These patents may interfere +with your right to use this software. It is possible to compile the +software using the RSAREF2 library by giving --with-rsaref on the +configure command line. This may or may not make it legal to use this +software for non-commercial purposes in the United States (I have sent +a query about this to RSADSI (on July 10, 1995), but have not received +an answer yet). The RSAREF2 distribution is not included in this +distribution, but can be obtained from almost any ftp site worldwide +containing cryptographic materials. Using RSAREF is not recommended +outside the United States. See "http://www.cs.hut.fi/crypto" if you +have trouble finding the RSAREF library. + +[ IDEA is now *only* included if configured with --with-idea. ] +The IDEA algorithm is claimed to be patented in the United States and +several other countries. I have been told by Ascom-Tech (the patent +holder) that IDEA can be used freely for non-commercial use. A copy +of their letter is at the end. The software can be compiled without +IDEA by specifying the --without-idea option on the configure command +line. + +[ All these files are now external to the distribution. ] +The DES implementation in this distribution is derived from the libdes +library by Eric Young <eay@mincom.oz.au>. It can be used under the +Gnu General Public License (libdes-COPYING) or the Artistic License +(libdes-ARTISTIC), at your option. See libdes-README for more +information. Eric Young has kindly given permission to distribute the +derived version under these terms. The file crypt.c is fcrypt.c from +SSLeay-0.4.3a by Eric Young; he permits free use. + +[ GMP is no longer part of the distribution. ] +The GNU Multiple Precision Library, included in this release and +linked into the executable, is distributed under the GNU General +Public License. A copy can be found in gmp-1.3.2/COPYING. + +[ Zlib is no longer part of the distribution. ] +The zlib compression library is copyright Jean-loup Gailly and Mark +Adler. Anyone is permitted to use the library for any purpose. A +copy of the license conditions can be found in zlib095/README. + +[ This script is no longer part of the distribution. ] +The make-ssh-known-hosts script was contributed by Tero Kivinen +<kivinen@niksula.hut.fi> and is distributed under the GNU General +Public License. A copy can be found in gnu-COPYING-GPL. + +Some files, such as memmove.c and random.c, are owned by the Regents +of the University of California, and can be freely used and +distributed. License terms are included in the affected files. The +file scp.c is derived from code owned by the Regents of the University +of California, and can be used freely. + +[ TSS has been removed from the distribution. ] +The TSS encryption algorithm implementation in tss.c is copyright Timo +Rinne <tri@iki.fi> and Cirion Oy. It is used with permission, and +permission has been given for anyone to use it for any purpose as part +of ssh. + +The MD5 implementation in md5.c was taken from PGP and is due to Colin +Plumb. Comments in the file indicate that it is in the public domain. + +The 32-bit CRC implementation in crc32.c is due to Gary S. Brown. +Comments in the file indicate it may be used for any purpose without +restrictions. + + +In some countries, particularly France, Russia, Iraq, and Pakistan, it +may be illegal to use any encryption at all without a special permit, +and the rumor is that you cannot get a permit for any strong +encryption. + +If you are in the United States, you should be aware that while this +software was written outside the United States using information +publicly available everywhere, the United States Government may +consider it a criminal offence to export this software from the United +States once it has been imported. I have been told that "the federal +mandatory sentencing guidelines for this offence are 41 to 51 months +in federal prison". The rumor is that the government considers +putting the software available on an ftp site the same as exporting +it. Contact the Office of Defence Trade Controls if you need more +information. Also, please write to your congress and senate +representatives to get these silly and unconstitutional restrictions +dropped. + +Note that any information and cryptographic algorithms used in this +software are publicly available on the Internet and at any major +bookstore, scientific library, and patent office worldwide. More +information can be found e.g. at "http://www.cs.hut.fi/crypto". + +The legal status of this program is some combination of all these +permissions and restrictions. Use only at your own responsibility. +You will be responsible for any legal consequences yourself; I am not +making any claims whether possessing or using this is legal or not in +your country, and I am not taking any responsibility on your behalf. + + + NO WARRANTY + +BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +--------------------------------------------------------------------------- +Below is a copy of a message I received from Ascom, the holder of the IDEA +patent. + +Date: Tue, 15 Aug 95 09:09:59 CET +From: IDEA@ascom.ch (Licensing Systec) +Encoding: 3001 Text +To: ylo@cs.hut.fi +Subject: Phone Call 15.8.95 + + Dear Mr. Ylonen + + Thank you for your inquiry about the IDEA encryption algorithm. + Please excuse the delay in answering your fax sent 26.6.95. + Here is the information you requested : + + Non commercial use of IDEA is free. The following examples (regarding + PGP) should clarify what we mean by commercial and non-commercial use + + Here are some examples of commercial use of PGP: + + 1. When PGP is used for signing and/or encrypting e-mail messages + exchanged between two corporations. + + 2. When a consultant uses PGP for his communications with his client + corporations. + + 3. When a bank makes PGP available to its clients for telebanking and + charges them money for it (directly or indirectly). + + 4. When you use the software you receive from a company for commercial + purposes (telebanking included). + + + Some examples of non commercial use: + + 1. When an individual uses PGP for his private communications. + + 2. When an individual obtains PGP on the Internet and uses it for + telebanking (assuming this is approved by the bank). + + 3. When you use the software you receive from a company for private + purposes (telebanking excluded). + + + You may use IDEA freely within your software for non commercial use. + If you include IDEA in your software, it must include the following + copy right statement : + + 1. Copyright and Licensing Statement + IDEA(tm) is a trademark of Ascom Systec AG. There is no license fee + required for non-commercial use. Commercial users of IDEA may + obtain licensing information from Ascom Systec AG. + e-mail: IDEA@ascom.ch + fax: ++41 64 56 59 54 + + + For selling the software commercially a product license is required: + + The PRODUCT LICENSE gives a software developer the right to implement + IDEA in a software product and to sell this product worldwide. With + the PRODUCT LICENSE we supply a source listing in C and a software + manual. We charge an initial fee per company and a percentage of sales + of the software product or products (typically between .5 and 4 per + cent of the sales price, depending on the price and the importance of + IDEA for the product). + + + For further information please do not hesitate to contact us. + + Best regards, + + Roland Weinhart + + + Ascom Systec Ltd + IDEA Licensing @@@@@ @@@@@ @@@@@ @@@@@ @@@@@@@ + Gewerbepark @ @ @ @ @ @ @ @ + CH-5506 Maegenwil @@@@@ @@@@@ @ @ @ @ @ @ + Switzerland @ @ @ @ @ @ @ @ @ + Phone ++41 64 56 59 54 @@@@@ @@@@@ @@@@@ @@@@@ @ @ @ + Fax ++41 64 56 59 98 + + diff --git a/usr.bin/ssh/ChangeLog b/usr.bin/ssh/ChangeLog new file mode 100644 index 00000000000..08d90f78d31 --- /dev/null +++ b/usr.bin/ssh/ChangeLog @@ -0,0 +1,578 @@ +Fri Nov 17 16:19:20 1995 Tatu Ylonen <ylo@trance.olari.clinet.fi> + + * 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 <ylo@trance.olari.clinet.fi> + + * 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 <ylo@trance.olari.clinet.fi> + + * 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 <argon@bat.cs.hut.fi>). + + * 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 <ylo@soikko.cs.hut.fi> + + * sshd.c: Permit immediate login with empty password only if + password authentication is allowed. + +Wed Nov 8 00:43:55 1995 Tatu Ylonen <ylo@soikko.cs.hut.fi> + + * 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 <ylo@soikko.cs.hut.fi> + + * 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 <ylo@soikko.cs.hut.fi> + + * (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 <ylo@soikko.cs.hut.fi> + + * ssh.1.in: Added more information about X11 forwarding. + +Thu Nov 2 18:42:13 1995 Tatu Ylonen <ylo@soikko.cs.hut.fi> + + * 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 <ylo@soikko.cs.hut.fi> + + * 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 <ylo@soikko.cs.hut.fi> + + * 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 <ylo@soikko.cs.hut.fi> + + * 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 <ylo@soikko.cs.hut.fi> + + * 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 <ylo@soikko.cs.hut.fi> + + * Implemented ProxyCommand stuff based on patches from Bryan + O'Sullivan <bos@serpentine.com>. + + * Merged BSD login/logout/lastlog patches from Mark Treacy + <mark@labtam.oz.au>. + + * sshd.c: Added chdir("/"). + +Tue Oct 24 00:29:01 1995 Tatu Ylonen <ylo@soikko.cs.hut.fi> + + * Merged RSA environment= patches from Felix Leitner + <leitner@prz.tu-berlin.de> 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 <ylo@soikko.cs.hut.fi> + + * sshd.c: Merged execle -> execve patches from Mark Martinec + <Mark.Martinec@nsc.ijs.si>. 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 <ylo@soikko.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * Merged /etc/default/login and MAIL environment variable changes + from Bryan O'Sullivan <bos@serpentine.com>. + - 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * Some more SCO fixes. + +Tue Oct 3 01:04:34 1995 Tatu Ylonen <ylo@shadows.cs.hut.fi> + + * Fixes and cleanups in README, INSTALL, COPYING. + +Mon Oct 2 03:36:08 1995 Tatu Ylonen <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * auth-rhosts.c: Fixed serious security problem in + /etc/hosts.equiv authentication. + +Fri Sep 29 00:41:02 1995 Tatu Ylonen <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * Merged patches for SCO Unix (from Michael Henits). + +Sun Sep 24 22:28:02 1995 Tatu Ylonen <ylo@shadows.cs.hut.fi> + + * Added ssh option ConnectionAttempts. + +Sat Sep 23 12:30:15 1995 Tatu Ylonen <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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 <ylo@shadows.cs.hut.fi> + + * 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. + diff --git a/usr.bin/ssh/INSTALL b/usr.bin/ssh/INSTALL new file mode 100644 index 00000000000..76cf2ee8902 --- /dev/null +++ b/usr.bin/ssh/INSTALL @@ -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 <ylo@cs.hut.fi>, Espoo, Finland. diff --git a/usr.bin/ssh/Makefile b/usr.bin/ssh/Makefile new file mode 100644 index 00000000000..15edbc03b8f --- /dev/null +++ b/usr.bin/ssh/Makefile @@ -0,0 +1,344 @@ +# Generated automatically from Makefile.in by configure. +# +# Makefile.in +# +# Author: Tatu Ylonen <ylo@cs.hut.fi> +# +# Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +# All rights reserved +# +# Created: Wed Mar 22 17:37:49 1995 ylo +# +# $Id: Makefile,v 1.1 1999/09/26 20:53:32 deraadt Exp $ +# + +srcdir = . + + +install_prefix = +prefix = /usr/local +exec_prefix = ${prefix} +bindir = $(exec_prefix)/bin +sbindir = $(exec_prefix)/sbin +mandir = $(prefix)/man +man1dir = $(mandir)/man1 +man8dir = $(mandir)/man8 +etcdir = /etc +piddir = /var/run + +CC = gcc -pipe +CFLAGS = -g -O2 +LDFLAGS = +DEFS = -DHAVE_CONFIG_H +LIBS = -lkrb -lz -lcrypto -ldes -lgmp -lutil +LIBOBJS = +CONFOBJS = bf_skey.o bf_enc.o compress.o + +MAKEDEP = makedepend +LN_S = ln -s +RANLIB = ranlib +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +WISH = /usr/local/bin/wish + +GMPLIBS = -lgmp +GMPINCS = + +KRB4_AUTH = +KRB4_ROOT = +KRB4_INCS = +KRB4_LIBS = +RADIX = + +RSAREFDEP = + +transform = s,x,x, + +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) diff --git a/usr.bin/ssh/Makefile.in b/usr.bin/ssh/Makefile.in new file mode 100644 index 00000000000..2f22ce010a3 --- /dev/null +++ b/usr.bin/ssh/Makefile.in @@ -0,0 +1,344 @@ +# +# Makefile.in +# +# Author: Tatu Ylonen <ylo@cs.hut.fi> +# +# Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +# All rights reserved +# +# Created: Wed Mar 22 17:37:49 1995 ylo +# +# $Id: Makefile.in,v 1.1 1999/09/26 20:53:32 deraadt Exp $ +# + +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) diff --git a/usr.bin/ssh/OVERVIEW b/usr.bin/ssh/OVERVIEW new file mode 100644 index 00000000000..3b95cda455a --- /dev/null +++ b/usr.bin/ssh/OVERVIEW @@ -0,0 +1,226 @@ +This document is inteded 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 <ylo@cs.hut.fi> +Updated 17 Nov 1995. + +The software consists of ssh (client), sshd (server), scp, sdist, and +the auxiliary programs ssh-keygen, ssh-agent, ssh-add, and +make-ssh-known-hosts. The main program for each of these is in a .c +file with the same name. + +There are some subsystems/abstractions that are used by a number of +these programs. + + Configuration + + - Ssh configures itself with "./configure" in the source + directory. The configuration system is based on GNU Autoconf. + The "configure" script is generated from configure.in using the + autoconf tool (2.4 required, plus a patch for AC_ARG_PROGRAM). + Additionally, the file config.h.in is generated from + configure.in and acconfig.h with the autoheader tool (also part + of GNU Autoconf). The configure process generates Makefile from + Makefile.in, the file config.h, and a few other files from their + respective .in files. The configure script uses the files + config.guess (to determine current host type), config.sub (to + validate given host type). It may also arrange to use the + install.sh script from the Makefile when installing programs. + + Makefile + + The Makefile (generated from Makefile.in with configure) contains the + following major targets: + + all: (default) compile all executables. + install: installs executables and manual pages; installs + configuration files and generates host key if they don't exist. + uninstall: removes installed executables and manual pages. + clean: removes object files, executables, and some temporary files. + distclean: removes all generated files ("distrigution state"). + depend: updates dependencies. + RFC: run RFC.nroff trough nroff to generate a new version of the RFC. + dist: generate a distribution ".tar.gz" file. + + Buffer manipulation routines + + - These provide an arbitrary size buffer, where data can be appended. + Data can be consumed from either end. The code is used heavily + throughout ssh. The basic buffer manipulation functions are in + buffer.c (header buffer.h), and additional code to manipulate specific + data types is in bufaux.c. + + Compression Library + + - Ssh uses the GNU GZIP compression library (ZLIB). It resides in + the zlib095 subdirectory. + + 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, idea.c, tss.c, + md5.c, rc4.c, and tss.c. + + Multiple Precision Integer Library + + - Ssh uses the GNU Multiple Precision Library (gmp). The code is in the + gmp-1.3.2 subdirectory. + + - Some auxiliary functions for mp-int manipulation are in mpaux.c. + + Random Numbers + + - The random numbers for cryptographic use are generated by using + a generator with 1024 byte pool that uses MD5 to stir the pool. + The generator acquires a little amount of new entropy every time + it stirs the pool. + + - The distribution also contains the file random.c which offers a + substitute for the BSD random() function. This function is only + refernced from the gmp library; the function where it is used is + only used in the gmp primality checking functions (ssh uses the + Fermat test in addition to the gmp primality test). + + RSA key generation, encryption, decryption + + - Ssh contains its own RSA routines. It can, however, also be compiled to + use RSAREF. The interface to RSA encryption/decryption is in rsaglue.c; + it will either call RSAREF (which must be in the rsaref2 subdirectory + if it is used - it does not come with ssh). Normally it calls functions + in rsa.c. The file rsa.c also contains prime generation code and + RSA key generation. + + RSA key files + + - RSA keys are stored in files with a special format. The code to + read/write these files is in authfile.c. The files are normally + encrypted with a passphrase. The functions to read passphrases + are in readpass.c (the same code is used to read passwords). + + Binary packet protocol + + - The ssh binary packet protocol is implemented in packet.c. The + code in packet.c does not concern itself with packet types or their + execution; it contains code to build packets, to receive them and + extract data from them, and the code to compress and/or encrypt + packets. CRC code comes from crc32.c. + + - The code in packet.c calls the buffer manipulation routines + (buffer.c, bufaux.c), compression routines (compress.c, zlib), + and the encryption routines. + + X11, TCP/IP, and Agent forwarding + + - Code for various types of channel forwarding is in channels.c. + The file defines a generic framework for arbitrary communication + channels inside the secure channel, and uses this framework to + implement X11 forwarding, TCP/IP forwarding, and authentication + agent forwarding. + + Authentication agent + + - Code to communicate with the authentication agent is in + authfd.c. The files gen-minfd.c, minfd.h, minfd.c + + Authentication methods + + - Code for various authentication methods resides in auth-*.c + (auth-passwd.c, auth-rh-rsa.c, auth-rhosts.c, auth-rsa.c). This + 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. + + - In the client end, authentication code is in sshconnect.c. It + reads Passwords/passphrases using code in readpass.c. It reads + RSA key files with authfile.c. It communicates the + authentication agent using authfd.c. + + The ssh client + + - The client main program is in ssh.c. It first parses arguments + and reads configuration (readconf.c), then calls ssh_connect (in + sshconnect.c) to open a connection to the server (possibly via a + proxy), and performs authentication (ssh_login in sshconnect.c). + It then makes any pty, forwarding, etc. requests. It may call + code in ttymodes.c to encode current tty modes. Finally it + calls client_loop in clientloop.c. This does the real work for + the session. + + - The client is suid root. It tries to temporarily give up this + rights while reading the configuration data. The root + privileges are only used to make the connection (from a + privileged socket). Any extra privileges are dropped before + calling ssh_login. + + Pseudo-tty manipulation and tty modes + + - Code to allocate and use a pseudo tty is in pty.c. Code to + encode and set terminal modes is in ttymodes.c. + + Logging in (updating utmp, lastlog, etc.) + + - The code to do things that are done when a user logs in are in + login.c. This includes things such as updating the utmp, wtmp, + and lastlog files. Some of the code is in sshd.c. + + Writing to the system log and terminal + + - The programs use the functions fatal(), log(), debug(), error() + in many places to write messages to system log or user's + terminal. The implementation that logs to system log is in + log-server.c; it is used in the server program. The other + programs use an implementation that sends output to stderr; it + is in log-client.c. The definitions are in ssh.h. + + The sshd server (daemon) + + - The sshd daemon starts by processing arguments and reading the + configuration file (servconf.c). It then reads the host key, + starts listening for connections, and generates the server key. + The server key will be regenerated every hour by an alarm. + + - When the server receives a connection, it forks, disables the + regeneration alarm, and starts communicating with the client. + They first perform identification string exchange, then + negotiate encryption, then perform authentication, preparatory + operations, and finally the server enters the normal session + mode by calling server_loop in serverloop.c. This does the real + work, calling functions in other modules. + + - The code for the server is in sshd.c. It contains a lot of + stuff, including: + - server main program + - waiting for connections + - processing new connection + - authentication + - preparatory operations + - building up the execution environment for the user program + - starting the user program. + + Auxiliary files + + - There are several other files in the distribution that contain + various auxiliary routines: + ssh.h the main header file for ssh (various definitions) + getput.h byte-order independent storage of integers + includes.h includes most system headers. Lots of #ifdefs. + tildexpand.c expand tilde in file names + uidswap.c uid-swapping + xmalloc.c "safe" malloc routines + + Substitutions files for missing functions + + - To ease porting, the distribution contains alternative versions of some + functions for those platforms that don't have them. These are + added to the CONFOBJS target by configure where needed. + crypt.c password encryption crypt() (Convex needs this) + memmove.c memmove() function + putenv.c putenv() function + random.c random() function (see discussion above) + remove.c remove() function + socketpair.c socketpair() function (kludge; SCO needs it) + strerror.c strerror() function + diff --git a/usr.bin/ssh/README b/usr.bin/ssh/README new file mode 100644 index 00000000000..ed360844185 --- /dev/null +++ b/usr.bin/ssh/README @@ -0,0 +1,563 @@ +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 +replacement for rlogin, rsh, rcp, and rdist. + +See the file INSTALL for installation instructions. See COPYING for +license terms and other legal issues. See RFC for a description of +the protocol. There is a WWW page for ssh; see http://www.cs.hut.fi/ssh. + +This file has been updated to match ssh-1.2.12. + + +FEATURES + + o Strong authentication. Closes several security holes (e.g., IP, + routing, and DNS spoofing). New authentication methods: .rhosts + together with RSA based host authentication, and pure RSA + authentication. + + o Improved privacy. All communications are automatically and + transparently encrypted. RSA is used for key exchange, and a + conventional cipher (normally IDEA, DES, or triple-DES) for + encrypting the session. Encryption is started before + authentication, and no passwords or other information is + transmitted in the clear. Encryption is also used to protect + against spoofed packets. + + o Secure X11 sessions. The program automatically sets DISPLAY on + the server machine, and forwards any X11 connections over the + secure channel. Fake Xauthority information is automatically + generated and forwarded to the remote machine; the local client + automatically examines incoming X11 connections and replaces the + fake authorization data with the real data (never telling the + remote machine the real information). + + o Arbitrary TCP/IP ports can be redirected through the encrypted channel + in both directions (e.g., for e-cash transactions). + + o No retraining needed for normal users; everything happens + automatically, and old .rhosts files will work with strong + authentication if administration installs host key files. + + o Never trusts the network. Minimal trust on the remote side of + the connection. Minimal trust on domain name servers. Pure RSA + authentication never trusts anything but the private key. + + 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 Host authentication key distribution can be centrally by the + administration, automatically when the first connection is made + to a machine (the key obtained on the first connection will be + recorded and used for authentication in the future), or manually + by each user for his/her own use. The central and per-user host + key repositories are both used and complement each other. Host + keys can be generated centrally or automatically when the software + is installed. Host authentication keys are typically 1024 bits. + + o Any user can create any number of user authentication RSA keys for + his/her own use. Each user has a file which lists the RSA public + keys for which proof of possession of the corresponding private + key is accepted as authentication. User authentication keys are + typically 1024 bits. + + o The server program has its own server RSA key which is + automatically regenerated every hour. This key is never saved in + any file. Exchanged session keys are encrypted using both the + server key and the server host key. The purpose of the separate + server key is to make it impossible to decipher a captured session by + breaking into the server machine at a later time; one hour from + the connection even the server machine cannot decipher the session + key. The key regeneration interval is configurable. The server + key is normally 768 bits. + + o An authentication agent, running in the user's laptop or local + workstation, can be used to hold the user's RSA authentication + keys. Ssh automatically forwards the connection to the + authentication agent over any connections, and there is no need to + store the RSA authentication keys on any machine in the network + (except the user's own local machine). The authentication + protocols never reveal the keys; they can only be used to verify + that the user's agent has a certain key. Eventually the agent + could rely on a smart card to perform all authentication + computations. + + o The software can be installed and used (with restricted + functionality) even without root privileges. + + o The client is customizable in system-wide and per-user + configuration files. Most aspects of the client's operation can + be configured. Different options can be specified on a per-host basis. + + o Automatically executes conventional rsh (after displaying a + warning) if the server machine is not running sshd. + + o Optional compression of all data with gzip (including forwarded X11 + and TCP/IP port data), which may result in significant speedups on + slow connections. + + o Complete replacement for rlogin, rsh, and rcp. + + +WHY TO USE SECURE SHELL + +Currently, almost all communications in computer networks are done +without encryption. As a consequence, anyone who has access to any +machine connected to the network can listen in on any communication. +This is being done by hackers, curious administrators, employers, +criminals, industrial spies, and governments. Some networks leak off +enough electromagnetic radiation that data may be captured even from a +distance. + +When you log in, your password goes in the network in plain +text. Thus, any listener can then use your account to do any evil he +likes. Many incidents have been encountered worldwide where crackers +have started programs on workstations without the owners knowledge +just to listen to the network and collect passwords. Programs for +doing this are available on the Internet, or can be built by a +competent programmer in a few hours. + +Any information that you type or is printed on your screen can be +monitored, recorded, and analyzed. For example, an intruder who has +penetrated a host connected to a major network can start a program +that listens to all data flowing in the network, and whenever it +encounters a 16-digit string, it checks if it is a valid credit card +number (using the check digit), and saves the number plus any +surrounding text (to catch expiration date and holder) in a file. +When the intruder has collected a few thousand credit card numbers, he +makes smallish mail-order purchases from a few thousand stores around +the world, and disappears when the goods arrive but before anyone +suspects anything. + +Businesses have trade secrets, patent applications in preparation, +pricing information, subcontractor information, client data, personnel +data, financial information, etc. Currently, anyone with access to +the network (any machine on the network) can listen to anything that +goes in the network, without any regard to normal access restrictions. + +Many companies are not aware that information can so easily be +recovered from the network. They trust that their data is safe +since nobody is supposed to know that there is sensitive information +in the network, or because so much other data is transferred in the +network. This is not a safe policy. + +Individual persons also have confidential information, such as +diaries, love letters, health care documents, information about their +personal interests and habits, professional data, job applications, +tax reports, political documents, unpublished manuscripts, etc. + +One should also be aware that economical intelligence and industrial +espionage has recently become a major priority of the intelligence +agencies of major governments. President Clinton recently assigned +economical espionage as the primary task of the CIA, and the French +have repeatedly been publicly boasting about their achievements on +this field. + + +There is also another frightening aspect about the poor security of +communications. Computer storage and analysis capability has +increased so much that it is feasible for governments, major +companies, and criminal organizations to automatically analyze, +identify, classify, and file information about millions of people over +the years. Because most of the work can be automated, the cost of +collecting this information is getting very low. + +Government agencies may be able to monitor major communication +systems, telephones, fax, computer networks, etc., and passively +collect huge amounts of information about all people with any +significant position in the society. Most of this information is not +sensitive, and many people would say there is no harm in someone +getting that information. However, the information starts to get +sensitive when someone has enough of it. You may not mind someone +knowing what you bought from the shop one random day, but you might +not like someone knowing every small thing you have bought in the last +ten years. + +If the government some day starts to move into a more totalitarian +direction (one should remember that Nazi Germany was created by +democratic elections), there is considerable danger of an ultimate +totalitarian state. With enough information (the automatically +collected records of an individual can be manually analyzed when the +person becomes interesting), one can form a very detailed picture of +the individual's interests, opinions, beliefs, habits, friends, +lovers, weaknesses, etc. This information can be used to 1) locate +any persons who might oppose the new system 2) use deception to +disturb any organizations which might rise against the government 3) +eliminate difficult individuals without anyone understanding what +happened. Additionally, if the government can monitor communications +too effectively, it becomes too easy to locate and eliminate any +persons distributing information contrary to the official truth. + +Fighting crime and terrorism are often used as grounds for domestic +surveillance and restricting encryption. These are good goals, but +there is considerable danger that the surveillance data starts to get +used for questionable purposes. I find that it is better to tolerate +a small amount of crime in the society than to let the society become +fully controlled. I am in favor of a fairly strong state, but the +state must never get so strong that people become unable to spread +contra-offical information and unable to overturn the government if it +is bad. The danger is that when you notice that the government is +too powerful, it is too late. Also, the real power may not be where +the official government is. + +For these reasons (privacy, protecting trade secrets, and making it +more difficult to create a totalitarian state), I think that strong +cryptography should be integrated to the tools we use every day. +Using it causes no harm (except for those who wish to monitor +everything), but not using it can cause huge problems. If the society +changes in undesirable ways, then it will be to late to start +encrypting. + +Encryption has had a "military" or "classified" flavor to it. There +are no longer any grounds for this. The military can and will use its +own encryption; that is no excuse to prevent the civilians from +protecting their privacy and secrets. Information on strong +encryption is available in every major bookstore, scientific library, +and patent office around the world, and strong encryption software is +available in every country on the Internet. + +Some people would like to make it illegal to use encryption, or to +force people to use encryption that governments can break. This +approach offers no protection if the government turns bad. Also, the +"bad guys" will be using true strong encryption anyway. Good +encryption techniques are too widely known to make them disappear. +Thus, any "key escrow encryption" or other restrictions will only help +monitor ordinary people and petty criminals. It does not help against +powerful criminals, terrorists, or espionage, because they will know +how to use strong encryption anyway. (One source for internationally +available encryption software is http://www.cs.hut.fi/crypto.) + + +OVERVIEW OF SECURE SHELL + +The software consists of a number of programs. + + sshd Server program run on the server machine. This + listens for connections from client machines, and + whenever it receives a connection, it performs + authentication and starts serving the client. + + ssh This is the client program used to log into another + machine or to execute commands on the other machine. + "slogin" is another name for this program. + + scp Securely copies files from one machine to another. + + ssh-keygen Used to create RSA keys (host keys and user + authentication keys). + + ssh-agent Authentication agent. This can be used to hold RSA + keys for authentication. + + ssh-add Used to register new keys with the agent. + + make-ssh-known-hosts + Used to create the /etc/ssh_known_hosts file. + + +Ssh is the program users normally use. It is started as + + ssh host + +or + + ssh host command + +The first form opens a new shell on the remote machine (after +authentication). The latter form executes the command on the remote +machine. + +When started, the ssh connects sshd on the server machine, verifies +that the server machine really is the machine it wanted to connect, +exchanges encryption keys (in a manner which prevents an outside +listener from getting the keys), performs authentication using .rhosts +and /etc/hosts.equiv, RSA authentication, or conventional password +based authentication. The server then (normally) allocates a +pseudo-terminal and starts an interactive shell or user program. + +The TERM environment variable (describing the type of the user's +terminal) is passed from the client side to the remote side. Also, +terminal modes will be copied from the client side to the remote side +to preserve user preferences (e.g., the erase character). + +If the DISPLAY variable is set on the client side, the server will +create a dummy X server and set DISPLAY accordingly. Any connections +to the dummy X server will be forwarded through the secure channel, +and will be made to the real X server from the client side. An +arbitrary number of X programs can be started during the session, and +starting them does not require anything special from the user. (Note +that the user must not manually set DISPLAY, because then it would +connect directly to the real display instead of going through the +encrypted channel). This behavior can be disabled in the +configuration file or by giving the -x option to the client. + +Arbitrary IP ports can be forwarded over the secure channel. The +program then creates a port on one side, and whenever a connection is +opened to this port, it will be passed over the secure channel, and a +connection will be made from the other side to a specified host:port +pair. Arbitrary IP forwarding must always be explicitly requested, +and cannot be used to forward privileged ports (unless the user is +root). It is possible to specify automatic forwards in a per-user +configuration file, for example to make electronic cash systems work +securely. + +If there is an authentication agent on the client side, connection to +it will be automatically forwarded to the server side. + +For more infomation, see the manual pages ssh(1), sshd(8), scp(1), +ssh-keygen(1), ssh-agent(1), ssh-add(1), and make-ssh-known-hosts(1) +included in this distribution. + + +X11 CONNECTION FORWARDING + +X11 forwarding serves two purposes: it is a convenience to the user +because there is no need to set the DISPLAY variable, and it provides +encrypted X11 connections. I cannot think of any other easy way to +make X11 connections encrypted; modifying the X server, clients or +libraries would require special work for each machine, vendor and +application. Widely used IP-level encryption does not seem likely for +several years. Thus what we have left is faking an X server on the +same machine where the clients are run, and forwarding the connections +to a real X server over the secure channel. + +X11 forwarding works as follows. The client extracts Xauthority +information for the server. It then creates random authorization +data, and sends the random data to the server. The server allocates +an X11 display number, and stores the (fake) Xauthority data for this +display. Whenever an X11 connection is opened, the server forwards +the connection over the secure channel to the client, and the client +parses the first packet of the X11 protocol, substitutes real +authentication data for the fake data (if the fake data matched), and +forwards the connection to the real X server. + +If the display does not have Xauthority data, the server will create a +unix domain socket in /tmp/.X11-unix, and use the unix domain socket +as the display. No authentication information is forwarded in this +case. X11 connections are again forwarded over the secure channel. +To the X server the connections appear to come from the client +machine, and the server must have connections allowed from the local +machine. Using authentication data is always recommended because not +using it makes the display insecure. If XDM is used, it automatically +generates the authentication data. + +One should be careful not to use "xin" or "xstart" or other similar +scripts that explicitly set DISPLAY to start X sessions in a remote +machine, because the connection will then not go over the secure +channel. The recommended way to start a shell in a remote machine is + + xterm -e ssh host & + +and the recommended way to execute an X11 application in a remote +machine is + + ssh -n host emacs & + +If you need to type a password/passphrase for the remote machine, + + ssh -f host emacs + +may be useful. + + + +RSA AUTHENTICATION + +RSA authentication is based on public key cryptograpy. The idea is +that there are two encryption keys, one for encryption and another for +decryption. It is not possible (on human timescale) to derive the +decryption key from the encryption key. The encryption key is called +the public key, because it can be given to anyone and it is not +secret. The decryption key, on the other hand, is secret, and is +called the private key. + +RSA authentication is based on the impossibility of deriving the +private key from the public key. The public key is stored on the +server machine in the user's $HOME/.ssh/authorized_keys file. The +private key is only kept on the user's local machine, laptop, or other +secure storage. Then the user tries to log in, the client tells the +server the public key that the user wishes to use for authentication. +The server then checks if this public key is admissible. If so, it +generates a 256 bit random number, encrypts it with the public key, +and sends the value to the client. The client then decrypts the +number with its private key, computes a 128 bit MD5 checksum from the +resulting data, and sends the checksum back to the server. (Only a +checksum is sent to prevent chosen-plaintext attacks against RSA.) +The server checks computes a checksum from the correct data, +and compares the checksums. Authentication is accepted if the +checksums match. (Theoretically this indicates that the client +only probably knows the correct key, but for all practical purposes +there is no doubt.) + +The RSA private key can be protected with a passphrase. The +passphrase can be any string; it is hashed with MD5 to produce an +encryption key for IDEA, which is used to encrypt the private part of +the key file. With passphrase, authorization requires access to the key +file and the passphrase. Without passphrase, authorization only +depends on possession of the key file. + +RSA authentication is the most secure form of authentication supported +by this software. It does not rely on the network, routers, domain +name servers, or the client machine. The only thing that matters is +access to the private key. + +All this, of course, depends on the security of the RSA algorithm +itself. RSA has been widely known since about 1978, and no effective +methods for breaking it are known if it is used properly. Care has +been taken to avoid the well-known pitfalls. Breaking RSA is widely +believed to be equivalent to factoring, which is a very hard +mathematical problem that has received considerable public research. +So far, no effective methods are known for numbers bigger than about +512 bits. However, as computer speeds and factoring methods are +increasing, 512 bits can no longer be considered secure. The +factoring work is exponential, and 768 or 1024 bits are widely +considered to be secure in the near future. + + +RHOSTS AUTHENTICATION + +Conventional .rhosts and hosts.equiv based authentication mechanisms +are fundamentally insecure due to IP, DNS (domain name server) and +routing spoofing attacks. Additionally this authentication method +relies on the integrity of the client machine. These weaknesses is +tolerable, and been known and exploited for a long time. + +Ssh provides an improved version of these types of authentication, +because they are very convenient for the user (and allow easy +transition from rsh and rlogin). It permits these types of +authentication, but additionally requires that the client host be +authenticated using RSA. + +The server has a list of host keys stored in /etc/ssh_known_host, and +additionally each user has host keys in $HOME/.ssh/known_hosts. Ssh +uses the name servers to obtain the canonical name of the client host, +looks for its public key in its known host files, and requires the +client to prove that it knows the private host key. This prevents IP +and routing spoofing attacks (as long as the client machine private +host key has not been compromized), but is still vulnerable to DNS +attacks (to a limited extent), and relies on the integrity of the +client machine as to who is requesting to log in. This prevents +outsiders from attacking, but does not protect against very powerful +attackers. If maximal security is desired, only RSA authentication +should be used. + +It is possible to enable conventional .rhosts and /etc/hosts.equiv +authentication (without host authentication) at compile time by giving +the option --with-rhosts to configure. However, this is not +recommended, and is not done by default. + +These weaknesses are present in rsh and rlogin. No improvement in +security will be obtained unless rlogin and rsh are completely +disabled (commented out in /etc/inetd.conf). This is highly +recommended. + + +WEAKEST LINKS IN SECURITY + +One should understand that while this software may provide +cryptographically secure communications, it may be easy to +monitor the communications at their endpoints. + +Basically, anyone with root access on the local machine on which you +are running the software may be able to do anything. Anyone with root +access on the server machine may be able to monitor your +communications, and a very talented root user might even be able to +send his/her own requests to your authentication agent. + +One should also be aware that computers send out electromagnetic +radition that can sometimes be picked up hundreds of meters away. +Your keyboard is particularly easy to listen to. The image on your +monitor might also be seen on another monitor in a van parked behind +your house. + +Beware that unwanted visitors might come to your home or office and +use your machine while you are away. They might also make +modifications or install bugs in your hardware or software. + +Beware that the most effective way for someone to decrypt your data +may be with a rubber hose. + + +LEGAL ISSUES + +As far as I am concerned, anyone is permitted to use this software +freely. However, see the file COPYING for detailed copying, +licensing, and distribution information. + +In some countries, particularly France, Russia, Iraq, and Pakistan, +it may be illegal to use any encryption at all without a special +permit, and the rumor has it that you cannot get a permit for any +strong encryption. + +This software may be freely imported into the United States; however, +the United States Government may consider re-exporting it a criminal +offence. + +Note that any information and cryptographic algorithms used in this +software are publicly available on the Internet and at any major +bookstore, scientific library, or patent office worldwide. + +THERE IS NO WARRANTY FOR THIS PROGRAM. Please consult the file +COPYING for more information. + + +MAILING LISTS AND OTHER INFORMATION + +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 +ssh" in body. + +The WWW home page for ssh is http://www.cs.hut.fi/ssh. It contains an +archive of the mailing list, and detailed information about new +releases, mailing lists, and other relevant issues. + +Bug reports should be sent to ossh-bugs@sics.se. + + +ABOUT THE AUTHOR + +This software was written by Tatu Ylonen <ylo@cs.hut.fi>. I work as a +researcher at Helsinki University of Technology, Finland. For more +information, see http://www.cs.hut.fi/~ylo/. My PGP public key is +available via finger from ylo@cs.hut.fi and from the key servers. I +prefer PGP encrypted mail. + +The author can be contacted via ordinary mail at + Tatu Ylonen + Helsinki University of Technology + Otakaari 1 + FIN-02150 ESPOO + Finland + + Fax. +358-0-4513293 + + +ACKNOWLEDGEMENTS + +I thank Tero Kivinen, Timo Rinne, Janne Snabb, and Heikki Suonsivu for +their help and comments in the design, implementation and porting of +this software. I also thank numerous contributors, including but not +limited to Walker Aumann, Jurgen Botz, Hans-Werner Braun, Stephane +Bortzmeyer, Adrian Colley, Michael Cooper, David Dombek, Jerome +Etienne, Bill Fithen, Mark Fullmer, Bert Gijsbers, Andreas Gustafsson, +Michael Henits, Steve Johnson, Thomas Koenig, Felix Leitner, Gunnar +Lindberg, Andrew Macpherson, Marc Martinec, Paul Mauvais, Donald +McKillican, Leon Mlakar, Robert Muchsel, Mark Treacy, Bryan +O'Sullivan, Mikael Suokas, Ollivier Robert, Jakob Schlyter, Tomasz +Surmacz, Alvar Vinacua, Petri Virkkula, Michael Warfield, and +Cristophe Wolfhugel. + +Thanks also go to Philip Zimmermann, whose PGP software and the +associated legal battle provided inspiration, motivation, and many +useful techniques, and to Bruce Schneier whose book Applied +Cryptography has done a great service in widely distributing knowledge +about cryptographic methods. + + +Copyright (c) 1995 Tatu Ylonen, Espoo, Finland. diff --git a/usr.bin/ssh/README.AFS-KERBEROS b/usr.bin/ssh/README.AFS-KERBEROS new file mode 100644 index 00000000000..6e03c976b51 --- /dev/null +++ b/usr.bin/ssh/README.AFS-KERBEROS @@ -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 diff --git a/usr.bin/ssh/RFC b/usr.bin/ssh/RFC new file mode 100644 index 00000000000..91195b16255 --- /dev/null +++ b/usr.bin/ssh/RFC @@ -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-<protocolmajor>.<protocolminor>- + <version>\n", where <protocolmajor> and <protocolminor> are integers + and specify the protocol version number (not software distribution + version). <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 "<shell> -c <command>" 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 "<shell> -c <com- + mand>", where <shell> 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 <ylo@cs.hut.fi> or the SSH + Mailing List <ssh@clinet.fi>. + +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] + diff --git a/usr.bin/ssh/RFC.nroff b/usr.bin/ssh/RFC.nroff new file mode 100644 index 00000000000..dccc954c78b --- /dev/null +++ b/usr.bin/ssh/RFC.nroff @@ -0,0 +1,1780 @@ +.\" -*- nroff -*- +.\" +.\" $Id: RFC.nroff,v 1.1 1999/09/26 20:53:32 deraadt Exp $ +.\" +.pl 10.0i +.po 0 +.ll 7.2i +.lt 7.2i +.nr LL 7.2i +.nr LT 7.2i +.ds LF Ylonen +.ds RF FORMFEED[Page %] +.ds CF +.ds LH Internet-Draft +.ds RH 15 November 1995 +.ds CH SSH (Secure Shell) Remote Login Protocol +.na +.hy 0 +.in 0 +Network Working Group T. Ylonen +Internet-Draft Helsinki University of Technology +draft-ylonen-ssh-protocol-00.txt 15 November 1995 +Expires: 15 May 1996 + +.in 3 + +.ce +The SSH (Secure Shell) Remote Login Protocol + +.ti 0 +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. + +.ti 0 +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: +.IP o +Closes several security holes (e.g., IP, routing, and DNS spoofing). +New authentication methods: .rhosts together with RSA [RSA] based host +authentication, and pure RSA authentication. +.IP o +All communications are automatically and transparently encrypted. +Encryption is also used to protect integrity. +.IP o +X11 connection forwarding provides secure X11 sessions. +.IP o +Arbitrary TCP/IP ports can be redirected over the encrypted channel +in both directions. +.IP 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). +.IP o +An authentication agent, running in the user's local workstation or +laptop, can be used to hold the user's RSA authentication keys. +.RT + +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. + + +.ti 0 +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 +transport can be used but are currently not defined. + +When the client connects the server, the server accepts the connection +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 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 +authentication 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 allocating 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 interactive +session mode. In this mode, data is passed in both directions, +new forwarded connections may be opened, etc. The interactive session +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 +extensions 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 +interactive 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. + +.ti 0 +The Binary Packet Protocol + +After the protocol identification strings, both sides only send +specially formatted packets. The packet layout is as follows: +.IP o +Packet length: 32 bit unsigned integer, coded as four 8-bit 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. +.IP 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 having some random padding +at the beginning of each packet is to make known plaintext attacks +more difficult. +.IP o +Packet type: 8-bit unsigned byte. The value 255 is reserved for +future extension. +.IP o +Data: binary data bytes, depending on the packet type. The number of +data bytes is the "length" field minus 5. +.IP 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 computed before +any encryption. +.RT + +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. + + +.ti 0 +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 direction +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 compression +dictionary is not flushed between packets. The two directions are +compressed independently of each other. + + +.ti 0 +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: +.TS +center; +l r l. +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 +.TE + +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 +direction) 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. +.IP 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. +.IP SSH_CIPHER_3DES +The variant of triple-DES used here works as follows: there are three +independent DES-CBC ciphers, with independent initialization 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 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.) +.IP 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. +.IP 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. +.IP 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. +.RT + + +.ti 0 +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: +.IP "8-bit byte" +The byte is stored directly as a single byte. +.IP "32-bit unsigned integer" +Stored in 4 bytes, msb first. +.IP "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. +.IP "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. +.RT + + +.ti 0 +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 +authentication, 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 programs +on the server may never notice if the other end of the connection is +rebooted. + + +.ti 0 +Protocol Version Identification + +After the socket is opened, the server sends an identification string, +which is of the form +"SSH-<protocolmajor>.<protocolminor>-<version>\\n", where +<protocolmajor> and <protocolminor> are integers and specify the +protocol version number (not software distribution version). +<version> is server side software version string (max 40 characters); +it is not interpreted by the remote side but may be useful 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 +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 +according to the lower of the protocol versions. + +By convention, changes which keep the protocol compatible with +previous 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 + +.ti 0 +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 public +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 significant +byte first. This string is concatenated with the server host key +interpreted the same way. Additionally, the cookie is concatenated +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 +contains 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 +generated 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 +from the data to be encrypted as follows (the integer is here +interpreted 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 identically 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 +different directions (that is, both directions have separate +initialization 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. + + +.ti 0 +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 +authentication 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 +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. + + +.ti 0 +Authentication Phase + +Provided the server didn't immediately accept the login, an +authentication 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 +authentication 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: +.TS +center; +l r l. +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 +.TE +.IP 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. + +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. +.IP SSH_AUTH_RHOSTS_RSA + +In addition to conventional .rhosts and hosts.equiv authentication, +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 verifies +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 containing +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 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. +.IP SSH_AUTH_RSA + +The idea behind RSA authentication is that the server recognizes the +public key offered by the client, generates a random challenge, 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 generates 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, concatenates +it with the session id, and computes an MD5 checksum 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 compromised RSA +key, a server might restrict access to a limited set of hosts. +.IP 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 possession of the +password can log in, but nobody else. +.RT + +.ti 0 +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. + +The following messages are currently defined for this phase. +.IP SSH_CMSG_REQUEST_COMPRESSION +Requests that compression be enabled for this session. A +gzip-compatible compression level (1-9) is passed as an argument. +.IP 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. +.IP 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 automatically passed to the server, and the +client may implement spoofing of authentication data for added +security. The authentication data is passed as arguments. +.IP 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). +.IP SSH_CMSG_AGENT_REQUEST_FORWARDING +Requests forwarding of the connection to the authentication agent. +.IP SSH_CMSG_EXEC_SHELL +Starts a shell (command interpreter) for the user, and moves into +interactive session mode. +.IP SSH_CMSG_EXEC_CMD +Executes the given command (actually "<shell> -c <command>" or +equivalent) for the user, and moves into interactive session mode. +.RT + + +.ti 0 +Interactive Session and Exchange of Data + +During the interactive session, any data written by the shell or +command 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. + +All exchange is asynchronous; either side can send at any time, and +there are no acknowledgements (TCP/IP already provides reliable +transport, 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: +.IP 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. +.IP 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.) +.IP 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. +.IP SSH_SMSG_AGENT_OPEN +Indicates that someone on the server side is requesting a connection +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. +.IP 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. +.IP SSH_MSG_PORT_OPEN +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. +.IP SSH_MSG_CHANNEL_OPEN_CONFIRMATION +This is sent by the server to indicate that it has opened a connection +as requested in a previous message. The first argument indicates the +client side channel number, and the second argument is the channel number +that the server has allocated for this connection. +.IP 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. +.IP 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. +.IP 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. +.IP 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. +.RT + +The client may send any of the following messages: +.IP 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. +.IP SSH_CMSG_EOF +Indicates that the client has encountered EOF while reading standard +input. The server will allow any buffered input data to drain, and +will then close the input to the program. +.IP 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. +.IP 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. +.IP SSH_MSG_CHANNEL_OPEN_CONFIRMATION +This is sent by the client to indicate that it has opened a connection +as requested in a previous message. The first argument indicates the +server side channel number, and the second argument is the channel +number that the client has allocated for this connection. +.IP 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. +.IP 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. +.IP 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. +.IP 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 server frees +the channel. +.RT + +Any unsupported messages during interactive mode cause the connection +to be terminated with SSH_MSG_DISCONNECT and an error message. +Compatible protocol upgrades should agree about any extensions during +the preparation phase or earlier. + + +.ti 0 +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. + +.ti 0 +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 extension; +the server first announces which added capabilities it supports, and +the client then sends the capabilities that it supports. + +The following flags are currently defined (the values are bit masks): +.IP "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. +.IP "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 containing +a description of the host at the other end of the connection. +.RT + +.ti 0 +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 +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.) +.IP "0 SSH_MSG_NONE" +This code is reserved. This message type is never sent. +.IP "1 SSH_MSG_DISCONNECT" +.TS +; +l l. +string Cause of disconnection +.TE +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. +.IP "2 SSH_SMSG_PUBLIC_KEY" +.TS +; +l l. +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 +.TE +Sent as the first message by the server. This message gives the +server's host key, server key, protocol flags (intended for compatible +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). +.IP "3 SSH_CMSG_SESSION_KEY" +.TS +; +l l. +1 byte cipher_type (must be one of the supported values) +8 bytes anti_spoofing_cookie (must match data sent by the server) +mp-int double-encrypted session key +32-bit int protocol_flags +.TE +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 negotiating compatible +protocol extensions. +.IP "4 SSH_CMSG_USER" +.TS +; +l l. +string user login name on server +.TE +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.] +.IP "5 SSH_CMSG_AUTH_RHOSTS" +.TS +; +l l. +string client-side user name +.TE +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.) +.IP "6 SSH_CMSG_AUTH_RSA" +.TS +; +l l. +mp-int identity_public_modulus +.TE +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 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 +authentication method is optional but recommended. +.IP "7 SSH_SMSG_AUTH_RSA_CHALLENGE" +.TS +; +l l. +mp-int encrypted challenge +.TE +Presents an RSA authentication challenge to the client. The challenge +is a 256-bit random value encrypted as described elsewhere 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. +.IP "8 SSH_CMSG_AUTH_RSA_RESPONSE" +.TS +; +l l. +16 bytes MD5 of decrypted challenge +.TE +This message is sent by the client in response to an RSA challenge. +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. +.IP "9 SSH_CMSG_AUTH_PASSWORD" +.TS +; +l l. +string plain text password +.TE +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. +.IP "10 SSH_CMSG_REQUEST_PTY" +.TS +; +l l. +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) +n bytes tty modes encoded in binary +.TE +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 format. +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. +.IP "11 SSH_CMSG_WINDOW_SIZE" +.TS +; +l l. +32-bit int terminal height, rows +32-bit int terminal width, columns +32-bit int terminal width, pixels +32-bit int terminal height, pixels +.TE +This message can only be sent by the client during the interactive +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). +.IP "12 SSH_CMSG_EXEC_SHELL" + +(no arguments) + +Starts a shell (command interpreter), and enters interactive session +mode. +.IP "13 SSH_CMSG_EXEC_CMD" +.TS +; +l l. +string command to execute +.TE +Starts executing the given command, and enters interactive session +mode. On UNIX, the command is run as "<shell> -c <command>", where +<shell> is the user's login shell. +.IP "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. +.IP "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. +.IP "16 SSH_CMSG_STDIN_DATA" +.TS +; +l l. +string data +.TE +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 acknowledgement is sent for this +message. +.IP "17 SSH_SMSG_STDOUT_DATA" +.TS +; +l l. +string data +.TE +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. +.IP "18 SSH_SMSG_STDERR_DATA" +.TS +; +l l. +string data +.TE +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. +.IP "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. +.IP "20 SSH_SMSG_EXITSTATUS" +.TS +; +l l. +32-bit int exit status of the command +.TE +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 program being executed dies with a signal instead of +exiting normally, 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. +.IP "21 SSH_MSG_CHANNEL_OPEN_CONFIRMATION" +.TS +; +l l. +32-bit int remote_channel +32-bit int local_channel +.TE +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 message has allocated for the channel. +Data can be transmitted on the channel after this message. +.IP "22 SSH_MSG_CHANNEL_OPEN_FAILURE" +.TS +; +l l. +32-bit int remote_channel +.TE +This message indicates that an earlier channel open request by the +other side has failed or has been denied. Remote_channel is the +channel number given in the original request. +.IP "23 SSH_MSG_CHANNEL_DATA" +.TS +; +l l. +32-bit int remote_channel +string data +.TE +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. +.IP "24 SSH_MSG_CHANNEL_CLOSE" +.TS +; +l l. +32-bit int remote_channel +.TE +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.) +.IP "25 SSH_MSG_CHANNEL_CLOSE_CONFIRMATION" +.TS +; +l l. +32-bit int remote_channel +.TE +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. +.IP "26 (OBSOLETED; was unix-domain X11 forwarding) +.IP "27 SSH_SMSG_X11_OPEN" +.TS +; +l l. +32-bit int local_channel +string originator_string (see below) +.TE +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 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 +contains a description of the host originating the connection. +.IP "28 SSH_CMSG_PORT_FORWARD_REQUEST" +.TS +; +l l. +32-bit int server_port +string host_to_connect +32-bit int port_to_connect +.TE +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. +.IP "29 SSH_MSG_PORT_OPEN" +.TS +; +l l. +32-bit int local_channel +string host_name +32-bit int port +string originator_string (see below) +.TE +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 sending 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 permit 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 SSH_PROTOFLAG_HOST_IN_FWD_OPEN in the protocol flags. It +contains a description of the host originating the connection. +.IP "30 SSH_CMSG_AGENT_REQUEST_FORWARDING" + +(no arguments) + +Requests that the connection to the authentication agent be forwarded +over the secure channel. The method used by clients to contact the +authentication agent within each machine is implementation and machine +dependent. If the server accepts this request, it should arrange that +any clients run from this session 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. +.IP "31 SSH_SMSG_AGENT_OPEN" +.TS +; +l l. +32-bit int local_channel +.TE +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. +.IP "32 SSH_MSG_IGNORE" +.TS +; +l l. +string data +.TE +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 recognize and ignore it. +.IP "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. +.IP "34 SSH_CMSG_X11_REQUEST_FORWARDING" +.TS +; +l l. +string x11_authentication_protocol +string x11_authentication_data +32-bit int screen number (if SSH_PROTOFLAG_SCREEN_NUMBER) +.TE +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". Authentication 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 important). + +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 authentication. 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. +.IP "35 SSH_CMSG_AUTH_RHOSTS_RSA" +.TS +; +l l. +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 +.TE +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 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. +.IP "36 SSH_MSG_DEBUG" +.TS +; +l l. +string debugging message sent to the other side +.TE +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 authentication 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 reasons. 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 +implementation must be able to receive this message, but no +implementation is required to send these. +.IP "37 SSH_CMSG_REQUEST_COMPRESSION" +.TS +; +l l. +32-bit int gzip compression level (1-9) +.TE +This message can be sent by the client in the preparatory operations +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 direction will be compressed by gzip. +.RT + + +.ti 0 +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 +different 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 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. +.IP "0 TTY_OP_END" +Indicates end of options. +.IP "1 VINTR" +Interrupt character; 255 if none. Similarly for the other characters. +Not all of these characters are supported on all systems. +.IP "2 VQUIT" +The quit character (sends SIGQUIT signal on UNIX systems). +.IP "3 VERASE" +Erase the character to left of the cursor. +.IP "4 VKILL" +Kill the current input line. +.IP "5 VEOF " +End-of-file character (sends EOF from the terminal). +.IP "6 VEOL " +End-of-line character in addition to carriage return and/or linefeed. +.IP "7 VEOL2" +Additional end-of-line character. +.IP "8 VSTART" +Continues paused output (normally ^Q). +.IP "9 VSTOP" +Pauses output (^S). +.IP "10 VSUSP" +Suspends the current program. +.IP "11 VDSUSP" +Another suspend character. +.IP "12 VREPRINT" +Reprints the current input line. +.IP "13 VWERASE" +Erases a word left of cursor. +.IP "14 VLNEXT" +More special input characters; these are probably not supported on +most systems. +.IP "15 VFLUSH" +.IP "16 VSWTCH" +.IP "17 VSTATUS" +.IP "18 VDISCARD" + +.IP "30 IGNPAR" +The ignore parity flag. The next byte should be 0 if this flag is not +set, and 1 if it is set. +.IP "31 PARMRK" +More flags. The exact definitions can be found in the POSIX standard. +.IP "32 INPCK" +.IP "33 ISTRIP" +.IP "34 INLCR" +.IP "35 IGNCR" +.IP "36 ICRNL" +.IP "37 IUCLC" +.IP "38 IXON" +.IP "39 IXANY" +.IP "40 IXOFF" +.IP "41 IMAXBEL" + +.IP "50 ISIG" +.IP "51 ICANON" +.IP "52 XCASE" +.IP "53 ECHO" +.IP "54 ECHOE" +.IP "55 ECHOK" +.IP "56 ECHONL" +.IP "57 NOFLSH" +.IP "58 TOSTOP" +.IP "59 IEXTEN" +.IP "60 ECHOCTL" +.IP "61 ECHOKE" +.IP "62 PENDIN" + +.IP "70 OPOST" +.IP "71 OLCUC" +.IP "72 ONLCR" +.IP "73 OCRNL" +.IP "74 ONOCR" +.IP "75 ONLRET" + +.IP "90 CS7" +.IP "91 CS8" +.IP "92 PARENB" +.IP "93 PARODD" + +.IP "192 TTY_OP_ISPEED" +Specifies the input baud rate in bits per second. +.IP "193 TTY_OP_OSPEED" +Specifies the output baud rate in bits per second. +.RT + + +.ti 0 +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 +challenge. How the connection is made to the agent (or its +representative) 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 +channel. + +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: +.TS +; +l l. +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. +.TE + +The following message types are currently defined: +.IP "1 SSH_AGENTC_REQUEST_RSA_IDENTITIES" + +(no arguments) + +Requests the agent to send a list of all RSA keys for which it can +answer a challenge. +.IP "2 SSH_AGENT_RSA_IDENTITIES_ANSWER" +.TS +; +l l. +32-bit int howmany +howmany times: +32-bit int bits +mp-int public exponent +mp-int public modulus +string comment +.TE +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. +.IP "3 SSH_AGENTC_RSA_CHALLENGE +.TS +; +l l. +32-bit int bits +mp-int public exponent +mp-int public modulus +mp-int challenge +16 bytes session_id +32-bit int response_type +.TE +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 (partial) +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. +.IP "4 SSH_AGENT_RSA_RESPONSE" +.TS +; +l l. +16 bytes MD5 of decrypted challenge +.TE +Answers an RSA authentication challenge. The response is 16 bytes: +the MD5 checksum of the 32-byte challenge. +.IP "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. +.IP "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. +.IP "7 SSH_AGENTC_ADD_RSA_IDENTITY" +.TS +; +l l. +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 +.TE +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. +.IP "8 SSH_AGENT_REMOVE_RSA_IDENTITY" +.TS +; +l l. +32-bit int bits +mp-int public exponent +mp-int public modulus +.TE +Removes an RSA key from the agent. The agent will no longer accept +challenges for this key and will not list it as a supported identity. +The agent responds with SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE. +.RT + +If the agent receives a message that it does not understand, it +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 +connections active simultaneously). + + +.ti 0 +References + +.IP "[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 Security. Prentice-Hall, +1989. +.IP "[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. +.IP "[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 Cryptography, John Wiley & +Sons, 1994. See also the following patents: PCT/CH91/00117, EP 0 482 +154 B1, US Pat. 5,214,703. +.IP [PKCS#1] +PKCS #1: RSA Encryption Standard. Version 1.5, RSA Laboratories, +November 1993. Available for anonymous ftp at ftp.rsa.com. +.IP [POSIX] +Portable Operating System Interface (POSIX) - Part 1: Application +Program Interface (API) [C language], ISO/IEC 9945-1, IEEE Std 1003.1, +1990. +.IP [RFC0791] +J. Postel: Internet Protocol, RFC 791, USC/ISI, September 1981. +.IP [RFC0793] +J. Postel: Transmission Control Protocol, RFC 793, USC/ISI, September +1981. +.IP [RFC1034] +P. Mockapetris: Domain Names - Concepts and Facilities, RFC 1034, +USC/ISI, November 1987. +.IP [RFC1282] +B. Kantor: BSD Rlogin, RFC 1258, UCSD, December 1991. +.IP "[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. +.IP "[X11] " +R. Scheifler: X Window System Protocol, X Consortium Standard, Version +11, Release 6. Massachusetts Institute of Technology, Laboratory of +Computer Science, 1994. +.RT + + +.ti 0 +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 arbitrary 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 telnet +and rlogin protocols. +.IP o +IP spoofing is restricted to closing a connection (by encryption, 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. +.IP o +DNS spoofing is made ineffective (by host keys). +.IP o +Routing spoofing is made ineffective (by host keys). +.IP o +All data is encrypted with strong algorithms to make eavesdropping as +difficult as possible. This includes encrypting any authentication +information such as passwords. The information for decrypting session +keys is destroyed every hour. +.IP o +Strong authentication methods: .rhosts combined with RSA host +authentication, and pure RSA authentication. +.IP o +X11 connections and arbitrary TCP/IP ports can be forwarded securely. +.IP o +Man-in-the-middle attacks are deterred by using the server host key to +encrypt the session key. +.IP 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. +.RT + +The security of SSH against man-in-the-middle attacks and the security +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 protect +data communicated between an X server and a client running on a remote +machine. By creating a fake display on the server, and forwarding 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 criminals 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. +This program is not secure if used with no encryption at all. + + +.ti 0 +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 <ylo@cs.hut.fi> or the SSH +Mailing List <ssh@clinet.fi>. + +.ti 0 +Author's Address + +.TS +; +l. +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 +.TE diff --git a/usr.bin/ssh/acconfig.h b/usr.bin/ssh/acconfig.h new file mode 100644 index 00000000000..77aa9a688fd --- /dev/null +++ b/usr.bin/ssh/acconfig.h @@ -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 <ylo@cs.hut.fi> + +*/ + +#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=<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 diff --git a/usr.bin/ssh/auth-krb4.c b/usr.bin/ssh/auth-krb4.c new file mode 100644 index 00000000000..f6f1cbbce57 --- /dev/null +++ b/usr.bin/ssh/auth-krb4.c @@ -0,0 +1,218 @@ +/* + + auth-kerberos.c + + Hacked together by Dug Song <dugsong@umich.edu>. + + Kerberos authentication and ticket-passing routines. + +*/ + +#include "includes.h" +#include "packet.h" +#include "xmalloc.h" +#include "ssh.h" + +#ifdef KRB4 +#include <sys/param.h> +#include <krb.h> + +int ssh_tf_init(uid_t uid) +{ + 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); +#ifdef AFS + if (lstat("/ticket", &st) != -1) + tkt_root = "/ticket/"; +#endif /* AFS */ + sprintf(ticket, "%.100s%d_%d", tkt_root, uid, getpid()); + (void) krb_set_tkt_string(ticket); + + /* Make sure we own this ticket file, and we created it. */ + if (lstat(ticket, &st) < 0 && 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 %.100s", ticket); + return 0; +} + +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_long 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. */ + r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""); + if (r != KSUCCESS) { + 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); + sprintf(*client, "%.100s%.100s%.100s@%.100s", 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 %.100s to account %.100s", + *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) %.100s", 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 +#include <kafs.h> + + +#ifdef KERBEROS_TGT_PASSING + +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 */ + strcpy(creds.service, "krbtgt"); + + if (strcmp(creds.service, "krbtgt")) { + log("Kerberos V4 tgt (%.100s%.100s%.100s@%.100s) rejected for uid %d", + creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm, + pw->pw_uid); + packet_send_debug("Kerberos V4 tgt (%.100s%.100s%.100s@%.100s) 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 ticket accepted (%.100s.%.100s@%.100s, %.100s%.100s%.100s@%.100s)", + 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; + +auth_kerberos_tgt_failure: + memset(&creds, 0, sizeof(creds)); + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + return 0; +} +#endif /* KERBEROS_TGT_PASSING */ + +int auth_afs_token(char *server_user, uid_t uid, const char *string) +{ + CREDENTIALS creds; + + 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 */ + strcpy(creds.service, "afs"); + + if (strncmp(creds.pname, "AFS ID ", 7) == 0) + uid = atoi(creds.pname + 7); + + if (kafs_settoken(creds.realm, uid, &creds)) { + log("AFS token (%.100s@%.100s) rejected for uid %d", + creds.pname, creds.realm, uid); + packet_send_debug("AFS token (%.100s@%.100s) 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 (%.100s@%.100s, %.100s@%.100s)", creds.service, + creds.realm, creds.pname, creds.realm); + packet_start(SSH_SMSG_SUCCESS); + packet_send(); + packet_write_wait(); + return 1; +} +#endif /* AFS */ diff --git a/usr.bin/ssh/auth-passwd.c b/usr.bin/ssh/auth-passwd.c new file mode 100644 index 00000000000..10d21ca0bf9 --- /dev/null +++ b/usr.bin/ssh/auth-passwd.c @@ -0,0 +1,343 @@ +/* + +auth-passwd.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.1 1999/09/26 20:53:33 deraadt Exp $"); + +#ifdef HAVE_SCO_ETC_SHADOW +# include <sys/security.h> +# include <sys/audit.h> +# include <prot.h> +#else /* HAVE_SCO_ETC_SHADOW */ +#ifdef HAVE_ETC_SHADOW +#include <shadow.h> +#endif /* HAVE_ETC_SHADOW */ +#endif /* HAVE_SCO_ETC_SHADOW */ +#ifdef HAVE_ETC_SECURITY_PASSWD_ADJUNCT +#include <sys/label.h> +#include <sys/audit.h> +#include <pwdadj.h> +#endif /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */ +#include "packet.h" +#include "ssh.h" +#include "servconf.h" +#include "xmalloc.h" + +#ifdef HAVE_SECURID +/* Support for Security Dynamics SecurID card. + Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */ +#define SECURID_USERS "/etc/securid.users" +#include "sdi_athd.h" +#include "sdi_size.h" +#include "sdi_type.h" +#include "sdacmvls.h" +#include "sdconf.h" +union config_record configure; +static int securid_initialized = 0; +#endif /* HAVE_SECURID */ + +#ifdef KRB4 +#include <sys/param.h> +#include <krb.h> +extern char *ticket; +#endif /* KRB4 */ + +/* Tries to authenticate the user using password. Returns true if + authentication succeeds. */ + +int auth_password(const char *server_user, const char *password) +{ + extern ServerOptions options; + extern char *crypt(const char *key, const char *salt); + struct passwd *pw; + char *encrypted_password; + char correct_passwd[200]; + + if (*password == '\0' && options.permit_empty_passwd == 0) + { + packet_send_debug("Server does not permit empty password login."); + return 0; + } + + /* Get the encrypted password for the user. */ + pw = getpwnam(server_user); + if (!pw) + return 0; + +#ifdef HAVE_SECURID + /* Support for Security Dynamics SecurId card. + Contributed by Donald McKillican <dmckilli@qc.bell.ca>. */ +#if defined(KRB4) + if (options.kerberos_or_local_passwd) +#endif /* KRB4 */ + { + /* + * the way we decide if this user is a securid user or not is + * to check to see if they are included in /etc/securid.users + */ + int found = 0; + FILE *securid_users = fopen(SECURID_USERS, "r"); + char *c; + char su_user[257]; + + if (securid_users) + { + while (fgets(su_user, sizeof(su_user), securid_users)) + { + if (c = strchr(su_user, '\n')) + *c = '\0'; + if (strcmp(su_user, server_user) == 0) + { + found = 1; + break; + } + } + } + fclose(securid_users); + + if (found) + { + /* The user has a SecurID card. */ + struct SD_CLIENT sd_dat, *sd; + log("SecurID authentication for %.100s required.", server_user); + + /* + * if no pass code has been supplied, fail immediately: passing + * a null pass code to sd_check causes a core dump + */ + if (*password == '\0') + { + log("No pass code given, authentication rejected."); + return 0; + } + + sd = &sd_dat; + if (!securid_initialized) + { + memset(&sd_dat, 0, sizeof(sd_dat)); /* clear struct */ + creadcfg(); /* accesses sdconf.rec */ + if (sd_init(sd)) + packet_disconnect("Cannot contact securid server."); + securid_initialized = 1; + } + return sd_check(password, server_user, sd) == ACM_OK; + } + } + /* If the user has no SecurID card specified, we fall to normal + password code. */ +#endif /* HAVE_SECURID */ + + /* Save the encrypted password. */ + strncpy(correct_passwd, pw->pw_passwd, sizeof(correct_passwd)); + +#ifdef HAVE_OSF1_C2_SECURITY + osf1c2_getprpwent(correct_passwd, pw->pw_name, sizeof(correct_passwd)); +#else /* HAVE_OSF1_C2_SECURITY */ + /* If we have shadow passwords, lookup the real encrypted password from + the shadow file, and replace the saved encrypted password with the + real encrypted password. */ +#ifdef HAVE_SCO_ETC_SHADOW + { + struct pr_passwd *pr = getprpwnam(pw->pw_name); + pr = getprpwnam(pw->pw_name); + if (pr) + strncpy(correct_passwd, pr->ufld.fd_encrypt, sizeof(correct_passwd)); + endprpwent(); + } +#else /* HAVE_SCO_ETC_SHADOW */ +#ifdef HAVE_ETC_SHADOW + { + struct spwd *sp = getspnam(pw->pw_name); + if (sp) + strncpy(correct_passwd, sp->sp_pwdp, sizeof(correct_passwd)); + endspent(); + } +#else /* HAVE_ETC_SHADOW */ +#ifdef HAVE_ETC_SECURITY_PASSWD_ADJUNCT + { + struct passwd_adjunct *sp = getpwanam(pw->pw_name); + if (sp) + strncpy(correct_passwd, sp->pwa_passwd, sizeof(correct_passwd)); + endpwaent(); + } +#else /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */ +#ifdef HAVE_ETC_SECURITY_PASSWD + { + FILE *f; + char line[1024], looking_for_user[200], *cp; + int found_user = 0; + f = fopen("/etc/security/passwd", "r"); + if (f) + { + sprintf(looking_for_user, "%.190s:", server_user); + while (fgets(line, sizeof(line), f)) + { + if (strchr(line, '\n')) + *strchr(line, '\n') = 0; + if (strcmp(line, looking_for_user) == 0) + found_user = 1; + else + if (line[0] != '\t' && line[0] != ' ') + found_user = 0; + else + if (found_user) + { + for (cp = line; *cp == ' ' || *cp == '\t'; cp++) + ; + if (strncmp(cp, "password = ", strlen("password = ")) == 0) + { + strncpy(correct_passwd, cp + strlen("password = "), + sizeof(correct_passwd)); + correct_passwd[sizeof(correct_passwd) - 1] = 0; + break; + } + } + } + fclose(f); + } + } +#endif /* HAVE_ETC_SECURITY_PASSWD */ +#endif /* HAVE_ETC_SECURITY_PASSWD_ADJUNCT */ +#endif /* HAVE_ETC_SHADOW */ +#endif /* HAVE_SCO_ETC_SHADOW */ +#endif /* HAVE_OSF1_C2_SECURITY */ + + /* Check for users with no password. */ +#if defined(KRB4) + if (options.kerberos_or_local_passwd) +#endif /* KRB4 */ + if (strcmp(password, "") == 0 && strcmp(correct_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. */ +#ifdef HAVE_OSF1_C2_SECURITY + encrypted_password = (char *)osf1c2crypt(password, + (correct_passwd[0] && correct_passwd[1]) ? + correct_passwd : "xx"); +#else /* HAVE_OSF1_C2_SECURITY */ +#ifdef HAVE_SCO_ETC_SHADOW + encrypted_password = bigcrypt(password, + (correct_passwd[0] && correct_passwd[1]) ? + correct_passwd : "xx"); +#else /* HAVE_SCO_ETC_SHADOW */ + encrypted_password = crypt(password, + (correct_passwd[0] && correct_passwd[1]) ? + correct_passwd : "xx"); +#endif /* HAVE_SCO_ETC_SHADOW */ +#endif /* HAVE_OSF1_C2_SECURITY */ + + /* Authentication is accepted if the encrypted passwords are identical. */ +#if defined(KRB4) + if (options.kerberos_or_local_passwd) +#endif /* KRB4 */ + if (strcmp(encrypted_password, correct_passwd) == 0) + return 1; /* Success */ + +#if defined(KRB4) + 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 %.100s!", + server_user); + goto kerberos_auth_failure; + } + /* Try to get TGT using our password. */ + r = krb_get_pw_in_tkt(server_user, "", realm, "krbtgt", realm, + DEFAULT_TKT_LIFE, password); + if (r != INTK_OK) { + packet_send_debug("Kerberos V4 password authentication for %.100s " + "failed: %.100s", server_user, krb_err_txt[r]); + goto kerberos_auth_failure; + } + /* Successful authentication. */ + chown(ticket, pw->pw_uid, pw->pw_gid); + + (void) gethostname(localhost, sizeof(localhost)); + (void) strncpy(phost, (char *)krb_get_phost(localhost), INST_SZ); + phost[INST_SZ-1] = 0; + + /* 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 %.100s unverifiable, no srvtab? " + "krb_rd_req: %.100s", server_user, krb_err_txt[r]); + } + else if (r != KSUCCESS) { + log("Kerberos V4 %.100s ticket unverifiable: %.100s", + 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 %.100s unverifiable: %.100s; %.100s.%.100s " + "not registered, or srvtab is wrong?", server_user, + 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" + "%.100s: %.100s", server_user, krb_err_txt[r]); + goto kerberos_auth_failure; + } + + /* 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 */ + + return 0; /* Fail */ +} diff --git a/usr.bin/ssh/auth-rhosts.c b/usr.bin/ssh/auth-rhosts.c new file mode 100644 index 00000000000..0d325bb04df --- /dev/null +++ b/usr.bin/ssh/auth-rhosts.c @@ -0,0 +1,332 @@ +/* + +auth-rhosts.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.1 1999/09/26 20:53:33 deraadt Exp $"); + +#include "packet.h" +#include "ssh.h" +#include "xmalloc.h" +#include "uidswap.h" + +/* Returns true if the strings are equal, ignoring case (a-z only). */ + +static int casefold_equal(const char *a, const char *b) +{ + unsigned char cha, chb; + for (; *a; a++, b++) + { + cha = *a; + chb = *b; + if (!chb) + return 0; + if (cha >= 'a' && cha <= 'z') + cha -= 32; + if (chb >= 'a' && chb <= 'z') + chb -= 32; + if (cha != chb) + return 0; + } + return !*b; +} + +/* 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. */ + strncpy(userbuf, server_user, sizeof(userbuf)); + userbuf[sizeof(userbuf) - 1] = 0; + 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... */ + } + + 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; + } + +#ifdef HAVE_INNETGR + + /* Verify that host name matches. */ + if (host[0] == '@') + { + if (!innetgr(host + 1, hostname, NULL, NULL) && + !innetgr(host + 1, ipaddr, NULL, NULL)) + continue; + } + else + if (!casefold_equal(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. */ + +#else /* HAVE_INNETGR */ + + if (!casefold_equal(host, hostname) && strcmp(host, ipaddr) != 0) + continue; /* Different hostname. */ + + if (strcmp(user, client_user) != 0) + continue; /* Different username. */ + +#endif /* HAVE_INNETGR */ + + /* 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). */ + +int auth_rhosts(struct passwd *pw, const char *client_user, + int ignore_rhosts, int strict_modes) +{ + 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. */ + sprintf(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. */ + sprintf(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; +} diff --git a/usr.bin/ssh/authfd.c b/usr.bin/ssh/authfd.c new file mode 100644 index 00000000000..a09dc4c2541 --- /dev/null +++ b/usr.bin/ssh/authfd.c @@ -0,0 +1,669 @@ +/* + +authfd.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.1 1999/09/26 20:53:33 deraadt Exp $"); + +#include "ssh.h" +#include "rsa.h" +#include "authfd.h" +#include "buffer.h" +#include "bufaux.h" +#include "xmalloc.h" +#include "getput.h" + +/* Returns the number of the authentication fd, or -1 if there is none. */ + +int ssh_get_authentication_fd() +{ + const char *authfd, *authsocket; + int sock; + struct sockaddr_un sunaddr; + + /* Get the file descriptor number from environment. */ + authfd = getenv(SSH_AUTHFD_ENV_NAME); + + /* Convert the value to an integer and return it if we got a value. */ + if (authfd) + return atoi(authfd); + + authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); + if (!authsocket) + return -1; + + sunaddr.sun_family = AF_UNIX; + strncpy(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, AF_UNIX_SIZE(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_fd(). */ + +void ssh_close_authentication_socket(int sock) +{ + if (getenv(SSH_AUTHSOCKET_ENV_NAME)) + close(sock); +} + +/* Dummy alarm used to prevent waiting for connection from the + authentication agent indefinitely. */ + +static RETSIGTYPE dummy_alarm_handler(int sig) +{ + /* Do nothing; a cought signal will just cause accept to return. */ +} + +/* Opens a socket to the authentication server. Returns the number of + that socket, or -1 if no connection could be made. */ + +int ssh_get_authentication_connection_fd() +{ + int authfd; + int listen_sock, sock, port, addrlen; + int old_timeout; + RETSIGTYPE (*old_handler)(); + struct sockaddr_in sin; + char msg[3]; + + /* Get the the socket number from the environment. This is the socket + used to obtain the real authentication socket. */ + authfd = ssh_get_authentication_fd(); + if (authfd == -1) + return -1; + + /* Create a local socket for listening. */ + listen_sock = socket(AF_INET, SOCK_STREAM, 0); + if (listen_sock == -1) + { + ssh_close_authentication_socket(authfd); + return -1; + } + + /* Bind the socket to random unprivileged port. */ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + do + { + port = 32768 + (rand() % 30000); + sin.sin_port = htons(port); + } + while (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0 && + errno == EADDRINUSE); + + /* Start listening for connections on the socket. */ + if (listen(listen_sock, 1) < 0) + { + error("listen: %.100s", strerror(errno)); + close(listen_sock); + ssh_close_authentication_socket(authfd); + return -1; + } + + /* Send a message to the authentication fd requesting the agent or its + local representative to connect to the given socket. Note that + we use send() to get the packet sent atomically (there can be several + clients trying to use the same authentication fd simultaneously). */ + msg[0] = (char)SSH_AUTHFD_CONNECT; + PUT_16BIT(msg + 1, port); + if (send(authfd, msg, 3, 0) < 0) + { + shutdown(listen_sock, 2); + close(listen_sock); + ssh_close_authentication_socket(authfd); + return -1; + } + + /* Setup a timeout so we won't wait for the connection indefinitely. */ + old_timeout = alarm(120); + old_handler = signal(SIGALRM, dummy_alarm_handler); + + /* Wait for the connection from the agent or its representative. */ + addrlen = sizeof(sin); + sock = accept(listen_sock, (struct sockaddr *)&sin, &addrlen); + + /* Remove the alarm (restore its old values). */ + alarm(old_timeout); + signal(SIGALRM, old_handler); + + /* Close the socket we used for listening. It is no longer needed. + (The authentication fd and the new connection still remain open.) */ + shutdown(listen_sock, 2); + close(listen_sock); + ssh_close_authentication_socket(authfd); + + return 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. */ + +AuthenticationConnection *ssh_get_authentication_connection() +{ + AuthenticationConnection *auth; + int sock; + + /* Get a connection to the authentication agent. */ + sock = ssh_get_authentication_connection_fd(); + + /* 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; + + return auth; +} + +/* Closes the connection to the authentication agent and frees any associated + memory. */ + +void ssh_close_authentication_connection(AuthenticationConnection *ac) +{ + buffer_free(&ac->packet); + buffer_free(&ac->identities); + close(ac->fd); +} + +/* 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, MP_INT *e, MP_INT *n, char **comment) +{ + 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 (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); + + /* Return the first entry (if any). */ + return ssh_get_next_identity(auth, bitsp, 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. */ + +int ssh_get_next_identity(AuthenticationConnection *auth, + int *bitsp, MP_INT *e, MP_INT *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_mp_int(&auth->identities, e); + buffer_get_mp_int(&auth->identities, n); + *comment = buffer_get_string(&auth->identities, NULL); + + /* Decrement the number of remaining entries. */ + auth->howmany--; + + 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. */ + +int ssh_decrypt_challenge(AuthenticationConnection *auth, + int bits, MP_INT *e, MP_INT *n, MP_INT *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_mp_int(&buffer, e); + buffer_put_mp_int(&buffer, n); + buffer_put_mp_int(&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; +} + +/* Adds an identity to the authentication server. This call is not meant to + be used by normal applications. */ + +int ssh_add_identity(AuthenticationConnection *auth, + RSAPrivateKey *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, key->bits); + buffer_put_mp_int(&buffer, &key->n); + buffer_put_mp_int(&buffer, &key->e); + buffer_put_mp_int(&buffer, &key->d); + buffer_put_mp_int(&buffer, &key->u); + buffer_put_mp_int(&buffer, &key->p); + buffer_put_mp_int(&buffer, &key->q); + 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; +} + +/* Removes an identity from the authentication server. This call is not meant + to be used by normal applications. */ + +int ssh_remove_identity(AuthenticationConnection *auth, RSAPublicKey *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, key->bits); + buffer_put_mp_int(&buffer, &key->e); + buffer_put_mp_int(&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; +} + +/* 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; +} + +/* Closes the connection to the authentication agent. */ + +void ssh_close_authentication(AuthenticationConnection *auth) +{ + /* Close the connection. */ + shutdown(auth->fd, 2); + close(auth->fd); + + /* Free the buffers. */ + buffer_free(&auth->packet); + buffer_free(&auth->identities); + + /* Free the connection data structure. */ + xfree(auth); +} diff --git a/usr.bin/ssh/authfd.h b/usr.bin/ssh/authfd.h new file mode 100644 index 00000000000..77f92b85b89 --- /dev/null +++ b/usr.bin/ssh/authfd.h @@ -0,0 +1,109 @@ +/* + +authfd.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.1 1999/09/26 20:53:33 deraadt Exp $"); */ + +#ifndef AUTHFD_H +#define AUTHFD_H + +#include "buffer.h" + +/* Message types for SSH_AUTHENTICATION_FD socket. */ +#define SSH_AUTHFD_CONNECT 0xf0 + +/* Messages for the authentication agent connection. */ +#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 +#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 +#define SSH_AGENTC_RSA_CHALLENGE 3 +#define SSH_AGENT_RSA_RESPONSE 4 +#define SSH_AGENT_FAILURE 5 +#define SSH_AGENT_SUCCESS 6 +#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; + +/* Returns the number of the authentication fd, or -1 if there is none. */ +int ssh_get_authentication_fd(); + +/* This should be called for any descriptor returned by + ssh_get_authentication_fd(). Depending on the way the descriptor was + obtained, this may close the descriptor. */ +void ssh_close_authentication_socket(int authfd); + +/* Opens a socket to the authentication server. Returns the number of + that socket, or -1 if no connection could be made. */ +int ssh_get_authentication_connection_fd(); + +/* 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, MP_INT *e, MP_INT *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, MP_INT *e, MP_INT *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, MP_INT *e, MP_INT *n, MP_INT *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, + RSAPrivateKey *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, + RSAPublicKey *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); + +#endif /* AUTHFD_H */ diff --git a/usr.bin/ssh/authfile.c b/usr.bin/ssh/authfile.c new file mode 100644 index 00000000000..3fea2d14b1f --- /dev/null +++ b/usr.bin/ssh/authfile.c @@ -0,0 +1,315 @@ +/* + +authfile.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.1 1999/09/26 20:53:33 deraadt Exp $"); + +#include <gmp.h> +#include "xmalloc.h" +#include "idea.h" +#include "buffer.h" +#include "bufaux.h" +#include "cipher.h" +#include "ssh.h" + +/* 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. */ + +int save_private_key(const char *filename, const char *passphrase, + RSAPrivateKey *key, const char *comment, + RandomState *state) +{ + Buffer buffer, encrypted; + char buf[100], *cp; + int f, i; + CipherContext cipher; + int cipher_type; + + /* 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. */ + buf[0] = random_get_byte(state); + buf[1] = random_get_byte(state); + 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_mp_int(&buffer, &key->d); + buffer_put_mp_int(&buffer, &key->u); + buffer_put_mp_int(&buffer, &key->p); + buffer_put_mp_int(&buffer, &key->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, key->bits); + buffer_put_mp_int(&encrypted, &key->n); + buffer_put_mp_int(&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; +} + +/* 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, RSAPublicKey *pub, + char **comment_return) +{ + int f, i; + unsigned long 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)0L, 2); + lseek(f, (off_t)0L, 0); + + buffer_init(&buffer); + buffer_append_space(&buffer, &cp, len); + + if (read(f, cp, len) != 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); + 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. */ + pub->bits = buffer_get_int(&buffer); + mpz_init(&pub->n); + buffer_get_mp_int(&buffer, &pub->n); + mpz_init(&pub->e); + buffer_get_mp_int(&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; +} + +/* 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. */ + +int load_private_key(const char *filename, const char *passphrase, + RSAPrivateKey *prv, char **comment_return) +{ + int f, i, check1, check2, cipher_type; + unsigned long len; + Buffer buffer, decrypted; + char *cp; + CipherContext cipher; + + /* Read the file into the buffer. */ + f = open(filename, O_RDONLY); + if (f < 0) + return 0; + + len = lseek(f, (off_t)0L, 2); + lseek(f, (off_t)0L, 0); + + buffer_init(&buffer); + buffer_append_space(&buffer, &cp, len); + + if (read(f, cp, len) != 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); + 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. */ + prv->bits = buffer_get_int(&buffer); + mpz_init(&prv->n); + buffer_get_mp_int(&buffer, &prv->n); + mpz_init(&prv->e); + buffer_get_mp_int(&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() & (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: + mpz_clear(&prv->n); + mpz_clear(&prv->e); + if (comment_return) + xfree(*comment_return); + return 0; + } + + /* Read the rest of the private key. */ + mpz_init(&prv->d); + buffer_get_mp_int(&decrypted, &prv->d); + mpz_init(&prv->u); + buffer_get_mp_int(&decrypted, &prv->u); + mpz_init(&prv->p); + buffer_get_mp_int(&decrypted, &prv->p); + mpz_init(&prv->q); + buffer_get_mp_int(&decrypted, &prv->q); + + buffer_free(&decrypted); + + return 1; +} diff --git a/usr.bin/ssh/bf_enc.c b/usr.bin/ssh/bf_enc.c new file mode 100644 index 00000000000..66a8604c594 --- /dev/null +++ b/usr.bin/ssh/bf_enc.c @@ -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 diff --git a/usr.bin/ssh/bf_locl.h b/usr.bin/ssh/bf_locl.h new file mode 100644 index 00000000000..a5663de8cae --- /dev/null +++ b/usr.bin/ssh/bf_locl.h @@ -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_3; \ + u&=BF_M; \ + v&=BF_M; \ + t^= *(BF_LONG *)((unsigned char *)&(S[512])+u); \ + LL^=P; \ + t+= *(BF_LONG *)((unsigned char *)&(S[768])+v); \ + LL^=t; \ + } + +#elif defined(BF_PTR) + +/* This is normally very good */ + +#define BF_ENC(LL,R,S,P) \ + LL^=P; \ + LL^= (((*(BF_LONG *)((unsigned char *)&(S[ 0])+((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<<BF_3)&BF_M))); +#else + +/* This will always work, even on 64 bit machines and strangly enough, + * on the Alpha it is faster than the pointer versions (both 32 and 64 + * versions of BF_LONG) */ + +#define BF_ENC(LL,R,S,P) \ + LL^=P; \ + LL^=((( S[ (int)(R>>24L) ] + \ + S[0x0100+((int)(R>>16L)&0xff)])^ \ + S[0x0200+((int)(R>> 8L)&0xff)])+ \ + S[0x0300+((int)(R )&0xff)])&0xffffffffL; +#endif diff --git a/usr.bin/ssh/bf_pi.h b/usr.bin/ssh/bf_pi.h new file mode 100644 index 00000000000..417b9355385 --- /dev/null +++ b/usr.bin/ssh/bf_pi.h @@ -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, + } + }; + diff --git a/usr.bin/ssh/bf_skey.c b/usr.bin/ssh/bf_skey.c new file mode 100644 index 00000000000..86574c0acc4 --- /dev/null +++ b/usr.bin/ssh/bf_skey.c @@ -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 <stdio.h> +#include <string.h> +#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]; + } + } + diff --git a/usr.bin/ssh/blowfish.h b/usr.bin/ssh/blowfish.h new file mode 100644 index 00000000000..c4a8085a29c --- /dev/null +++ b/usr.bin/ssh/blowfish.h @@ -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 diff --git a/usr.bin/ssh/bufaux.c b/usr.bin/ssh/bufaux.c new file mode 100644 index 00000000000..4bc77f6684b --- /dev/null +++ b/usr.bin/ssh/bufaux.c @@ -0,0 +1,170 @@ +/* + +bufaux.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.1 1999/09/26 20:53:33 deraadt Exp $"); + +#include "ssh.h" +#include "gmp.h" +#include "bufaux.h" +#include "xmalloc.h" +#include "getput.h" + +/* Stores an MP_INT 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_mp_int(Buffer *buffer, MP_INT *value) +{ + int bits = mpz_sizeinbase(value, 2); + int hex_size = mpz_sizeinbase(value, 16); + char *buf = xmalloc(hex_size + 2); + int i, oi, byte; + char msg[2]; + + /* Get the value of the number in hex. Too bad that gmp does not allow + us to get it in binary. */ + mpz_get_str(buf, 16, value); + + /* i is "input index", oi is "output index". Both point to the same array, + and start from the beginning. "input index" moves twice as fast. */ + i = 0; + oi = 0; + /* Check for an odd number of hex digits. Process the odd digit + separately. */ + if (hex_size & 1) + { + sscanf(buf, "%1x", &byte); + buf[oi++] = byte; + i = 1; + } + + /* Convert the hex number into binary representation. */ + for (; i < hex_size; i += 2) + { + sscanf(buf + i, "%2x", &byte); + buf[oi++] = byte; + } + + assert(oi == ((bits + 7) / 8)); + /* 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, hex_size); + xfree(buf); +} + +/* Retrieves an MP_INT from the buffer. */ + +int buffer_get_mp_int(Buffer *buffer, MP_INT *value) +{ + int i, bits, bytes; + char *hex; + unsigned char buf[2]; + + /* 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; + /* Allocate space for a corresponding hex string. */ + hex = xmalloc(2 * bytes + 1); + + /* Read and convert the binary bytes into a hex string. */ + for (i = 0; i < bytes; i++) + { + unsigned char byte; + buffer_get(buffer, (char *)&byte, 1); + sprintf(hex + 2 * i, "%02x", byte); + } + /* Read the hex string into a mp-int. */ + mpz_set_str(value, hex, 16); + /* Free the string. */ + xfree(hex); + 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); +} diff --git a/usr.bin/ssh/bufaux.h b/usr.bin/ssh/bufaux.h new file mode 100644 index 00000000000..052cb14d630 --- /dev/null +++ b/usr.bin/ssh/bufaux.h @@ -0,0 +1,51 @@ +/* + +bufaux.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Wed Mar 29 02:18:23 1995 ylo + +*/ + +/* RCSID("$Id: bufaux.h,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); */ + +#ifndef BUFAUX_H +#define BUFAUX_H + +#include "buffer.h" + +/* Stores an MP_INT 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_mp_int(Buffer *buffer, MP_INT *value); + +/* Retrieves an MP_INT from the buffer. */ +int buffer_get_mp_int(Buffer *buffer, MP_INT *value); + +/* Returns an integer from the buffer (4 bytes, msb first). */ +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); + +/* Returns a character from the buffer (0 - 255). */ +int buffer_get_char(Buffer *buffer); + +/* Stores a character in the buffer. */ +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); + +/* Stores and arbitrary binary string in the buffer. */ +void buffer_put_string(Buffer *buffer, const void *buf, unsigned int len); + +#endif /* BUFAUX_H */ diff --git a/usr.bin/ssh/buffer.c b/usr.bin/ssh/buffer.c new file mode 100644 index 00000000000..0e81ac43588 --- /dev/null +++ b/usr.bin/ssh/buffer.c @@ -0,0 +1,150 @@ +/* + +buffer.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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 $"); + +#include "xmalloc.h" +#include "buffer.h" +#include "ssh.h" + +/* Initializes the buffer structure. */ + +void buffer_init(Buffer *buffer) +{ + 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) +{ + 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. */ + +void buffer_clear(Buffer *buffer) +{ + 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) +{ + 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) +{ + return buffer->end - buffer->offset; +} + +/* Gets data from the beginning of the buffer. */ + +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; +} + +/* Consumes the given number of bytes from the beginning of the buffer. */ + +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; +} + +/* Consumes the given number of bytes from the end of the buffer. */ + +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; +} + +/* Returns a pointer to the first used byte in the buffer. */ + +char *buffer_ptr(Buffer *buffer) +{ + return buffer->buf + buffer->offset; +} + +/* Dumps the contents of the buffer to stderr. */ + +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"); +} diff --git a/usr.bin/ssh/buffer.h b/usr.bin/ssh/buffer.h new file mode 100644 index 00000000000..f2bdac29651 --- /dev/null +++ b/usr.bin/ssh/buffer.h @@ -0,0 +1,66 @@ +/* + +buffer.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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; + +/* Initializes the buffer structure. */ +void buffer_init(Buffer *buffer); + +/* Frees any memory used for the 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); + +/* Appends data to the buffer, expanding it if necessary. */ +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); + +/* Returns the number of bytes of data in the 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); + +/* Consumes the given number of bytes from the beginning of the buffer. */ +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); + +/* Returns a pointer to the first used byte in the 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); + +#endif /* BUFFER_H */ diff --git a/usr.bin/ssh/canohost.c b/usr.bin/ssh/canohost.c new file mode 100644 index 00000000000..a30fbde7058 --- /dev/null +++ b/usr.bin/ssh/canohost.c @@ -0,0 +1,237 @@ +/* + +canohost.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.1 1999/09/26 20:53:34 deraadt 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. */ + +char *get_remote_hostname(int socket) +{ + struct sockaddr_in from; + int fromlen, i; + struct hostent *hp; + char name[512]; + + /* 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)); + strcpy(name, "UNKNOWN"); + 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) + strncpy(name, hp->h_name, sizeof(name)); + else if (hp->h_aliases != 0 + && hp->h_aliases[0] != 0 + && strchr(hp->h_aliases[0], '.') != 0) + strncpy(name, hp->h_aliases[0], sizeof(name)); + else + strncpy(name, hp->h_name, sizeof(name)); + name[sizeof(name) - 1] = '\0'; + + /* 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); + strcpy(name, inet_ntoa(from.sin_addr)); + 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); + strcpy(name, inet_ntoa(from.sin_addr)); + 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. */ + strcpy(name, inet_ntoa(from.sin_addr)); + log("Could not reverse map address %.100s.", name); + } + + check_ip_options: + +#ifdef 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); + } + } +#endif + + 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. */ + +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"); + + return canonical_host_name; +} + +/* Returns the IP-address of the remote host as a string. The returned + string need not be freed. */ + +const char *get_remote_ipaddr() +{ + 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; + } + + /* Get the IP address in ascii. */ + canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr)); + + /* Return ip address string. */ + return canonical_host_ip; +} + +/* Returns the port of the peer of the socket. */ + +int get_peer_port(int sock) +{ + 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); +} + +/* Returns the port number of the remote host. */ + +int get_remote_port() +{ + 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; + + /* Get client socket. */ + socket = packet_get_connection_in(); + + /* Get and return the peer port number. */ + return get_peer_port(socket); +} diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c new file mode 100644 index 00000000000..c6b2e21a3b9 --- /dev/null +++ b/usr.bin/ssh/channels.c @@ -0,0 +1,1559 @@ +/* + +channels.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.1 1999/09/26 20:53:34 deraadt Exp $"); + +#ifndef HAVE_GETHOSTNAME +#include <sys/utsname.h> +#endif +#include "ssh.h" +#include "packet.h" +#include "xmalloc.h" +#include "buffer.h" +#include "authfd.h" +#include "uidswap.h" + +/* Maximum number of fake X11 displays to try. */ +#define MAX_DISPLAYS 1000 + +/* 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 */ +#define SSH_CHANNEL_AUTH_FD 6 /* authentication fd */ +#define SSH_CHANNEL_AUTH_SOCKET 7 /* authentication socket */ +#define 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. */ + +typedef struct +{ + int type; + int sock; + int remote_id; + Buffer input; + Buffer output; + char path[200]; /* path for unix domain sockets, or host name for forwards */ + int host_port; /* port to connect for forwards */ + int listening_port; /* port being listened for forwards */ + char *remote_name; +} Channel; + +/* 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. */ +static int channels_alloc = 0; + +/* Maximum file descriptor value used in any of the channels. This is updated + in channel_allocate. */ +static int channel_max_fd_value = 0; + +/* These two variables are for authentication agent forwarding. */ +static int channel_forwarded_auth_fd = -1; +static char *channel_forwarded_auth_socket_name = NULL; + +/* Saved X11 authentication protocol name. */ +char *x11_saved_proto = NULL; + +/* Saved X11 authentication data. This is the real data. */ +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. */ +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. */ +} 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. */ +static int all_opens_permitted = 0; + +/* This is set to true if both sides support SSH_PROTOFLAG_HOST_IN_FWD_OPEN. */ +static int have_hostname_in_open = 0; + +/* Sets specific protocol options. */ + +void channel_set_options(int 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].type = type; + channels[i].sock = sock; + channels[i].remote_id = -1; + channels[i].remote_name = remote_name; + 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].type = type; + channels[old_channels].sock = sock; + channels[old_channels].remote_id = -1; + channels[old_channels].remote_name = remote_name; + return old_channels; +} + +/* Free the channel and close its socket. */ + +void channel_free(int channel) +{ + assert(channel >= 0 && channel < channels_alloc && + channels[channel].type != SSH_CHANNEL_FREE); + shutdown(channels[channel].sock, 2); + 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: + case SSH_CHANNEL_AUTH_SOCKET_FD: + case SSH_CHANNEL_AUTH_FD: + FD_SET(ch->sock, readset); + break; + + case SSH_CHANNEL_OPEN: + if (buffer_len(&ch->input) < 32768) + FD_SET(ch->sock, readset); + if (buffer_len(&ch->output) > 0) + FD_SET(ch->sock, writeset); + break; + + case SSH_CHANNEL_INPUT_DRAINING: + 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 (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; + 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); + 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(); + 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, port; + 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); + sprintf(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); + sprintf(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_FD: + /* This is the authentication agent file descriptor. It is used to + obtain the real connection to the agent. */ + case SSH_CHANNEL_AUTH_SOCKET_FD: + /* This is the temporary connection obtained by connecting the + authentication agent socket. */ + if (FD_ISSET(ch->sock, readset)) + { + len = recv(ch->sock, buf, sizeof(buf), 0); + if (len <= 0) + { + channel_free(i); + break; + } + if (len != 3 || (unsigned char)buf[0] != SSH_AUTHFD_CONNECT) + break; /* Ignore any messages of wrong length or type. */ + port = 256 * (unsigned char)buf[1] + (unsigned char)buf[2]; + packet_start(SSH_SMSG_AGENT_OPEN); + packet_put_int(port); + 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)) + { + len = sizeof(addr); + newsock = accept(ch->sock, &addr, &len); + if (newsock < 0) + error("Accept from authentication socket failed"); + (void)channel_allocate(SSH_CHANNEL_AUTH_SOCKET_FD, newsock, + xstrdup("accepted auth socket")); + } + 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. */ + if (FD_ISSET(ch->sock, readset)) + { + len = read(ch->sock, buf, sizeof(buf)); + if (len <= 0) + { + buffer_consume(&ch->output, buffer_len(&ch->output)); + ch->type = SSH_CHANNEL_INPUT_DRAINING; + debug("Channel %d status set to input draining.", i); + 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) + { + buffer_consume(&ch->output, buffer_len(&ch->output)); + debug("Channel %d status set to input draining.", i); + ch->type = SSH_CHANNEL_INPUT_DRAINING; + break; + } + buffer_consume(&ch->output, len); + } + break; + + case SSH_CHANNEL_OUTPUT_DRAINING: + /* 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() +{ + 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 + { + 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); + } + } +} + +/* 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 (channels[i].type) + { + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_AUTH_SOCKET_FD: + case SSH_CHANNEL_AUTH_FD: + 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; + } + } + return 1; +} + +/* This is called after receiving CHANNEL_CLOSE. */ + +void channel_input_close() +{ + 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); + + /* 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)); */ + } +} + +/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */ + +void channel_input_close_confirmation() +{ + 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 (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); +} + +/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */ + +void channel_input_open_confirmation() +{ + 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; +} + +/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */ + +void channel_input_open_failure() +{ + 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; + } + } +} + +/* 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() +{ + return channel_max_fd_value; +} + +/* Returns true if any channel is 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_FD: + case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_AUTH_SOCKET_FD: + continue; + case SSH_CHANNEL_OPENING: + case SSH_CHANNEL_OPEN: + case SSH_CHANNEL_X11_OPEN: + case SSH_CHANNEL_INPUT_DRAINING: + case SSH_CHANNEL_OUTPUT_DRAINING: + 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); + sprintf(buf, "The following connections are open:\r\n"); + buffer_append(&buffer, buf, strlen(buf)); + 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_FD: + case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_AUTH_SOCKET_FD: + continue; + case SSH_CHANNEL_OPENING: + case SSH_CHANNEL_OPEN: + case SSH_CHANNEL_X11_OPEN: + case SSH_CHANNEL_INPUT_DRAINING: + case SSH_CHANNEL_OUTPUT_DRAINING: + sprintf(buf, " %.300s\r\n", channels[i].remote_name); + buffer_append(&buffer, buf, strlen(buf)); + continue; + default: + fatal("channel_still_open: bad channel type %d", channels[i].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; + + 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; + sin.sin_addr.s_addr = INADDR_ANY; + 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 < 1024 && !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)); +#ifdef BROKEN_INET_ADDR + sin.sin_addr.s_addr = inet_network(host); +#else /* BROKEN_INET_ADDR */ + sin.sin_addr.s_addr = inet_addr(host); +#endif /* BROKEN_INET_ADDR */ + 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) +{ + int display_number, port, sock; + struct sockaddr_in sin; + char buf[512]; +#ifdef HAVE_GETHOSTNAME + char hostname[257]; +#else + struct utsname uts; +#endif + + for (display_number = 1; 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 = 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, 2); + 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, 2); + close(sock); + return NULL; + } + + /* Set up a suitable value for the DISPLAY variable. */ +#ifdef HPSUX_NONSTANDARD_X11_KLUDGE + /* HPSUX has some special shared memory stuff in their X server, which + appears to be enable if the host name matches that of the local machine. + However, it can be circumvented by using the IP address of the local + machine instead. */ + if (gethostname(hostname, sizeof(hostname)) < 0) + fatal("gethostname: %.100s", strerror(errno)); + { + struct hostent *hp; + struct in_addr addr; + hp = gethostbyname(hostname); + if (!hp->h_addr_list[0]) + { + error("Could not server IP address for %.200d.", hostname); + packet_send_debug("Could not get server IP address for %.200d.", + hostname); + shutdown(sock, 2); + close(sock); + return NULL; + } + memcpy(&addr, hp->h_addr_list[0], sizeof(addr)); + sprintf(buf, "%.100s:%d.%d", inet_ntoa(addr), display_number, + screen_number); + } +#else /* HPSUX_NONSTANDARD_X11_KLUDGE */ +#ifdef HAVE_GETHOSTNAME + if (gethostname(hostname, sizeof(hostname)) < 0) + fatal("gethostname: %.100s", strerror(errno)); + sprintf(buf, "%.400s:%d.%d", hostname, display_number, screen_number); +#else /* HAVE_GETHOSTNAME */ + if (uname(&uts) < 0) + fatal("uname: %s", strerror(errno)); + sprintf(buf, "%.400s:%d.%d", uts.nodename, display_number, screen_number); +#endif /* HAVE_GETHOSTNAME */ +#endif /* HPSUX_NONSTANDARD_X11_KLUDGE */ + + /* 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); +} + +#ifndef X_UNIX_PATH +#define X_UNIX_PATH "/tmp/.X11-unix/X" +#endif + +static +int +connect_local_xsocket(unsigned 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; + sprintf(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)); +#ifdef BROKEN_INET_ADDR + sin.sin_addr.s_addr = inet_network(buf); +#else /* BROKEN_INET_ADDR */ + sin.sin_addr.s_addr = inet_addr(buf); +#endif /* BROKEN_INET_ADDR */ + 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(RandomState *state, + 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; + + 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); + x11_saved_data[i] = value; + x11_fake_data[i] = random_get_byte(state); + } + 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() +{ + packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); + packet_send(); + packet_write_wait(); +} + +/* Returns the number of the file descriptor to pass to child programs as + the authentication fd. Returns -1 if there is no forwarded authentication + fd. */ + +int auth_get_fd() +{ + return channel_forwarded_auth_fd; +} + +/* 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() +{ + return channel_forwarded_auth_socket_name; +} + +/* 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 pfd = get_permanent_fd(pw->pw_shell); +#ifdef HAVE_UMASK + mode_t savedumask; +#endif /* HAVE_UMASK */ + + if (pfd < 0) + { + int sock, newch; + struct sockaddr_un sunaddr; + + if (auth_get_socket_name() != NULL) + fatal("Protocol error: authentication forwarding requested twice."); + + /* Allocate a buffer for the socket name, and format the name. */ + channel_forwarded_auth_socket_name = xmalloc(100); + sprintf(channel_forwarded_auth_socket_name, SSH_AGENT_SOCKET, + (int)getpid()); + + /* 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)); + +#ifdef HAVE_UMASK + savedumask = umask(0077); +#endif /* HAVE_UMASK */ + + /* Temporarily use a privileged uid. */ + temporarily_use_uid(pw->pw_uid); + + if (bind(sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)) < 0) + packet_disconnect("bind: %.100s", strerror(errno)); + + /* Restore the privileged uid. */ + restore_uid(); + +#ifdef HAVE_UMASK + umask(savedumask); +#endif /* HAVE_UMASK */ + + /* 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); + } + else + { + int sockets[2], i, cnt, newfd; + int *dups = xmalloc(sizeof (int) * (pfd + 1)); + + if (auth_get_fd() != -1) + fatal("Protocol error: authentication forwarding requested twice."); + + /* Create a socket pair. */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) + packet_disconnect("socketpair: %.100s", strerror(errno)); + + /* Dup some descriptors to get the authentication fd to pfd, + because some shells arbitrarily close descriptors below that. + Don't use dup2 because maybe some systems don't have it?? */ + for (cnt = 0;; cnt++) + { + if ((dups[cnt] = dup(packet_get_connection_in())) < 0) + fatal("auth_input_request_forwarding: dup failed"); + if (dups[cnt] == pfd) + break; + } + close(dups[cnt]); + + /* Move the file descriptor we pass to children up high where + the shell won't close it. */ + newfd = dup(sockets[1]); + if (newfd != pfd) + fatal ("auth_input_request_forwarding: dup didn't return %d.", pfd); + close(sockets[1]); + sockets[1] = newfd; + /* Close duped descriptors. */ + for (i = 0; i < cnt; i++) + close(dups[i]); + free(dups); + + /* Record the file descriptor to be passed to children. */ + channel_forwarded_auth_fd = sockets[1]; + + /* Allcate a channel for the authentication fd. */ + (void)channel_allocate(SSH_CHANNEL_AUTH_FD, sockets[0], + xstrdup("auth fd")); + } +} + +/* This is called to process an SSH_SMSG_AGENT_OPEN message. */ + +void auth_input_open_request() +{ + int port, sock, newch; + char *dummyname; + + /* Read the port number from the message. */ + port = packet_get_int(); + + /* Get a connection to the local authentication agent (this may again get + forwarded). */ + sock = ssh_get_authentication_connection_fd(); + + /* If we could not connect the agent, just return. This will cause the + client to timeout and fail. This should never happen unless the agent + dies, because authentication forwarding is only enabled if we have an + agent. */ + if (sock < 0) + 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"); + + /* Allocate a channel for the new connection. */ + newch = channel_allocate(SSH_CHANNEL_OPENING, sock, dummyname); + + /* Fake a forwarding request. */ + packet_start(SSH_MSG_PORT_OPEN); + packet_put_int(newch); + packet_put_string("localhost", strlen("localhost")); + packet_put_int(port); + if (have_hostname_in_open) + packet_put_string(dummyname, strlen(dummyname)); + packet_send(); +} diff --git a/usr.bin/ssh/check-fds.c b/usr.bin/ssh/check-fds.c new file mode 100644 index 00000000000..20e8bf5c1b3 --- /dev/null +++ b/usr.bin/ssh/check-fds.c @@ -0,0 +1,43 @@ +/* + +check-fds.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Apr 8 00:25:04 1995 ylo + +*/ + +#include <stdio.h> +RCSID("$Id: check-fds.c,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); + +#include <sys/types.h> +#include <fcntl.h> +#include <sys/stat.h> + +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); +} + diff --git a/usr.bin/ssh/cipher.c b/usr.bin/ssh/cipher.c new file mode 100644 index 00000000000..4711d9afce3 --- /dev/null +++ b/usr.bin/ssh/cipher.c @@ -0,0 +1,418 @@ +/* + +cipher.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Wed Apr 19 17:41:39 1995 ylo + +*/ + +#include "includes.h" +RCSID("$Id: cipher.c,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); + +#include "ssh.h" +#include "cipher.h" + +/* + * What kind of tripple DES are these 2 routines? + * + * Why is there a redundant initialization vector? + * + * If only iv3 was used, then, this would till effect have been + * outer-cbc. However, there is also a private iv1 == iv2 which + * perhaps makes differential analysis easier. On the other hand, the + * private iv1 probably makes the CRC-32 attack ineffective. This is a + * result of that there is no longer any known iv1 to use when + * choosing the X block. + */ +void +SSH_3CBC_ENCRYPT(des_key_schedule ks1, + des_key_schedule ks2, des_cblock *iv2, + des_key_schedule ks3, des_cblock *iv3, + void *dest, void *src, + unsigned int len) +{ + des_cblock iv1; + + memcpy(&iv1, iv2, 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, 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, + void *dest, void *src, + unsigned int len) +{ + des_cblock iv1; + + memcpy(&iv1, iv2, 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, ks1, &iv1, DES_DECRYPT); + /* memcpy(&iv1, iv2, 8); */ /* Note how iv1 == iv2 on entry and exit. */ +} + +#ifdef WITH_BLOWFISH +/* + * SSH uses a variation on Blowfish, all bytes must be swapped before + * and after encryption/decryption. Thus the swap_bytes stuff (yuk). + */ +static +void +swap_bytes(const unsigned char *src, unsigned char *dst_, int n) +{ + uint32 *dst = (uint32 *)dst_; /* dst must be properly aligned. */ + union { + uint32 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; + } +} +#endif /* WITH_BLOWFISH */ + +void (*cipher_attack_detected)(const char *fmt, ...) = fatal; + +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"); +} + +#ifdef WITH_IDEA +static inline +void +detect_cfb_attack(const unsigned char *src, + unsigned int len, + const unsigned char iv[8]) +{ + return; + + log("CRC-32 CFB insertion attack detected"); + cipher_attack_detected("CRC-32 CFB insertion attack detected"); +} +#endif /* WITH_IDEA */ + +/* Names of all encryption algorithms. These must match the numbers defined + int cipher.h. */ +static char *cipher_names[] = +{ "none", +#ifdef WITH_IDEA + "idea", +#else + "no idea", +#endif +#ifdef WITH_DES + "des", +#else + "no des", +#endif + "3des", + "no tss", +#ifdef WITH_RC4 + "rc4", +#else + "no rc4", +#endif +#ifdef WITH_BLOWFISH + "blowfish" +#else + "no blowfish" +#endif +}; + +/* 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_NONE; +#ifdef WITH_IDEA + mask |= 1 << SSH_CIPHER_IDEA; +#endif /* WITH_IDEA */ +#ifdef WITH_DES + mask |= 1 << SSH_CIPHER_DES; +#endif + mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ +#ifdef WITH_RC4 + mask |= 1 << SSH_CIPHER_RC4; +#endif +#ifdef WITH_BLOWFISH + mask |= 1 << SSH_CIPHER_BLOWFISH; +#endif + return mask; +} + +/* Returns the name of the cipher. */ + +const char *cipher_name(int cipher) +{ + if (cipher < 0 || cipher >= sizeof(cipher_names) / sizeof(cipher_names[0])) + 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. */ + +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) + 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. */ + +void cipher_set_key_string(CipherContext *context, int cipher, + const char *passphrase, int for_encryption) +{ + struct MD5Context 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)); +} + +/* 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: + break; + +#ifdef WITH_IDEA + case SSH_CIPHER_IDEA: + if (keylen < 16) + error("Key length %d is insufficient for IDEA.", keylen); + idea_set_key(&context->u.idea.key, padded); + memset(context->u.idea.iv, 0, sizeof(context->u.idea.iv)); + break; +#endif /* WITH_IDEA */ + +#ifdef WITH_DES + case SSH_CIPHER_DES: + /* Note: the least significant bit of each byte of key is parity, + and must be ignored by the implementation. 8 bytes of key are + used. */ + if (keylen < 8) + error("Key length %d is insufficient for DES.", keylen); + des_set_key((void*)padded, context->u.des.key); + memset(context->u.des.iv, 0, sizeof(context->u.des.iv)); + break; +#endif /* WITH_DES */ + + 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; + +#ifdef WITH_RC4 + case SSH_CIPHER_RC4: + rc4_init(&context->u.rc4, key, keylen); + break; +#endif /* WITH_RC4 */ + +#ifdef WITH_BLOWFISH + case SSH_CIPHER_BLOWFISH: + BF_set_key(&context->u.bf.key, keylen, padded); + memset(context->u.bf.iv, 0, 8); + break; +#endif /* WITH_BLOWFISH */ + + default: + fatal("cipher_set_key: unknown cipher: %d", 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; + +#ifdef WITH_IDEA + case SSH_CIPHER_IDEA: + idea_cfb_encrypt(&context->u.idea.key, context->u.idea.iv, + dest, src, len); + break; +#endif /* WITH_IDEA */ + +#ifdef WITH_DES + case SSH_CIPHER_DES: + des_cbc_encrypt((void*)src, (void*)dest, len, + context->u.des.key, &context->u.des.iv, DES_ENCRYPT); + memcpy(context->u.des.iv, dest + len - 8, 8); + break; +#endif /* WITH_DES */ + + 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; + +#ifdef WITH_RC4 + case SSH_CIPHER_RC4: + rc4_encrypt(&context->u.rc4, dest, src, len); + break; +#endif /* WITH_RC4 */ + +#ifdef WITH_BLOWFISH + 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; +#endif /* WITH_BLOWFISH */ + + default: + fatal("cipher_encrypt: unknown cipher: %d", 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); + + switch (context->type) + { + case SSH_CIPHER_NONE: + memcpy(dest, src, len); + break; + +#ifdef WITH_IDEA + case SSH_CIPHER_IDEA: + detect_cfb_attack(src, len, context->u.idea.iv); + idea_cfb_decrypt(&context->u.idea.key, context->u.idea.iv, + dest, src, len); + break; +#endif /* WITH_IDEA */ + +#ifdef WITH_DES + case SSH_CIPHER_DES: + detect_cbc_attack(src, len); + des_cbc_encrypt((void*)src, (void*)dest, len, + context->u.des.key, &context->u.des.iv, DES_DECRYPT); + memcpy(context->u.des.iv, src + len - 8, 8); + break; +#endif /* WITH_DES */ + + 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; + +#ifdef WITH_RC4 + case SSH_CIPHER_RC4: + /* CRC-32 attack? */ + rc4_decrypt(&context->u.rc4, dest, src, len); + break; +#endif /* WITH_RC4 */ + +#ifdef WITH_BLOWFISH + 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; +#endif /* WITH_BLOWFISH */ + + default: + fatal("cipher_decrypt: unknown cipher: %d", context->type); + } +} diff --git a/usr.bin/ssh/cipher.h b/usr.bin/ssh/cipher.h new file mode 100644 index 00000000000..3979006728d --- /dev/null +++ b/usr.bin/ssh/cipher.h @@ -0,0 +1,109 @@ +/* + +cipher.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Wed Apr 19 16:50:42 1995 ylo + +*/ + +/* RCSID("$Id: cipher.h,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); */ + +#ifndef CIPHER_H +#define CIPHER_H + +#ifdef WITH_IDEA +#include "idea.h" +#endif /* WITH_IDEA */ +#include "des.h" +#ifdef WITH_RC4 +#include "rc4.h" +#endif +#ifdef WITH_BLOWFISH +#include "blowfish.h" +#endif + +/* 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_BLOWFISH 6 + +typedef struct { + unsigned int type; + union { +#ifdef WITH_IDEA + struct { + IDEAContext key; + unsigned char iv[8]; + } idea; +#endif /* WITH_IDEA */ +#ifdef WITH_DES + struct { + des_key_schedule key; + des_cblock iv; + } des; +#endif /* WITH_DES */ + struct { + des_key_schedule key1; + des_key_schedule key2; + des_cblock iv2; + des_key_schedule key3; + des_cblock iv3; + } des3; +#ifdef WITH_RC4 + RC4Context rc4; +#endif +#ifdef WITH_BLOWFISH + struct { + struct bf_key_st key; + unsigned char iv[8]; + } bf; +#endif /* WITH_BLOWFISH */ + } 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); + +/* Encrypts data using the cipher. */ +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, ...); + +#endif /* CIPHER_H */ diff --git a/usr.bin/ssh/clientloop.c b/usr.bin/ssh/clientloop.c new file mode 100644 index 00000000000..6813f2cee3e --- /dev/null +++ b/usr.bin/ssh/clientloop.c @@ -0,0 +1,973 @@ +/* + +clientloop.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, 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.1 1999/09/26 20:53:34 deraadt Exp $"); + +#include "xmalloc.h" +#include "randoms.h" +#include "ssh.h" +#include "packet.h" +#include "buffer.h" +#include "authfd.h" + +/* Flag indicating whether quiet mode is on. */ +extern int quiet_flag; + +/* 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. */ +extern char *host; + +#ifdef SIGWINCH +/* 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; +#endif /* SIGWINCH */ + +/* Terminal modes, as saved by enter_raw_mode. */ +#ifdef USING_TERMIOS +static struct termios saved_tio; +#endif +#ifdef USING_SGTTY +static struct sgttyb saved_tio; +#endif + +/* 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 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. */ + +/* Returns the user\'s terminal to normal mode if it had been put in raw + mode. */ + +void leave_raw_mode() +{ + if (!in_raw_mode) + return; + in_raw_mode = 0; +#ifdef USING_TERMIOS + if (tcsetattr(fileno(stdin), TCSADRAIN, &saved_tio) < 0) + perror("tcsetattr"); +#endif /* USING_TERMIOS */ +#ifdef USING_SGTTY + if (ioctl(fileno(stdin), TIOCSETP, &saved_tio) < 0) + perror("ioctl(stdin, TIOCSETP, ...)"); +#endif /* USING_SGTTY */ + + fatal_remove_cleanup((void (*)(void *))leave_raw_mode, NULL); +} + +/* Puts the user\'s terminal in raw mode. */ + +void enter_raw_mode() +{ +#ifdef USING_TERMIOS + 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); +#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; +#endif /* USING_TERMIOS */ +#ifdef USING_SGTTY + struct sgttyb tio; + + if (ioctl(fileno(stdin), TIOCGETP, &tio) < 0) + perror("ioctl(stdin, TIOCGETP, ...)"); + saved_tio = tio; + tio.sg_flags &= ~(CBREAK | ECHO | CRMOD | LCASE | TANDEM); + tio.sg_flags |= (RAW | ANYP); + if (ioctl(fileno(stdin), TIOCSETP, &tio) < 0) + perror("ioctl(stdin, TIOCSETP, ...)"); + in_raw_mode = 1; +#endif /* USING_SGTTY */ + + fatal_add_cleanup((void (*)(void *))leave_raw_mode, NULL); +} + +/* Puts stdin terminal in non-blocking mode. */ + +/* 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); + } +} + +void enter_non_blocking() +{ + in_non_blocking_mode = 1; +#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) + (void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); +#else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + (void)fcntl(fileno(stdin), F_SETFL, O_NDELAY); +#endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + fatal_add_cleanup((void (*)(void *))leave_non_blocking, NULL); +} + +#ifdef SIGWINCH +/* Signal handler for the window change signal (SIGWINCH). This just + sets a flag indicating that the window has changed. */ + +RETSIGTYPE window_change_handler(int sig) +{ + received_window_change_signal = 1; + signal(SIGWINCH, window_change_handler); +} +#endif /* SIGWINCH */ + +/* Signal handler for signals that cause the program to terminate. These + signals must be trapped to restore terminal modes. */ + +RETSIGTYPE 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() +{ +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +#else /* HAVE_GETTIMEOFDAY */ + return (double)time(NULL); +#endif /* HAVE_GETTIMEOFDAY */ +} + +/* 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() +{ +#ifdef SIGWINCH + /* 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(); + } + } +#endif /* SIGWINCH */ +} + +/* 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. */ + sprintf(buf, "select: %.100s\r\n", strerror(errno)); + buffer_append(&stderr_buffer, buf, strlen(buf)); + stderr_bytes += strlen(buf); + quit_pending = 1; + } +} + +void client_suspend_self() +{ +#ifdef SIGWINCH + struct winsize oldws, newws; +#endif /* SIGWINCH */ + + /* 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); + +#ifdef SIGWINCH + /* Save old window size. */ + ioctl(fileno(stdin), TIOCGWINSZ, &oldws); +#endif /* SIGWINCH */ + + /* Send the suspend signal to the program + itself. */ + kill(getpid(), SIGTSTP); + +#ifdef SIGWINCH + /* 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; +#endif /* SIGWINCH */ + + /* 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. */ + sprintf(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. */ + sprintf(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) + { + sprintf(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. */ + sprintf(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 the user. */ + sprintf(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) + { + 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 '?': + sprintf(buf, "%c?\r\n\ +Supported escape sequences:\r\n\ +~. - terminate connection\r\n\ +~^Z - suspend ssh\r\n\ +~# - list forwarded connections\r\n\ +~& - background ssh (when waiting for connections to terminate)\r\n\ +~? - this message\r\n\ +~~ - send the escape character by typing it twice\r\n\ +(Note that escapes are only recognized immediately after newline.)\r\n", + escape_char); + buffer_append(&stderr_buffer, buf, strlen(buf)); + continue; + + case '#': + sprintf(buf, "%c#\r\n", escape_char); + buffer_append(&stderr_buffer, buf, strlen(buf)); + s = channel_open_message(); + buffer_append(&stderr_buffer, s, strlen(s)); + xfree(s); + continue; + + default: + if (ch != escape_char) + { + /* Escape character followed by non-special + character. Append both to the input + buffer. */ + buf[0] = escape_char; + buf[1] = ch; + buffer_append(&stdin_buffer, buf, 2); + stdin_bytes += 2; + continue; + } + /* Note that escape character typed twice falls through + here; the latter gets processed as a normal + character below. */ + break; + } + } + else + { + /* The previous character was not an escape char. + Check if this is an escape. */ + if (last_was_cr && ch == escape_char) + { + /* It is. Set the flag and continue to next + character. */ + escape_pending = 1; + continue; + } + } + + /* Normal character. Record whether it was a newline, + and append it to the buffer. */ + last_was_cr = (ch == '\r' || ch == '\n'); + buf[0] = ch; + buffer_append(&stdin_buffer, buf, 1); + stdin_bytes += 1; + continue; + } + } + } +} + +void client_process_output(fd_set *writeset) +{ + int len; + char buf[100]; + + /* Write buffered output to stdout. */ + if (FD_ISSET(fileno(stdout), writeset)) + { + /* Write as much data as possible. */ + len = write(fileno(stdout), buffer_ptr(&stdout_buffer), + buffer_len(&stdout_buffer)); + if (len <= 0) + { + if (errno == EAGAIN) + len = 0; + else + { + /* An error or EOF was encountered. Put an error message + to stderr buffer. */ + sprintf(buf, "write stdout: %.50s\r\n", strerror(errno)); + buffer_append(&stderr_buffer, buf, strlen(buf)); + stderr_bytes += strlen(buf); + quit_pending = 1; + return; + } + } + /* Consume printed data from the buffer. */ + buffer_consume(&stdout_buffer, len); + } + + /* Write buffered output to stderr. */ + if (FD_ISSET(fileno(stderr), writeset)) + { + /* Write as much data as possible. */ + len = write(fileno(stderr), buffer_ptr(&stderr_buffer), + buffer_len(&stderr_buffer)); + if (len <= 0) + if (errno == EAGAIN) + len = 0; + else + { + /* EOF or error, but can't even print error message. */ + quit_pending = 1; + return; + } + /* Consume printed characters from the buffer. */ + buffer_consume(&stderr_buffer, len); + } +} + +/* Implements the interactive session with the server. This is called + after the user has been authenticated, and a command has been + started on the remote host. If escape_char != -1, it is the character + used as an escape character for terminating or suspending the + session. */ + +int client_loop(int have_pty, int escape_char_arg) +{ + double start_time, total_time; + int len; + char buf[100]; + + debug("Entering interactive session."); + + start_time = get_current_time(); + + /* Initialize variables. */ + escape_pending = 0; + last_was_cr = 1; + exit_status = -1; + stdin_eof = 0; + buffer_high = 64 * 1024; + connection_in = packet_get_connection_in(); + connection_out = packet_get_connection_out(); + max_fd = connection_in; + if (connection_out > max_fd) + max_fd = connection_out; + stdin_bytes = 0; + stdout_bytes = 0; + stderr_bytes = 0; + quit_pending = 0; + escape_char = escape_char_arg; + + /* Initialize buffers. */ + buffer_init(&stdin_buffer); + buffer_init(&stdout_buffer); + buffer_init(&stderr_buffer); + + /* Set signal handlers to restore non-blocking mode. */ + signal(SIGINT, signal_handler); + signal(SIGQUIT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGPIPE, SIG_IGN); +#ifdef SIGWINCH + if (have_pty) + signal(SIGWINCH, window_change_handler); +#endif /* SIGWINCH */ + + /* Enter raw mode if have a pseudo terminal. */ + if (have_pty) + enter_raw_mode(); + + /* Check if we should immediately send of on stdin. */ + client_check_initial_eof_on_stdin(); + + /* Main loop of the client for the interactive session mode. */ + while (!quit_pending) + { + fd_set readset, writeset; + + /* Precess buffered packets sent by the server. */ + client_process_buffered_input_packets(); + + /* Make packets of buffered stdin data, and buffer them for sending + to the server. */ + client_make_packets_from_stdin_data(); + + /* Make packets from buffered channel data, and buffer them for sending + to the server. */ + if (packet_not_very_much_data_to_write()) + channel_output_poll(); + + /* Check if the window size has changed, and buffer a message about + it to the server if so. */ + client_check_window_change(); + + if (quit_pending) + break; + + /* Wait until we have something to do (something becomes available + on one of the descriptors). */ + client_wait_until_can_do_something(&readset, &writeset); + + if (quit_pending) + break; + + /* Do channel operations. */ + channel_after_select(&readset, &writeset); + + /* Process input from the connection and from stdin. Buffer any data + that is available. */ + client_process_input(&readset); + + /* Process output to stdout and stderr. Output to the connection + is processed elsewhere (above). */ + client_process_output(&writeset); + + /* Send as much buffered packet data as possible to the sender. */ + if (FD_ISSET(connection_out, &writeset)) + packet_write_poll(); + } + + /* Terminate the session. */ + +#ifdef SIGWINCH + /* Stop watching for window change. */ + if (have_pty) + signal(SIGWINCH, SIG_DFL); +#endif /* SIGWINCH */ + + /* Stop listening for connections. */ + channel_stop_listening(); + + /* In interactive mode (with pseudo tty) display a message indicating that + the connection has been closed. */ + if (have_pty && !quiet_flag) + { + sprintf(buf, "Connection to %.64s closed.\r\n", host); + buffer_append(&stderr_buffer, buf, strlen(buf)); + stderr_bytes += strlen(buf); + } + + /* Output any buffered data for stdout. */ + while (buffer_len(&stdout_buffer) > 0) + { + len = write(fileno(stdout), buffer_ptr(&stdout_buffer), + buffer_len(&stdout_buffer)); + if (len <= 0) + { + error("Write failed flushing stdout buffer."); + break; + } + buffer_consume(&stdout_buffer, len); + } + + /* Output any buffered data for stderr. */ + while (buffer_len(&stderr_buffer) > 0) + { + len = write(fileno(stderr), buffer_ptr(&stderr_buffer), + buffer_len(&stderr_buffer)); + if (len <= 0) + { + error("Write failed flushing stderr buffer."); + break; + } + buffer_consume(&stderr_buffer, len); + } + + /* Leave raw mode. */ + if (have_pty) + leave_raw_mode(); + + /* Clear and free any buffers. */ + memset(buf, 0, sizeof(buf)); + buffer_free(&stdin_buffer); + buffer_free(&stdout_buffer); + buffer_free(&stderr_buffer); + + /* Report bytes transferred, and transfer rates. */ + total_time = get_current_time() - start_time; + debug("Transferred: stdin %lu, stdout %lu, stderr %lu bytes in %.1f seconds", + stdin_bytes, stdout_bytes, stderr_bytes, total_time); + if (total_time > 0) + debug("Bytes per second: stdin %.1f, stdout %.1f, stderr %.1f", + stdin_bytes / total_time, stdout_bytes / total_time, + stderr_bytes / total_time); + + /* Return the exit status of the program. */ + debug("Exit status %d", exit_status); + return exit_status; +} diff --git a/usr.bin/ssh/compress.c b/usr.bin/ssh/compress.c new file mode 100644 index 00000000000..a6e2f0d4ae0 --- /dev/null +++ b/usr.bin/ssh/compress.c @@ -0,0 +1,160 @@ +/* + +compress.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Wed Oct 25 22:12:46 1995 ylo + +Interface to packet compression for ssh. + +*/ + +#include "includes.h" +RCSID("$Id: compress.c,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); + +#include "ssh.h" +#include "buffer.h" +#include "zlib.h" + +static z_stream incoming_stream; +static z_stream outgoing_stream; + +/* Initializes compression; level is compression level from 1 to 9 (as in + gzip). */ + +void buffer_compress_init(int level) +{ + debug("Enabling compression at level %d.", level); + if (level < 1 || level > 9) + fatal("Bad compression level %d.", level); + inflateInit(&incoming_stream); + deflateInit(&outgoing_stream, level); +} + +/* Frees any data structures allocated for compression. */ + +void buffer_compress_uninit() +{ + debug("compress outgoing: raw data %lu, compressed %lu, factor %.2f", + outgoing_stream.total_in, outgoing_stream.total_out, + outgoing_stream.total_in == 0 ? 0.0 : + (double)outgoing_stream.total_out / outgoing_stream.total_in); + debug("compress incoming: raw data %lu, compressed %lu, factor %.2f", + incoming_stream.total_out, incoming_stream.total_in, + incoming_stream.total_out == 0 ? 0.0 : + (double)incoming_stream.total_in / incoming_stream.total_out); + inflateEnd(&incoming_stream); + deflateEnd(&outgoing_stream); +} + +/* Compresses the contents of input_buffer into output_buffer. All + packets compressed using this function will form a single + compressed data stream; however, data will be flushed at the end of + every call so that each output_buffer can be decompressed + independently (but in the appropriate order since they together + form a single compression stream) by the receiver. This appends + the compressed data to the output buffer. */ + +void buffer_compress(Buffer *input_buffer, Buffer *output_buffer) +{ + char buf[4096]; + int status; + + /* This case is not handled below. */ + if (buffer_len(input_buffer) == 0) + return; + + /* Input is the contents of the input buffer. */ + outgoing_stream.next_in = buffer_ptr(input_buffer); + outgoing_stream.avail_in = buffer_len(input_buffer); + + /* Loop compressing until deflate() returns with avail_out != 0. */ + do + { + /* Set up fixed-size output buffer. */ + outgoing_stream.next_out = buf; + outgoing_stream.avail_out = sizeof(buf); + + /* Compress as much data into the buffer as possible. */ + status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH); + switch (status) + { + case Z_OK: + /* Append compressed data to output_buffer. */ + buffer_append(output_buffer, buf, + sizeof(buf) - outgoing_stream.avail_out); + break; + case Z_STREAM_END: + fatal("buffer_compress: deflate returned Z_STREAM_END"); + /*NOTREACHED*/ + case Z_STREAM_ERROR: + fatal("buffer_compress: deflate returned Z_STREAM_ERROR"); + /*NOTREACHED*/ + case Z_BUF_ERROR: + fatal("buffer_compress: deflate returned Z_BUF_ERROR"); + /*NOTREACHED*/ + default: + fatal("buffer_compress: deflate returned %d", status); + /*NOTREACHED*/ + } + } + while (outgoing_stream.avail_out == 0); +} + +/* Uncompresses the contents of input_buffer into output_buffer. All + packets uncompressed using this function will form a single + compressed data stream; however, data will be flushed at the end of + every call so that each output_buffer. This must be called for the + same size units that the buffer_compress was called, and in the + same order that buffers compressed with that. This appends the + uncompressed data to the output buffer. */ + +void buffer_uncompress(Buffer *input_buffer, Buffer *output_buffer) +{ + char buf[4096]; + int status; + + incoming_stream.next_in = buffer_ptr(input_buffer); + incoming_stream.avail_in = buffer_len(input_buffer); + + incoming_stream.next_out = buf; + incoming_stream.avail_out = sizeof(buf); + + for (;;) + { + status = inflate(&incoming_stream, Z_PARTIAL_FLUSH); + switch (status) + { + case Z_OK: + buffer_append(output_buffer, buf, + sizeof(buf) - incoming_stream.avail_out); + incoming_stream.next_out = buf; + incoming_stream.avail_out = sizeof(buf); + break; + case Z_STREAM_END: + fatal("buffer_uncompress: inflate returned Z_STREAM_END"); + /*NOTREACHED*/ + case Z_DATA_ERROR: + fatal("buffer_uncompress: inflate returned Z_DATA_ERROR"); + /*NOTREACHED*/ + case Z_STREAM_ERROR: + fatal("buffer_uncompress: inflate returned Z_STREAM_ERROR"); + /*NOTREACHED*/ + case Z_BUF_ERROR: + /* Comments in zlib.h say that we should keep calling inflate() + until we get an error. This appears to be the error that we + get. */ + return; + case Z_MEM_ERROR: + fatal("buffer_uncompress: inflate returned Z_MEM_ERROR"); + /*NOTREACHED*/ + default: + fatal("buffer_uncompress: inflate returned %d", status); + } + } +} + diff --git a/usr.bin/ssh/compress.h b/usr.bin/ssh/compress.h new file mode 100644 index 00000000000..c46e2ea7025 --- /dev/null +++ b/usr.bin/ssh/compress.h @@ -0,0 +1,46 @@ +/* + +compress.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Wed Oct 25 22:12:46 1995 ylo + +Interface to packet compression for ssh. + +*/ + +/* RCSID("$Id: compress.h,v 1.1 1999/09/26 20:53:34 deraadt Exp $"); */ + +#ifndef COMPRESS_H +#define COMPRESS_H + +/* Initializes compression; level is compression level from 1 to 9 (as in + gzip). */ +void buffer_compress_init(int level); + +/* Frees any data structures allocated by buffer_compress_init. */ +void buffer_compress_uninit(); + +/* Compresses the contents of input_buffer into output_buffer. All + packets compressed using this function will form a single + compressed data stream; however, data will be flushed at the end of + every call so that each output_buffer can be decompressed + independently (but in the appropriate order since they together + form a single compression stream) by the receiver. This appends + the compressed data to the output buffer. */ +void buffer_compress(Buffer *input_buffer, Buffer *output_buffer); + +/* Uncompresses the contents of input_buffer into output_buffer. All + packets uncompressed using this function will form a single + compressed data stream; however, data will be flushed at the end of + every call so that each output_buffer. This must be called for the + same size units that the buffer_compress was called, and in the + same order that buffers compressed with that. This appends the + uncompressed data to the output buffer. */ +void buffer_uncompress(Buffer *input_buffer, Buffer *output_buffer); + +#endif /* COMPRESS_H */ diff --git a/usr.bin/ssh/config.cache b/usr.bin/ssh/config.cache new file mode 100644 index 00000000000..3e1490d3a6b --- /dev/null +++ b/usr.bin/ssh/config.cache @@ -0,0 +1,102 @@ +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +ac_cv_c_bigendian=${ac_cv_c_bigendian=no} +ac_cv_c_const=${ac_cv_c_const=yes} +ac_cv_c_inline=${ac_cv_c_inline=inline} +ac_cv_func__getpty=${ac_cv_func__getpty=no} +ac_cv_func_clock=${ac_cv_func_clock=yes} +ac_cv_func_fchmod=${ac_cv_func_fchmod=yes} +ac_cv_func_getdtablesize=${ac_cv_func_getdtablesize=yes} +ac_cv_func_gethostname=${ac_cv_func_gethostname=yes} +ac_cv_func_getrusage=${ac_cv_func_getrusage=yes} +ac_cv_func_gettimeofday=${ac_cv_func_gettimeofday=yes} +ac_cv_func_initgroups=${ac_cv_func_initgroups=yes} +ac_cv_func_innetgr=${ac_cv_func_innetgr=yes} +ac_cv_func_memcpy=${ac_cv_func_memcpy=yes} +ac_cv_func_memmove=${ac_cv_func_memmove=yes} +ac_cv_func_openpty=${ac_cv_func_openpty=no} +ac_cv_func_popen=${ac_cv_func_popen=yes} +ac_cv_func_putenv=${ac_cv_func_putenv=yes} +ac_cv_func_random=${ac_cv_func_random=yes} +ac_cv_func_remove=${ac_cv_func_remove=yes} +ac_cv_func_seteuid=${ac_cv_func_seteuid=yes} +ac_cv_func_setlogin=${ac_cv_func_setlogin=yes} +ac_cv_func_setluid=${ac_cv_func_setluid=no} +ac_cv_func_setrlimit=${ac_cv_func_setrlimit=yes} +ac_cv_func_setsid=${ac_cv_func_setsid=yes} +ac_cv_func_socketpair=${ac_cv_func_socketpair=yes} +ac_cv_func_strchr=${ac_cv_func_strchr=yes} +ac_cv_func_strerror=${ac_cv_func_strerror=yes} +ac_cv_func_times=${ac_cv_func_times=yes} +ac_cv_func_ulimit=${ac_cv_func_ulimit=no} +ac_cv_func_umask=${ac_cv_func_umask=yes} +ac_cv_func_vhangup=${ac_cv_func_vhangup=no} +ac_cv_func_vsnprintf=${ac_cv_func_vsnprintf=yes} +ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h=yes} +ac_cv_header_gmp_h=${ac_cv_header_gmp_h=yes} +ac_cv_header_krb_h=${ac_cv_header_krb_h=no} +ac_cv_header_lastlog_h=${ac_cv_header_lastlog_h=no} +ac_cv_header_netinet_in_systm_h=${ac_cv_header_netinet_in_systm_h=yes} +ac_cv_header_paths_h=${ac_cv_header_paths_h=yes} +ac_cv_header_rusage_h=${ac_cv_header_rusage_h=no} +ac_cv_header_sgtty_h=${ac_cv_header_sgtty_h=yes} +ac_cv_header_stat_broken=${ac_cv_header_stat_broken=no} +ac_cv_header_stdc=${ac_cv_header_stdc=yes} +ac_cv_header_sys_filio_h=${ac_cv_header_sys_filio_h=yes} +ac_cv_header_sys_ioctl_h=${ac_cv_header_sys_ioctl_h=yes} +ac_cv_header_sys_select_h=${ac_cv_header_sys_select_h=yes} +ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h=yes} +ac_cv_header_sys_wait_h=${ac_cv_header_sys_wait_h=yes} +ac_cv_header_termios_h=${ac_cv_header_termios_h=yes} +ac_cv_header_time=${ac_cv_header_time=yes} +ac_cv_header_ulimit_h=${ac_cv_header_ulimit_h=no} +ac_cv_header_unistd_h=${ac_cv_header_unistd_h=yes} +ac_cv_header_usersec_h=${ac_cv_header_usersec_h=no} +ac_cv_header_utime_h=${ac_cv_header_utime_h=yes} +ac_cv_header_utmp_h=${ac_cv_header_utmp_h=yes} +ac_cv_header_utmpx_h=${ac_cv_header_utmpx_h=no} +ac_cv_header_zlib_h=${ac_cv_header_zlib_h=yes} +ac_cv_lib_c_crypt=${ac_cv_lib_c_crypt=yes} +ac_cv_lib_des_main=${ac_cv_lib_des_main=yes} +ac_cv_lib_dir_opendir=${ac_cv_lib_dir_opendir=no} +ac_cv_lib_gmp_main=${ac_cv_lib_gmp_main=yes} +ac_cv_lib_krb_main=${ac_cv_lib_krb_main=yes} +ac_cv_lib_nsl_main=${ac_cv_lib_nsl_main=no} +ac_cv_lib_socket_socket=${ac_cv_lib_socket_socket=no} +ac_cv_lib_sun_getpwnam=${ac_cv_lib_sun_getpwnam=no} +ac_cv_lib_util_login=${ac_cv_lib_util_login=yes} +ac_cv_lib_z_main=${ac_cv_lib_z_main=yes} +ac_cv_path_RSH_PATH=${ac_cv_path_RSH_PATH=/usr/bin/rsh} +ac_cv_path_WISH=${ac_cv_path_WISH=/usr/bin/true} +ac_cv_path_XAUTH_PATH=${ac_cv_path_XAUTH_PATH=/usr/X11R6/bin/xauth} +ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'} +ac_cv_prog_CC=${ac_cv_prog_CC=gcc} +ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'} +ac_cv_prog_LN_S=${ac_cv_prog_LN_S='ln -s'} +ac_cv_prog_MAKEDEP=${ac_cv_prog_MAKEDEP=makedepend} +ac_cv_prog_RANLIB=${ac_cv_prog_RANLIB=ranlib} +ac_cv_prog_cc_cross=${ac_cv_prog_cc_cross=no} +ac_cv_prog_cc_g=${ac_cv_prog_cc_g=yes} +ac_cv_prog_cc_works=${ac_cv_prog_cc_works=yes} +ac_cv_prog_gcc=${ac_cv_prog_gcc=yes} +ac_cv_sizeof_int=${ac_cv_sizeof_int=4} +ac_cv_sizeof_long=${ac_cv_sizeof_long=4} +ac_cv_sizeof_short=${ac_cv_sizeof_short=2} +ac_cv_struct_st_blksize=${ac_cv_struct_st_blksize=yes} +ac_cv_type_mode_t=${ac_cv_type_mode_t=yes} +ac_cv_type_off_t=${ac_cv_type_off_t=yes} +ac_cv_type_signal=${ac_cv_type_signal=void} +ac_cv_type_size_t=${ac_cv_type_size_t=yes} +ac_cv_type_uid_t=${ac_cv_type_uid_t=yes} diff --git a/usr.bin/ssh/config.guess b/usr.bin/ssh/config.guess new file mode 100644 index 00000000000..72f934d4003 --- /dev/null +++ b/usr.bin/ssh/config.guess @@ -0,0 +1,1012 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 97, 1998, 1999 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner <bothner@cygnus.com>. +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <<EOF >dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than generic posix subsystem? + # Should we change UNAME_MACHINE based on the output of uname + # instead of the specific alpha model. + echo alpha-pc-interix + exit 0;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + *9??*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9] ) + + sed 's/^ //' << EOF >dummy.c + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (${CC-cc} dummy.c -o dummy 2>/dev/null ) && HP_ARCH=`./dummy` + rm -f dummy.c dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + if test -x /usr/bin/objformat -a "elf" = "`/usr/bin/objformat`"; then + echo ${UNAME_MACHINE}-unknown-freebsdelf + else + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'` + fi + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin32 + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than generic posix subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # change UNAME_MACHINE based on the output of uname instead of + # i386? + echo i386-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin32 + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # uname on the ARM produces all sorts of strangeness, and we need to + # filter it out. + case "$UNAME_MACHINE" in + armv*) UNAME_MACHINE=$UNAME_MACHINE ;; + arm* | sa110*) UNAME_MACHINE="arm" ;; + esac + + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc | elf32ppclinux) + # Determine Lib Version + cat >dummy.c <<EOF +#include <features.h> +#if defined(__GLIBC__) +extern char __libc_version[]; +extern char __libc_release[]; +#endif +main(argc, argv) + int argc; + char *argv[]; +{ +#if defined(__GLIBC__) + printf("%s %s\n", __libc_version, __libc_release); +#else + printf("unkown\n"); +#endif + return 0; +} +EOF + LIBC="" + ${CC-cc} dummy.c -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy | grep 1\.99 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.c dummy + echo powerpc-unknown-linux-gnu${LIBC} ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <<EOF >dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c <<EOF +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >dummy.c <<EOF +#include <features.h> +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:5:7*) + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 +# 5.0.4c returns "Pent II". 5.0.5 returns PentII + (/bin/uname -X|egrep '^Machine.*Pent.*II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}${UNAME_VERSION}-sysv${UNAME_RELEASE} + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*PentII' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pent II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/usr.bin/ssh/config.h b/usr.bin/ssh/config.h new file mode 100644 index 00000000000..e4d202f9122 --- /dev/null +++ b/usr.bin/ssh/config.h @@ -0,0 +1,443 @@ +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.in by autoheader. */ +/* + +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 <ylo@cs.hut.fi> + +*/ + +#define RCSID(msg) \ +static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } + + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to `int' if <sys/types.h> doesn't define. */ +/* #undef gid_t */ + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define as __inline if that's what the C compiler calls it. */ +/* #undef inline */ + +/* Define to `int' if <sys/types.h> doesn't define. */ +/* #undef mode_t */ + +/* Define if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Define if your Fortran 77 compiler doesn't accept -c and -o together. */ +/* #undef F77_NO_MINUS_C_MINUS_O */ + +/* Define to `long' if <sys/types.h> doesn't define. */ +/* #undef off_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to the type of arg1 for select(). */ +/* #undef SELECT_TYPE_ARG1 */ + +/* Define to the type of args 2, 3 and 4 for select(). */ +/* #undef SELECT_TYPE_ARG234 */ + +/* Define to the type of arg5 for select(). */ +/* #undef SELECT_TYPE_ARG5 */ + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +/* #undef size_t */ + +/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both <sys/time.h> and <time.h>. */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to `int' if <sys/types.h> doesn't define. */ +/* #undef uid_t */ + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* 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. */ +#define HAVE_HOST_IN_UTMP 1 + +/* 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. */ +#define HAVE_NAME_IN_UTMP 1 + +/* 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 to use SSL. */ +#define DO_SSL 1 + +/* Define this to be the path of the rsh program to support executing rsh. */ +#define RSH_PATH "/usr/bin/rsh" + +/* Define this to be the path of the xauth program. */ +#define XAUTH_PATH "/usr/X11R6/bin/xauth" + +/* Default path for utmp. Determined by configure. */ +#define SSH_UTMP "/var/run/utmp" + +/* Default path for wtmp. Determined by configure. */ +#define SSH_WTMP "/var/log/wtmp" + +/* Default path for lastlog. Determined by configure. */ +#define SSH_LASTLOG "/var/log/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. */ +#define HAVE_LASTLOG 1 + +/* Define this if libutil.a contains BSD 4.4 compatible login(), logout(), + and logwtmp() calls. */ +#define HAVE_LIBUTIL_LOGIN 1 + +/* Location of system mail spool directory. */ +#define MAIL_SPOOL_DIRECTORY "/var/mail" + +/* 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=<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. */ +#define WITH_BLOWFISH 1 + +/* 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. */ +#define USE_PIPES 1 + +/* 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. */ +#define WITH_ZLIB 1 + +/* The number of bytes in a int. */ +#define SIZEOF_INT 4 + +/* The number of bytes in a long. */ +#define SIZEOF_LONG 4 + +/* The number of bytes in a short. */ +#define SIZEOF_SHORT 2 + +/* Define if you have the _getpty function. */ +/* #undef HAVE__GETPTY */ + +/* Define if you have the clock function. */ +#define HAVE_CLOCK 1 + +/* Define if you have the fchmod function. */ +#define HAVE_FCHMOD 1 + +/* Define if you have the getdtablesize function. */ +#define HAVE_GETDTABLESIZE 1 + +/* Define if you have the gethostname function. */ +#define HAVE_GETHOSTNAME 1 + +/* Define if you have the getrusage function. */ +#define HAVE_GETRUSAGE 1 + +/* Define if you have the gettimeofday function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define if you have the initgroups function. */ +#define HAVE_INITGROUPS 1 + +/* Define if you have the innetgr function. */ +#define HAVE_INNETGR 1 + +/* Define if you have the memcpy function. */ +#define HAVE_MEMCPY 1 + +/* Define if you have the memmove function. */ +#define HAVE_MEMMOVE 1 + +/* Define if you have the openpty function. */ +/* #undef HAVE_OPENPTY */ + +/* Define if you have the popen function. */ +#define HAVE_POPEN 1 + +/* Define if you have the putenv function. */ +#define HAVE_PUTENV 1 + +/* Define if you have the random function. */ +#define HAVE_RANDOM 1 + +/* Define if you have the remove function. */ +#define HAVE_REMOVE 1 + +/* Define if you have the seteuid function. */ +#define HAVE_SETEUID 1 + +/* Define if you have the setlogin function. */ +#define HAVE_SETLOGIN 1 + +/* Define if you have the setluid function. */ +/* #undef HAVE_SETLUID */ + +/* Define if you have the setrlimit function. */ +#define HAVE_SETRLIMIT 1 + +/* Define if you have the setsid function. */ +#define HAVE_SETSID 1 + +/* Define if you have the socketpair function. */ +#define HAVE_SOCKETPAIR 1 + +/* Define if you have the strchr function. */ +#define HAVE_STRCHR 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the times function. */ +#define HAVE_TIMES 1 + +/* Define if you have the ulimit function. */ +/* #undef HAVE_ULIMIT */ + +/* Define if you have the umask function. */ +#define HAVE_UMASK 1 + +/* Define if you have the vhangup function. */ +/* #undef HAVE_VHANGUP */ + +/* Define if you have the vsnprintf function. */ +#define HAVE_VSNPRINTF 1 + +/* Define if you have the <dirent.h> header file. */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the <gmp.h> header file. */ +#define HAVE_GMP_H 1 + +/* Define if you have the <krb.h> header file. */ +/* #undef HAVE_KRB_H */ + +/* Define if you have the <lastlog.h> header file. */ +/* #undef HAVE_LASTLOG_H */ + +/* Define if you have the <ndir.h> header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the <netinet/in_systm.h> header file. */ +#define HAVE_NETINET_IN_SYSTM_H 1 + +/* Define if you have the <paths.h> header file. */ +#define HAVE_PATHS_H 1 + +/* Define if you have the <rusage.h> header file. */ +/* #undef HAVE_RUSAGE_H */ + +/* Define if you have the <sgtty.h> header file. */ +#define HAVE_SGTTY_H 1 + +/* Define if you have the <sys/dir.h> header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the <sys/filio.h> header file. */ +#define HAVE_SYS_FILIO_H 1 + +/* Define if you have the <sys/ioctl.h> header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the <sys/ndir.h> header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the <sys/select.h> header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the <sys/time.h> header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the <termios.h> header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the <ulimit.h> header file. */ +/* #undef HAVE_ULIMIT_H */ + +/* Define if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the <usersec.h> header file. */ +/* #undef HAVE_USERSEC_H */ + +/* Define if you have the <utime.h> header file. */ +#define HAVE_UTIME_H 1 + +/* Define if you have the <utmp.h> header file. */ +#define HAVE_UTMP_H 1 + +/* Define if you have the <utmpx.h> header file. */ +/* #undef HAVE_UTMPX_H */ + +/* Define if you have the <zlib.h> header file. */ +#define HAVE_ZLIB_H 1 + +/* Define if you have the crypt library (-lcrypt). */ +/* #undef HAVE_LIBCRYPT */ + +/* Define if you have the des library (-ldes). */ +#define HAVE_LIBDES 1 + +/* Define if you have the gen library (-lgen). */ +/* #undef HAVE_LIBGEN */ + +/* Define if you have the gmp library (-lgmp). */ +#define HAVE_LIBGMP 1 + +/* Define if you have the krb library (-lkrb). */ +#define HAVE_LIBKRB 1 + +/* Define if you have the nsl library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define if you have the s library (-ls). */ +/* #undef HAVE_LIBS */ + +/* Define if you have the security library (-lsecurity). */ +/* #undef HAVE_LIBSECURITY */ + +/* Define if you have the socket library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define if you have the sun library (-lsun). */ +/* #undef HAVE_LIBSUN */ + +/* Define if you have the z library (-lz). */ +#define HAVE_LIBZ 1 diff --git a/usr.bin/ssh/config.h.in b/usr.bin/ssh/config.h.in new file mode 100644 index 00000000000..215a96e7cd9 --- /dev/null +++ b/usr.bin/ssh/config.h.in @@ -0,0 +1,442 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ +/* + +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 <ylo@cs.hut.fi> + +*/ + +#define RCSID(msg) \ +static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } + + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef gid_t + +/* Define if your struct stat has st_blksize. */ +#undef HAVE_ST_BLKSIZE + +/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define as __inline if that's what the C compiler calls it. */ +#undef inline + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef mode_t + +/* Define if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Define if your Fortran 77 compiler doesn't accept -c and -o together. */ +#undef F77_NO_MINUS_C_MINUS_O + +/* Define to `long' if <sys/types.h> doesn't define. */ +#undef off_t + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define to the type of arg1 for select(). */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for select(). */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg5 for select(). */ +#undef SELECT_TYPE_ARG5 + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +#undef size_t + +/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +#undef STAT_MACROS_BROKEN + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both <sys/time.h> and <time.h>. */ +#undef TIME_WITH_SYS_TIME + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef uid_t + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* 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 to use SSL. */ +#undef DO_SSL + +/* 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=<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 + +/* 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 + +/* The number of bytes in a int. */ +#undef SIZEOF_INT + +/* The number of bytes in a long. */ +#undef SIZEOF_LONG + +/* The number of bytes in a short. */ +#undef SIZEOF_SHORT + +/* Define if you have the _getpty function. */ +#undef HAVE__GETPTY + +/* Define if you have the clock function. */ +#undef HAVE_CLOCK + +/* Define if you have the fchmod function. */ +#undef HAVE_FCHMOD + +/* Define if you have the getdtablesize function. */ +#undef HAVE_GETDTABLESIZE + +/* Define if you have the gethostname function. */ +#undef HAVE_GETHOSTNAME + +/* Define if you have the getrusage function. */ +#undef HAVE_GETRUSAGE + +/* Define if you have the gettimeofday function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define if you have the initgroups function. */ +#undef HAVE_INITGROUPS + +/* Define if you have the innetgr function. */ +#undef HAVE_INNETGR + +/* Define if you have the memcpy function. */ +#undef HAVE_MEMCPY + +/* Define if you have the memmove function. */ +#undef HAVE_MEMMOVE + +/* Define if you have the openpty function. */ +#undef HAVE_OPENPTY + +/* Define if you have the popen function. */ +#undef HAVE_POPEN + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the random function. */ +#undef HAVE_RANDOM + +/* Define if you have the remove function. */ +#undef HAVE_REMOVE + +/* Define if you have the seteuid function. */ +#undef HAVE_SETEUID + +/* Define if you have the setlogin function. */ +#undef HAVE_SETLOGIN + +/* Define if you have the setluid function. */ +#undef HAVE_SETLUID + +/* Define if you have the setrlimit function. */ +#undef HAVE_SETRLIMIT + +/* Define if you have the setsid function. */ +#undef HAVE_SETSID + +/* Define if you have the socketpair function. */ +#undef HAVE_SOCKETPAIR + +/* Define if you have the strchr function. */ +#undef HAVE_STRCHR + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the times function. */ +#undef HAVE_TIMES + +/* Define if you have the ulimit function. */ +#undef HAVE_ULIMIT + +/* Define if you have the umask function. */ +#undef HAVE_UMASK + +/* Define if you have the vhangup function. */ +#undef HAVE_VHANGUP + +/* Define if you have the vsnprintf function. */ +#undef HAVE_VSNPRINTF + +/* Define if you have the <dirent.h> header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the <gmp.h> header file. */ +#undef HAVE_GMP_H + +/* Define if you have the <krb.h> header file. */ +#undef HAVE_KRB_H + +/* Define if you have the <lastlog.h> header file. */ +#undef HAVE_LASTLOG_H + +/* Define if you have the <ndir.h> header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the <netinet/in_systm.h> header file. */ +#undef HAVE_NETINET_IN_SYSTM_H + +/* Define if you have the <paths.h> header file. */ +#undef HAVE_PATHS_H + +/* Define if you have the <rusage.h> header file. */ +#undef HAVE_RUSAGE_H + +/* Define if you have the <sgtty.h> header file. */ +#undef HAVE_SGTTY_H + +/* Define if you have the <sys/dir.h> header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the <sys/filio.h> header file. */ +#undef HAVE_SYS_FILIO_H + +/* Define if you have the <sys/ioctl.h> header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define if you have the <sys/ndir.h> header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the <termios.h> header file. */ +#undef HAVE_TERMIOS_H + +/* Define if you have the <ulimit.h> header file. */ +#undef HAVE_ULIMIT_H + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the <usersec.h> header file. */ +#undef HAVE_USERSEC_H + +/* Define if you have the <utime.h> header file. */ +#undef HAVE_UTIME_H + +/* Define if you have the <utmp.h> header file. */ +#undef HAVE_UTMP_H + +/* Define if you have the <utmpx.h> header file. */ +#undef HAVE_UTMPX_H + +/* Define if you have the <zlib.h> header file. */ +#undef HAVE_ZLIB_H + +/* Define if you have the crypt library (-lcrypt). */ +#undef HAVE_LIBCRYPT + +/* Define if you have the des library (-ldes). */ +#undef HAVE_LIBDES + +/* Define if you have the gen library (-lgen). */ +#undef HAVE_LIBGEN + +/* Define if you have the gmp library (-lgmp). */ +#undef HAVE_LIBGMP + +/* Define if you have the krb library (-lkrb). */ +#undef HAVE_LIBKRB + +/* Define if you have the nsl library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define if you have the s library (-ls). */ +#undef HAVE_LIBS + +/* Define if you have the security library (-lsecurity). */ +#undef HAVE_LIBSECURITY + +/* Define if you have the socket library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define if you have the sun library (-lsun). */ +#undef HAVE_LIBSUN + +/* Define if you have the z library (-lz). */ +#undef HAVE_LIBZ diff --git a/usr.bin/ssh/config.log b/usr.bin/ssh/config.log new file mode 100644 index 00000000000..b318101a081 --- /dev/null +++ b/usr.bin/ssh/config.log @@ -0,0 +1,420 @@ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +configure:593: checking host system type +configure:617: checking for gcc +configure:730: checking whether the C compiler (gcc ) works +configure:746: gcc -o conftest conftest.c 1>&5 +configure:772: checking whether the C compiler (gcc ) is a cross-compiler +configure:777: checking whether we are using GNU C +configure:786: gcc -E conftest.c +configure:805: checking whether gcc accepts -g +configure:837: checking how to run the C preprocessor +configure:858: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1332: checking that the compiler works +configure:1341: gcc -o conftest -g -O2 conftest.c 1>&5 +configure:1358: checking if the compiler understands -pipe +configure:1369: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure:1397: checking for vhangup +configure:1425: gcc -pipe -o conftest -g -O2 conftest.c 1>&5 +configure:1419: Undefined symbol `_vhangup' referenced from text segment +collect2: ld returned 1 exit status +configure: failed program was: +#line 1402 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char vhangup(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vhangup(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vhangup) || defined (__stub___vhangup) +choke me +#else +vhangup(); +#endif + +; return 0; } +configure:1455: checking for setsid +configure:1483: gcc -pipe -o conftest -g -O2 conftest.c 1>&5 +configure:1510: checking where to find mandatory GMP library +configure:1535: checking for gmp.h +configure:1545: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1577: checking for main in -lgmp +configure:1592: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1636: checking for _getpty +configure:1664: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1658: Undefined symbol `__getpty' referenced from text segment +collect2: ld returned 1 exit status +configure: failed program was: +#line 1641 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _getpty(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _getpty(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__getpty) || defined (__stub____getpty) +choke me +#else +_getpty(); +#endif + +; return 0; } +configure:1636: checking for clock +configure:1664: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1636: checking for fchmod +configure:1664: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1636: checking for getdtablesize +configure:1664: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1636: checking for gethostname +configure:1664: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1636: checking for getrusage +configure:1664: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1691: checking for gettimeofday +configure:1719: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1691: checking for initgroups +configure:1719: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1691: checking for innetgr +configure:1719: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1691: checking for memcpy +configure:1719: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1703: warning: conflicting types for built-in function `memcpy' +configure:1691: checking for openpty +configure:1719: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1713: Undefined symbol `_openpty' referenced from text segment +collect2: ld returned 1 exit status +configure: failed program was: +#line 1696 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char openpty(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char openpty(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_openpty) || defined (__stub___openpty) +choke me +#else +openpty(); +#endif + +; return 0; } +configure:1691: checking for popen +configure:1719: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1691: checking for seteuid +configure:1719: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1746: checking for setlogin +configure:1774: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1746: checking for setluid +configure:1774: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1768: Undefined symbol `_setluid' referenced from text segment +collect2: ld returned 1 exit status +configure: failed program was: +#line 1751 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char setluid(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char setluid(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_setluid) || defined (__stub___setluid) +choke me +#else +setluid(); +#endif + +; return 0; } +configure:1746: checking for setrlimit +configure:1774: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1746: checking for strchr +configure:1774: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1746: checking for times +configure:1774: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1746: checking for ulimit +configure:1774: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1768: Undefined symbol `_ulimit' referenced from text segment +collect2: ld returned 1 exit status +configure: failed program was: +#line 1751 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char ulimit(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ulimit(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_ulimit) || defined (__stub___ulimit) +choke me +#else +ulimit(); +#endif + +; return 0; } +configure:1746: checking for umask +configure:1774: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1746: checking for vsnprintf +configure:1774: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1800: checking return type of signal handlers +configure:1822: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure:1841: checking for ANSI C header files +configure:1854: gcc -E conftest.c >/dev/null 2>conftest.out +configure:1921: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:1945: checking for size_t +configure:1978: checking for uid_t in sys/types.h +configure:2012: checking for off_t +configure:2045: checking for mode_t +configure:2078: checking for st_blksize in struct stat +configure:2091: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure:2113: checking for working const +configure:2167: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure:2188: checking for inline +configure:2202: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure:2228: checking whether byte ordering is bigendian +configure:2246: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure:2261: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure: In function `main': +configure:2256: syntax error before `big' +configure: failed program was: +#line 2250 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/param.h> +int main() { + +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif +; return 0; } +configure:2318: checking size of long +configure:2337: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:2357: checking size of int +configure:2376: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:2396: checking size of short +configure:2415: gcc -pipe -o conftest -g -O2 conftest.c -lgmp 1>&5 +configure:2440: checking for termios.h +configure:2450: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2479: checking for ANSI C header files +configure:2583: checking for sys/wait.h that is POSIX.1 compatible +configure:2604: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure:2628: checking for unistd.h +configure:2638: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2628: checking for rusage.h +configure:2638: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2634: rusage.h: No such file or directory +configure: failed program was: +#line 2633 "configure" +#include "confdefs.h" +#include <rusage.h> +configure:2628: checking for sys/time.h +configure:2638: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2628: checking for lastlog.h +configure:2638: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2634: lastlog.h: No such file or directory +configure: failed program was: +#line 2633 "configure" +#include "confdefs.h" +#include <lastlog.h> +configure:2628: checking for utmp.h +configure:2638: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2628: checking for utmpx.h +configure:2638: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2634: utmpx.h: No such file or directory +configure: failed program was: +#line 2633 "configure" +#include "confdefs.h" +#include <utmpx.h> +configure:2668: checking for sgtty.h +configure:2678: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2668: checking for sys/select.h +configure:2678: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2668: checking for sys/ioctl.h +configure:2678: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2668: checking for sys/filio.h +configure:2678: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2708: checking for paths.h +configure:2718: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2708: checking for usersec.h +configure:2718: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2714: usersec.h: No such file or directory +configure: failed program was: +#line 2713 "configure" +#include "confdefs.h" +#include <usersec.h> +configure:2708: checking for utime.h +configure:2718: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2708: checking for netinet/in_systm.h +configure:2718: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2708: checking for ulimit.h +configure:2718: gcc -E conftest.c >/dev/null 2>conftest.out +configure:2714: ulimit.h: No such file or directory +configure: failed program was: +#line 2713 "configure" +#include "confdefs.h" +#include <ulimit.h> +configure:2745: checking whether time.h and sys/time.h may both be included +configure:2759: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure:2784: checking for dirent.h that defines DIR +configure:2797: gcc -pipe -c -g -O2 conftest.c 1>&5 +configure:2822: checking for opendir in -ldir +configure:2841: gcc -pipe -o conftest -g -O2 conftest.c -ldir -lgmp 1>&5 +ld: -ldir: no match +collect2: ld returned 1 exit status +configure: failed program was: +#line 2830 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir(); + +int main() { +opendir() +; return 0; } +configure:2905: checking whether stat file-mode macros are broken +configure:3038: utmpx.h: No such file or directory +configure:3053: utmpx.h: No such file or directory +configure:3068: checking for crypt in -lc +configure:3087: gcc -pipe -o conftest -g -O2 conftest.c -lc -lgmp 1>&5 +configure:3155: checking for main in -lnsl +configure:3170: gcc -pipe -o conftest -g -O2 conftest.c -lnsl -lgmp 1>&5 +ld: -lnsl: no match +collect2: ld returned 1 exit status +configure: failed program was: +#line 3163 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +configure:3199: checking for socket in -lsocket +configure:3218: gcc -pipe -o conftest -g -O2 conftest.c -lsocket -lgmp 1>&5 +ld: -lsocket: no match +collect2: ld returned 1 exit status +configure: failed program was: +#line 3207 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket(); + +int main() { +socket() +; return 0; } +configure:3248: checking for getpwnam in -lsun +configure:3267: gcc -pipe -o conftest -g -O2 conftest.c -lsun -lgmp 1>&5 +ld: -lsun: no match +collect2: ld returned 1 exit status +configure: failed program was: +#line 3256 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char getpwnam(); + +int main() { +getpwnam() +; return 0; } +configure:3296: checking for login in -lutil +configure:3315: gcc -pipe -o conftest -g -O2 conftest.c -lutil -lgmp 1>&5 +configure:3341: checking for main in -ldes +configure:3356: gcc -pipe -o conftest -g -O2 conftest.c -ldes -lgmp -lutil 1>&5 +configure:3387: checking for strerror +configure:3415: gcc -pipe -o conftest -g -O2 conftest.c -ldes -lgmp -lutil 1>&5 +configure:3387: checking for memmove +configure:3415: gcc -pipe -o conftest -g -O2 conftest.c -ldes -lgmp -lutil 1>&5 +configure:3387: checking for remove +configure:3415: gcc -pipe -o conftest -g -O2 conftest.c -ldes -lgmp -lutil 1>&5 +configure:3387: checking for random +configure:3415: gcc -pipe -o conftest -g -O2 conftest.c -ldes -lgmp -lutil 1>&5 +configure:3387: checking for putenv +configure:3415: gcc -pipe -o conftest -g -O2 conftest.c -ldes -lgmp -lutil 1>&5 +configure:3387: checking for socketpair +configure:3415: gcc -pipe -o conftest -g -O2 conftest.c -ldes -lgmp -lutil 1>&5 +configure:3443: checking whether ln -s works +configure:3475: checking for a BSD compatible install +configure:3531: checking for ranlib +configure:3566: checking for makedepend +configure:3601: checking for wish8.0 +configure:3601: checking for wish +configure:3601: checking for wishx +configure:3601: checking for wish4.1 +configure:3601: checking for true +configure:3643: checking for xauth +configure:3683: checking for pseudo ttys +configure:3705: checking for /etc/default/login +configure:3718: checking for shadow passwords +configure:3743: checking location of mail spool files +configure:3764: checking location of utmp +configure:3800: checking location of wtmp +configure:3834: checking location of lastlog +configure:3889: checking whether /var/log/lastlog is a directory +configure:3902: checking whether to include the IDEA encryption algorithm +configure:3926: checking whether to include the RC4 encryption algorithm +configure:3950: checking whether to include the Blowfish encryption algorithm +configure:3982: checking whether to use rsaref +configure:4008: checking whether to use ssl +configure:4032: checking whether to use rsh +configure:4102: checking for remsh +configure:4102: checking for rsh +configure:4147: checking default path +configure:4170: checking etcdir +configure:4195: checking whether to support SecurID +configure:4238: checking whether to include compression support +configure:4262: checking for zlib.h +configure:4272: gcc -E conftest.c >/dev/null 2>conftest.out +configure:4303: checking for main in -lz +configure:4318: gcc -pipe -o conftest -g -O2 conftest.c -lz -lcrypto -ldes -lgmp -lutil 1>&5 +configure:4361: checking whether to use Kerberos v4 +configure:4530: checking for krb.h +configure:4540: gcc -E conftest.c >/dev/null 2>conftest.out +configure:4536: krb.h: No such file or directory +configure: failed program was: +#line 4535 "configure" +#include "confdefs.h" +#include <krb.h> +configure:4567: checking for main in -lkrb +configure:4582: gcc -pipe -o conftest -g -O2 conftest.c -lkrb -lz -lcrypto -ldes -lgmp -lutil 1>&5 +configure:4717: checking whether to use AFS +configure:4749: checking whether to use libwrap +configure:4815: checking whether to support SOCKS +configure:4884: checking where to put sshd.pid diff --git a/usr.bin/ssh/config.sample b/usr.bin/ssh/config.sample new file mode 100644 index 00000000000..34daeee5630 --- /dev/null +++ b/usr.bin/ssh/config.sample @@ -0,0 +1,62 @@ +# This is a sample per-user ssh configuration file. This file could be +# the user's .ssh/config. + +# Configuration data is parsed as follows: +# 1. command line options +# 2. user-specific file +# 3. system-wide file +# Any configuration value is only changed the first time it is set. +# Thus, host-specific definitions should be at the beginning of the +# configuration file, and defaults at the end. + +# System defaults will be used for anything not explicitly specified +# in this file. + +Host fake + HostName sparc.ngs.fi + UseRsh yes + +Host pooh + HostName pooh.tky.hut.fi + +Host shadows.cs.hut.fi shadows + RhostsAuthentication yes + KeepAlive no + RemoteForward 30000 olari.clinet.fi:23 + LocalForward 30001 lk-hp-13.hut.fi:23 + IdentityFile ~/.identityfiles/shadows + +Host ngs.fi *.ngs.fi + RhostsAuthentication no + FallBackToRsh no + PasswordAuthentication no + IdentityFile ~/.identityfiles/ngs + KeepAlive no + Compression yes + CompressionLevel 9 + +Host *.fr + UseRsh yes + +Host *.su + FallBackToRsh yes + Cipher none + PasswordAuthentication no + ForwardAgent no + +Host *.com *.edu *.gov *.mil *.org *.de *.uk + Cipher 3des + ForwardAgent no + +# Defaults for various options +Host * + ForwardAgent yes + ForwardX11 yes + RhostsAuthentication yes + PasswordAuthentication yes + RSAAuthentication yes + FallBackToRsh no + UseRsh no + IdentityFile ~/.ssh/identity + Port 22 + Cipher idea diff --git a/usr.bin/ssh/config.status b/usr.bin/ssh/config.status new file mode 100644 index 00000000000..63dfa66413e --- /dev/null +++ b/usr.bin/ssh/config.status @@ -0,0 +1,536 @@ +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host cvs.openbsd.org: +# +# ./configure --with-ssl +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]" +for ac_option +do + case "$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running ${CONFIG_SHELL-/bin/sh} ./configure --with-ssl --no-create --no-recursion" + exec ${CONFIG_SHELL-/bin/sh} ./configure --with-ssl --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "./config.status generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "$ac_cs_usage"; exit 0 ;; + *) echo "$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=. +ac_given_INSTALL="/usr/bin/install -c" + +trap 'rm -fr Makefile sshd.8 ssh.1 config.h conftest*; exit 1' 1 2 15 + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g; + s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF +/^[ ]*VPATH[ ]*=[^:]*$/d + +s%@SHELL@%/bin/sh%g +s%@CFLAGS@%-g -O2%g +s%@CPPFLAGS@%%g +s%@CXXFLAGS@%%g +s%@FFLAGS@%%g +s%@DEFS@%-DHAVE_CONFIG_H%g +s%@LDFLAGS@%%g +s%@LIBS@%-lkrb -lz -lcrypto -ldes -lgmp -lutil%g +s%@exec_prefix@%${prefix}%g +s%@prefix@%/usr/local%g +s%@program_transform_name@%s,x,x,%g +s%@bindir@%${exec_prefix}/bin%g +s%@sbindir@%${exec_prefix}/sbin%g +s%@libexecdir@%${exec_prefix}/libexec%g +s%@datadir@%${prefix}/share%g +s%@sysconfdir@%${prefix}/etc%g +s%@sharedstatedir@%${prefix}/com%g +s%@localstatedir@%${prefix}/var%g +s%@libdir@%${exec_prefix}/lib%g +s%@includedir@%${prefix}/include%g +s%@oldincludedir@%/usr/include%g +s%@infodir@%${prefix}/info%g +s%@mandir@%${prefix}/man%g +s%@host@%i386-unknown-openbsd2.5%g +s%@host_alias@%i386-unknown-openbsd2.5%g +s%@host_cpu@%i386%g +s%@host_vendor@%unknown%g +s%@host_os@%openbsd2.5%g +s%@CC@%gcc -pipe%g +s%@CPP@%gcc -E%g +s%@GMPINCS@%%g +s%@GMPLIBS@%-lgmp%g +s%@LIBOBJS@%%g +s%@LN_S@%ln -s%g +s%@INSTALL_PROGRAM@%${INSTALL}%g +s%@INSTALL_SCRIPT@%${INSTALL_PROGRAM}%g +s%@INSTALL_DATA@%${INSTALL} -m 644%g +s%@RANLIB@%ranlib%g +s%@MAKEDEP@%makedepend%g +s%@WISH@%/usr/local/bin/wish%g +s%@XAUTH_PATH@%/usr/X11R6/bin/xauth%g +s%@RSH_PATH@%/usr/bin/rsh%g +s%@KRB4_AUTH@%%g +s%@KRB4_ROOT@%%g +s%@KRB4_INCS@%%g +s%@KRB4_LIBS@%%g +s%@RADIX@%%g +s%@ETCDIR@%/etc%g +s%@PIDDIR@%/var/run%g +s%@RSAREFDEP@%%g +s%@CONFOBJS@% bf_skey.o bf_enc.o compress.o%g + +CEOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi + +CONFIG_FILES=${CONFIG_FILES-"Makefile sshd.8 ssh.1"} +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then + CONFIG_HEADERS="config.h" +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}USE_PIPES${ac_dB}USE_PIPES${ac_dC}1${ac_dD} +${ac_uA}USE_PIPES${ac_uB}USE_PIPES${ac_uC}1${ac_uD} +${ac_eA}USE_PIPES${ac_eB}USE_PIPES${ac_eC}1${ac_eD} +${ac_dA}HAVE_SETSID${ac_dB}HAVE_SETSID${ac_dC}1${ac_dD} +${ac_uA}HAVE_SETSID${ac_uB}HAVE_SETSID${ac_uC}1${ac_uD} +${ac_eA}HAVE_SETSID${ac_eB}HAVE_SETSID${ac_eC}1${ac_eD} +${ac_dA}HAVE_GMP_H${ac_dB}HAVE_GMP_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_GMP_H${ac_uB}HAVE_GMP_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_GMP_H${ac_eB}HAVE_GMP_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_LIBGMP${ac_dB}HAVE_LIBGMP${ac_dC}1${ac_dD} +${ac_uA}HAVE_LIBGMP${ac_uB}HAVE_LIBGMP${ac_uC}1${ac_uD} +${ac_eA}HAVE_LIBGMP${ac_eB}HAVE_LIBGMP${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_CLOCK${ac_dB}HAVE_CLOCK${ac_dC}1${ac_dD} +${ac_uA}HAVE_CLOCK${ac_uB}HAVE_CLOCK${ac_uC}1${ac_uD} +${ac_eA}HAVE_CLOCK${ac_eB}HAVE_CLOCK${ac_eC}1${ac_eD} +${ac_dA}HAVE_FCHMOD${ac_dB}HAVE_FCHMOD${ac_dC}1${ac_dD} +${ac_uA}HAVE_FCHMOD${ac_uB}HAVE_FCHMOD${ac_uC}1${ac_uD} +${ac_eA}HAVE_FCHMOD${ac_eB}HAVE_FCHMOD${ac_eC}1${ac_eD} +${ac_dA}HAVE_GETDTABLESIZE${ac_dB}HAVE_GETDTABLESIZE${ac_dC}1${ac_dD} +${ac_uA}HAVE_GETDTABLESIZE${ac_uB}HAVE_GETDTABLESIZE${ac_uC}1${ac_uD} +${ac_eA}HAVE_GETDTABLESIZE${ac_eB}HAVE_GETDTABLESIZE${ac_eC}1${ac_eD} +${ac_dA}HAVE_GETHOSTNAME${ac_dB}HAVE_GETHOSTNAME${ac_dC}1${ac_dD} +${ac_uA}HAVE_GETHOSTNAME${ac_uB}HAVE_GETHOSTNAME${ac_uC}1${ac_uD} +${ac_eA}HAVE_GETHOSTNAME${ac_eB}HAVE_GETHOSTNAME${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_GETRUSAGE${ac_dB}HAVE_GETRUSAGE${ac_dC}1${ac_dD} +${ac_uA}HAVE_GETRUSAGE${ac_uB}HAVE_GETRUSAGE${ac_uC}1${ac_uD} +${ac_eA}HAVE_GETRUSAGE${ac_eB}HAVE_GETRUSAGE${ac_eC}1${ac_eD} +${ac_dA}HAVE_GETTIMEOFDAY${ac_dB}HAVE_GETTIMEOFDAY${ac_dC}1${ac_dD} +${ac_uA}HAVE_GETTIMEOFDAY${ac_uB}HAVE_GETTIMEOFDAY${ac_uC}1${ac_uD} +${ac_eA}HAVE_GETTIMEOFDAY${ac_eB}HAVE_GETTIMEOFDAY${ac_eC}1${ac_eD} +${ac_dA}HAVE_INITGROUPS${ac_dB}HAVE_INITGROUPS${ac_dC}1${ac_dD} +${ac_uA}HAVE_INITGROUPS${ac_uB}HAVE_INITGROUPS${ac_uC}1${ac_uD} +${ac_eA}HAVE_INITGROUPS${ac_eB}HAVE_INITGROUPS${ac_eC}1${ac_eD} +${ac_dA}HAVE_INNETGR${ac_dB}HAVE_INNETGR${ac_dC}1${ac_dD} +${ac_uA}HAVE_INNETGR${ac_uB}HAVE_INNETGR${ac_uC}1${ac_uD} +${ac_eA}HAVE_INNETGR${ac_eB}HAVE_INNETGR${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_MEMCPY${ac_dB}HAVE_MEMCPY${ac_dC}1${ac_dD} +${ac_uA}HAVE_MEMCPY${ac_uB}HAVE_MEMCPY${ac_uC}1${ac_uD} +${ac_eA}HAVE_MEMCPY${ac_eB}HAVE_MEMCPY${ac_eC}1${ac_eD} +${ac_dA}HAVE_POPEN${ac_dB}HAVE_POPEN${ac_dC}1${ac_dD} +${ac_uA}HAVE_POPEN${ac_uB}HAVE_POPEN${ac_uC}1${ac_uD} +${ac_eA}HAVE_POPEN${ac_eB}HAVE_POPEN${ac_eC}1${ac_eD} +${ac_dA}HAVE_SETEUID${ac_dB}HAVE_SETEUID${ac_dC}1${ac_dD} +${ac_uA}HAVE_SETEUID${ac_uB}HAVE_SETEUID${ac_uC}1${ac_uD} +${ac_eA}HAVE_SETEUID${ac_eB}HAVE_SETEUID${ac_eC}1${ac_eD} +${ac_dA}HAVE_SETLOGIN${ac_dB}HAVE_SETLOGIN${ac_dC}1${ac_dD} +${ac_uA}HAVE_SETLOGIN${ac_uB}HAVE_SETLOGIN${ac_uC}1${ac_uD} +${ac_eA}HAVE_SETLOGIN${ac_eB}HAVE_SETLOGIN${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_SETRLIMIT${ac_dB}HAVE_SETRLIMIT${ac_dC}1${ac_dD} +${ac_uA}HAVE_SETRLIMIT${ac_uB}HAVE_SETRLIMIT${ac_uC}1${ac_uD} +${ac_eA}HAVE_SETRLIMIT${ac_eB}HAVE_SETRLIMIT${ac_eC}1${ac_eD} +${ac_dA}HAVE_STRCHR${ac_dB}HAVE_STRCHR${ac_dC}1${ac_dD} +${ac_uA}HAVE_STRCHR${ac_uB}HAVE_STRCHR${ac_uC}1${ac_uD} +${ac_eA}HAVE_STRCHR${ac_eB}HAVE_STRCHR${ac_eC}1${ac_eD} +${ac_dA}HAVE_TIMES${ac_dB}HAVE_TIMES${ac_dC}1${ac_dD} +${ac_uA}HAVE_TIMES${ac_uB}HAVE_TIMES${ac_uC}1${ac_uD} +${ac_eA}HAVE_TIMES${ac_eB}HAVE_TIMES${ac_eC}1${ac_eD} +${ac_dA}HAVE_UMASK${ac_dB}HAVE_UMASK${ac_dC}1${ac_dD} +${ac_uA}HAVE_UMASK${ac_uB}HAVE_UMASK${ac_uC}1${ac_uD} +${ac_eA}HAVE_UMASK${ac_eB}HAVE_UMASK${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_VSNPRINTF${ac_dB}HAVE_VSNPRINTF${ac_dC}1${ac_dD} +${ac_uA}HAVE_VSNPRINTF${ac_uB}HAVE_VSNPRINTF${ac_uC}1${ac_uD} +${ac_eA}HAVE_VSNPRINTF${ac_eB}HAVE_VSNPRINTF${ac_eC}1${ac_eD} +${ac_dA}RETSIGTYPE${ac_dB}RETSIGTYPE${ac_dC}void${ac_dD} +${ac_uA}RETSIGTYPE${ac_uB}RETSIGTYPE${ac_uC}void${ac_uD} +${ac_eA}RETSIGTYPE${ac_eB}RETSIGTYPE${ac_eC}void${ac_eD} +${ac_dA}STDC_HEADERS${ac_dB}STDC_HEADERS${ac_dC}1${ac_dD} +${ac_uA}STDC_HEADERS${ac_uB}STDC_HEADERS${ac_uC}1${ac_uD} +${ac_eA}STDC_HEADERS${ac_eB}STDC_HEADERS${ac_eC}1${ac_eD} +${ac_dA}HAVE_ST_BLKSIZE${ac_dB}HAVE_ST_BLKSIZE${ac_dC}1${ac_dD} +${ac_uA}HAVE_ST_BLKSIZE${ac_uB}HAVE_ST_BLKSIZE${ac_uC}1${ac_uD} +${ac_eA}HAVE_ST_BLKSIZE${ac_eB}HAVE_ST_BLKSIZE${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}SIZEOF_LONG${ac_dB}SIZEOF_LONG${ac_dC}4${ac_dD} +${ac_uA}SIZEOF_LONG${ac_uB}SIZEOF_LONG${ac_uC}4${ac_uD} +${ac_eA}SIZEOF_LONG${ac_eB}SIZEOF_LONG${ac_eC}4${ac_eD} +${ac_dA}SIZEOF_INT${ac_dB}SIZEOF_INT${ac_dC}4${ac_dD} +${ac_uA}SIZEOF_INT${ac_uB}SIZEOF_INT${ac_uC}4${ac_uD} +${ac_eA}SIZEOF_INT${ac_eB}SIZEOF_INT${ac_eC}4${ac_eD} +${ac_dA}SIZEOF_SHORT${ac_dB}SIZEOF_SHORT${ac_dC}2${ac_dD} +${ac_uA}SIZEOF_SHORT${ac_uB}SIZEOF_SHORT${ac_uC}2${ac_uD} +${ac_eA}SIZEOF_SHORT${ac_eB}SIZEOF_SHORT${ac_eC}2${ac_eD} +${ac_dA}HAVE_TERMIOS_H${ac_dB}HAVE_TERMIOS_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_TERMIOS_H${ac_uB}HAVE_TERMIOS_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_TERMIOS_H${ac_eB}HAVE_TERMIOS_H${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}STDC_HEADERS${ac_dB}STDC_HEADERS${ac_dC}1${ac_dD} +${ac_uA}STDC_HEADERS${ac_uB}STDC_HEADERS${ac_uC}1${ac_uD} +${ac_eA}STDC_HEADERS${ac_eB}STDC_HEADERS${ac_eC}1${ac_eD} +${ac_dA}HAVE_SYS_WAIT_H${ac_dB}HAVE_SYS_WAIT_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_SYS_WAIT_H${ac_uB}HAVE_SYS_WAIT_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_SYS_WAIT_H${ac_eB}HAVE_SYS_WAIT_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_UNISTD_H${ac_dB}HAVE_UNISTD_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_UNISTD_H${ac_uB}HAVE_UNISTD_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_UNISTD_H${ac_eB}HAVE_UNISTD_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_SYS_TIME_H${ac_dB}HAVE_SYS_TIME_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_SYS_TIME_H${ac_uB}HAVE_SYS_TIME_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_SYS_TIME_H${ac_eB}HAVE_SYS_TIME_H${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_UTMP_H${ac_dB}HAVE_UTMP_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_UTMP_H${ac_uB}HAVE_UTMP_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_UTMP_H${ac_eB}HAVE_UTMP_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_SGTTY_H${ac_dB}HAVE_SGTTY_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_SGTTY_H${ac_uB}HAVE_SGTTY_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_SGTTY_H${ac_eB}HAVE_SGTTY_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_SYS_SELECT_H${ac_dB}HAVE_SYS_SELECT_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_SYS_SELECT_H${ac_uB}HAVE_SYS_SELECT_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_SYS_SELECT_H${ac_eB}HAVE_SYS_SELECT_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_SYS_IOCTL_H${ac_dB}HAVE_SYS_IOCTL_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_SYS_IOCTL_H${ac_uB}HAVE_SYS_IOCTL_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_SYS_IOCTL_H${ac_eB}HAVE_SYS_IOCTL_H${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_SYS_FILIO_H${ac_dB}HAVE_SYS_FILIO_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_SYS_FILIO_H${ac_uB}HAVE_SYS_FILIO_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_SYS_FILIO_H${ac_eB}HAVE_SYS_FILIO_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_PATHS_H${ac_dB}HAVE_PATHS_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_PATHS_H${ac_uB}HAVE_PATHS_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_PATHS_H${ac_eB}HAVE_PATHS_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_UTIME_H${ac_dB}HAVE_UTIME_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_UTIME_H${ac_uB}HAVE_UTIME_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_UTIME_H${ac_eB}HAVE_UTIME_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_NETINET_IN_SYSTM_H${ac_dB}HAVE_NETINET_IN_SYSTM_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_NETINET_IN_SYSTM_H${ac_uB}HAVE_NETINET_IN_SYSTM_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_NETINET_IN_SYSTM_H${ac_eB}HAVE_NETINET_IN_SYSTM_H${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}TIME_WITH_SYS_TIME${ac_dB}TIME_WITH_SYS_TIME${ac_dC}1${ac_dD} +${ac_uA}TIME_WITH_SYS_TIME${ac_uB}TIME_WITH_SYS_TIME${ac_uC}1${ac_uD} +${ac_eA}TIME_WITH_SYS_TIME${ac_eB}TIME_WITH_SYS_TIME${ac_eC}1${ac_eD} +${ac_dA}HAVE_DIRENT_H${ac_dB}HAVE_DIRENT_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_DIRENT_H${ac_uB}HAVE_DIRENT_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_DIRENT_H${ac_eB}HAVE_DIRENT_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_NAME_IN_UTMP${ac_dB}HAVE_NAME_IN_UTMP${ac_dC}1${ac_dD} +${ac_uA}HAVE_NAME_IN_UTMP${ac_uB}HAVE_NAME_IN_UTMP${ac_uC}1${ac_uD} +${ac_eA}HAVE_NAME_IN_UTMP${ac_eB}HAVE_NAME_IN_UTMP${ac_eC}1${ac_eD} +${ac_dA}HAVE_HOST_IN_UTMP${ac_dB}HAVE_HOST_IN_UTMP${ac_dC}1${ac_dD} +${ac_uA}HAVE_HOST_IN_UTMP${ac_uB}HAVE_HOST_IN_UTMP${ac_uC}1${ac_uD} +${ac_eA}HAVE_HOST_IN_UTMP${ac_eB}HAVE_HOST_IN_UTMP${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_LIBUTIL_LOGIN${ac_dB}HAVE_LIBUTIL_LOGIN${ac_dC}1${ac_dD} +${ac_uA}HAVE_LIBUTIL_LOGIN${ac_uB}HAVE_LIBUTIL_LOGIN${ac_uC}1${ac_uD} +${ac_eA}HAVE_LIBUTIL_LOGIN${ac_eB}HAVE_LIBUTIL_LOGIN${ac_eC}1${ac_eD} +${ac_dA}HAVE_LIBDES${ac_dB}HAVE_LIBDES${ac_dC}1${ac_dD} +${ac_uA}HAVE_LIBDES${ac_uB}HAVE_LIBDES${ac_uC}1${ac_uD} +${ac_eA}HAVE_LIBDES${ac_eB}HAVE_LIBDES${ac_eC}1${ac_eD} +${ac_dA}HAVE_STRERROR${ac_dB}HAVE_STRERROR${ac_dC}1${ac_dD} +${ac_uA}HAVE_STRERROR${ac_uB}HAVE_STRERROR${ac_uC}1${ac_uD} +${ac_eA}HAVE_STRERROR${ac_eB}HAVE_STRERROR${ac_eC}1${ac_eD} +${ac_dA}HAVE_MEMMOVE${ac_dB}HAVE_MEMMOVE${ac_dC}1${ac_dD} +${ac_uA}HAVE_MEMMOVE${ac_uB}HAVE_MEMMOVE${ac_uC}1${ac_uD} +${ac_eA}HAVE_MEMMOVE${ac_eB}HAVE_MEMMOVE${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_REMOVE${ac_dB}HAVE_REMOVE${ac_dC}1${ac_dD} +${ac_uA}HAVE_REMOVE${ac_uB}HAVE_REMOVE${ac_uC}1${ac_uD} +${ac_eA}HAVE_REMOVE${ac_eB}HAVE_REMOVE${ac_eC}1${ac_eD} +${ac_dA}HAVE_RANDOM${ac_dB}HAVE_RANDOM${ac_dC}1${ac_dD} +${ac_uA}HAVE_RANDOM${ac_uB}HAVE_RANDOM${ac_uC}1${ac_uD} +${ac_eA}HAVE_RANDOM${ac_eB}HAVE_RANDOM${ac_eC}1${ac_eD} +${ac_dA}HAVE_PUTENV${ac_dB}HAVE_PUTENV${ac_dC}1${ac_dD} +${ac_uA}HAVE_PUTENV${ac_uB}HAVE_PUTENV${ac_uC}1${ac_uD} +${ac_eA}HAVE_PUTENV${ac_eB}HAVE_PUTENV${ac_eC}1${ac_eD} +${ac_dA}HAVE_SOCKETPAIR${ac_dB}HAVE_SOCKETPAIR${ac_dC}1${ac_dD} +${ac_uA}HAVE_SOCKETPAIR${ac_uB}HAVE_SOCKETPAIR${ac_uC}1${ac_uD} +${ac_eA}HAVE_SOCKETPAIR${ac_eB}HAVE_SOCKETPAIR${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}XAUTH_PATH${ac_dB}XAUTH_PATH${ac_dC}"/usr/X11R6/bin/xauth"${ac_dD} +${ac_uA}XAUTH_PATH${ac_uB}XAUTH_PATH${ac_uC}"/usr/X11R6/bin/xauth"${ac_uD} +${ac_eA}XAUTH_PATH${ac_eB}XAUTH_PATH${ac_eC}"/usr/X11R6/bin/xauth"${ac_eD} +${ac_dA}MAIL_SPOOL_DIRECTORY${ac_dB}MAIL_SPOOL_DIRECTORY${ac_dC}"/var/mail"${ac_dD} +${ac_uA}MAIL_SPOOL_DIRECTORY${ac_uB}MAIL_SPOOL_DIRECTORY${ac_uC}"/var/mail"${ac_uD} +${ac_eA}MAIL_SPOOL_DIRECTORY${ac_eB}MAIL_SPOOL_DIRECTORY${ac_eC}"/var/mail"${ac_eD} +${ac_dA}SSH_UTMP${ac_dB}SSH_UTMP${ac_dC}"/var/run/utmp"${ac_dD} +${ac_uA}SSH_UTMP${ac_uB}SSH_UTMP${ac_uC}"/var/run/utmp"${ac_uD} +${ac_eA}SSH_UTMP${ac_eB}SSH_UTMP${ac_eC}"/var/run/utmp"${ac_eD} +${ac_dA}SSH_WTMP${ac_dB}SSH_WTMP${ac_dC}"/var/log/wtmp"${ac_dD} +${ac_uA}SSH_WTMP${ac_uB}SSH_WTMP${ac_uC}"/var/log/wtmp"${ac_uD} +${ac_eA}SSH_WTMP${ac_eB}SSH_WTMP${ac_eC}"/var/log/wtmp"${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}SSH_LASTLOG${ac_dB}SSH_LASTLOG${ac_dC}"/var/log/lastlog"${ac_dD} +${ac_uA}SSH_LASTLOG${ac_uB}SSH_LASTLOG${ac_uC}"/var/log/lastlog"${ac_uD} +${ac_eA}SSH_LASTLOG${ac_eB}SSH_LASTLOG${ac_eC}"/var/log/lastlog"${ac_eD} +${ac_dA}HAVE_LASTLOG${ac_dB}HAVE_LASTLOG${ac_dC}1${ac_dD} +${ac_uA}HAVE_LASTLOG${ac_uB}HAVE_LASTLOG${ac_uC}1${ac_uD} +${ac_eA}HAVE_LASTLOG${ac_eB}HAVE_LASTLOG${ac_eC}1${ac_eD} +${ac_dA}WITH_BLOWFISH${ac_dB}WITH_BLOWFISH${ac_dC}1${ac_dD} +${ac_uA}WITH_BLOWFISH${ac_uB}WITH_BLOWFISH${ac_uC}1${ac_uD} +${ac_eA}WITH_BLOWFISH${ac_eB}WITH_BLOWFISH${ac_eC}1${ac_eD} +${ac_dA}DO_SSL${ac_dB}DO_SSL${ac_dC}1${ac_dD} +${ac_uA}DO_SSL${ac_uB}DO_SSL${ac_uC}1${ac_uD} +${ac_eA}DO_SSL${ac_eB}DO_SSL${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}RSH_PATH${ac_dB}RSH_PATH${ac_dC}"/usr/bin/rsh"${ac_dD} +${ac_uA}RSH_PATH${ac_uB}RSH_PATH${ac_uC}"/usr/bin/rsh"${ac_uD} +${ac_eA}RSH_PATH${ac_eB}RSH_PATH${ac_eC}"/usr/bin/rsh"${ac_eD} +${ac_dA}HAVE_ZLIB_H${ac_dB}HAVE_ZLIB_H${ac_dC}1${ac_dD} +${ac_uA}HAVE_ZLIB_H${ac_uB}HAVE_ZLIB_H${ac_uC}1${ac_uD} +${ac_eA}HAVE_ZLIB_H${ac_eB}HAVE_ZLIB_H${ac_eC}1${ac_eD} +${ac_dA}HAVE_LIBZ${ac_dB}HAVE_LIBZ${ac_dC}1${ac_dD} +${ac_uA}HAVE_LIBZ${ac_uB}HAVE_LIBZ${ac_uC}1${ac_uD} +${ac_eA}HAVE_LIBZ${ac_eB}HAVE_LIBZ${ac_eC}1${ac_eD} +${ac_dA}WITH_ZLIB${ac_dB}WITH_ZLIB${ac_dC}1${ac_dD} +${ac_uA}WITH_ZLIB${ac_uB}WITH_ZLIB${ac_uC}1${ac_uD} +${ac_eA}WITH_ZLIB${ac_eB}WITH_ZLIB${ac_eC}1${ac_eD} +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag <<CEOF +${ac_dA}HAVE_LIBKRB${ac_dB}HAVE_LIBKRB${ac_dC}1${ac_dD} +${ac_uA}HAVE_LIBKRB${ac_uB}HAVE_LIBKRB${ac_uC}1${ac_uD} +${ac_eA}HAVE_LIBKRB${ac_eB}HAVE_LIBKRB${ac_eC}1${ac_eD} +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + + + +exit 0 diff --git a/usr.bin/ssh/config.sub b/usr.bin/ssh/config.sub new file mode 100644 index 00000000000..567459eb1f5 --- /dev/null +++ b/usr.bin/ssh/config.sub @@ -0,0 +1,1238 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond ) # EGCS LOCAL + os= + basic_machine=$1 + ;; + -scout) # EGCS LOCAL + ;; + -wrs) # EGCS LOCAL + os=-vxworks + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 \ + | tron | a29k | 580 | i960 | h8300 \ + | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ + | alpha | alphaev5 | alphaev56 | alphapca56 | alphaev6 \ + | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \ + | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x) + basic_machine=$basic_machine-unknown + ;; + m88110 | m680[012346]0 | m683?2 | m68360 | m5200 | z8k | v70 \ + | h8500 | w65) # EGCS LOCAL + ;; + thumb) + basic_machine=$basic_machine-unknown + ;; + mips64vr4300 | mips64vr4300el) # EGCS LOCAL jsmith/vr4300 + basic_machine=$basic_machine-unknown + ;; + mips64vr4100 | mips64vr4100el) # EGCS LOCAL jsmith/vr4100 + basic_machine=$basic_machine-unknown + ;; + mips64vr5000 | mips64vr5000el) # EGCS LOCAL ian/vr5000 + basic_machine=$basic_machine-unknown + ;; + mips16) + basic_machine=$basic_machine-unknown + ;; + d10v) + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[34567]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* \ + | hppa-* | hppa1.0-* | hppa1.1-* \ + | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \ + | alpha-* | alphaev5-* | alphaev56-* | alphapca56-* \ + | alphaev6-* | we32k-* | cydra-* | ns16k-* | pn-* | np1-* \ + | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | sparcv9-* | sparc86x-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-* | arm*-*) + ;; + m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | h8500-* | d10v-*) # EGCS LOCAL + ;; + thumb-*) # EGCS LOCAL angela/thumb + ;; + v850-*) # EGCS LOCAL + ;; + d30v-*) # EGCS LOCAL + ;; + mips64vr4300-* | mips64vr4300el-*) # EGCS LOCAL jsmith/vr4300 + ;; + mips64vr4100-* | mips64vr4100el-*) # EGCS LOCAL jsmith/vr4100 + ;; + mips16-*) # EGCS LOCAL krk/mips16 + ;; + tic30-*) # EGCS LOCAL ian/tic30 + ;; + c30-*) # EGCS LOCAL ian/tic30 + basic_machine=tic30-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) # EGCS LOCAL + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) # EGCS LOCAL + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) # EGCS LOCAL + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) # EGCS LOCAL + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) # EGCS LOCAL + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) # EGCS LOCAL + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) # EGCS LOCAL + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + w89k-*) # EGCS LOCAL + basic_machine=hppa1.1-winbond + os=-proelf + ;; + op50n-*) # EGCS LOCAL + basic_machine=hppa1.1-oki + os=-proelf + ;; + op60c-*) # EGCS LOCAL + basic_machine=hppa1.1-oki + os=-proelf + ;; + hppro) # EGCS LOCAL + basic_machine=hppa1.1-hp + os=-proelf + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9] ) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9] ) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9] ) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | \ + hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893 ) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679] ) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) # EGCS LOCAL + basic_machine=hppa1.1-hp + os=-osf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) # EGCS LOCAL + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) # EGCS LOCAL + basic_machine=i386-unknown + os=-vsta + ;; + i386-go32 | go32) # EGCS LOCAL + basic_machine=i386-unknown + os=-go32 + ;; + i386-mingw32 | mingw32) + basic_machine=i386-unknown + os=-mingw32 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) # EGCS LOCAL + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) # EGCS LOCAL + basic_machine=i386-unknown + os=-msdos + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown # EGCS LOCAL + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-corel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) # EGCS LOCAL + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) # EGCS LOCAL + basic_machine=i960-intel + os=-mon960 + ;; + np1) + basic_machine=np1-gould + ;; + OSE68000 | ose68000) # EGCS LOCAL + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) # EGCS LOCAL + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rom68k) # EGCS LOCAL + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) # EGCS LOCAL + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) # EGCS LOCAL + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) # EGCS LOCAL + basic_machine=m68k-tandem + ;; + stratus) # EGCS LOCAL + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) # EGCS LOCAL + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) # EGCS LOCAL + basic_machine=w65-wdc + os=-none + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) # EGCS LOCAL + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) # EGCS LOCAL + basic_machine=hppa1.1-winbond + ;; + op50n) # EGCS LOCAL + basic_machine=hppa1.1-oki + ;; + op60c) # EGCS LOCAL + basic_machine=hppa1.1-oki + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc | sparcv9) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) # EGCS LOCAL + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) # EGCS LOCAL + basic_machine=powerpc-apple + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* ) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + # EGCS LOCAL + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mon960* | -lnews* ) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + # END EGCS LOCAL + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) # EGCS LOCAL + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) # EGCS LOCAL + os=-ose + ;; + -es1800*) # EGCS LOCAL + os=-ose + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-corel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) # EGCS LOCAL + os=-aout + ;; + mips*-cisco) # EGCS LOCAL + os=-elf + ;; + mips*-*) # EGCS LOCAL + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) # EGCS LOCAL + os=-proelf + ;; + *-winbond) # EGCS LOCAL + os=-proelf + ;; + *-oki) # EGCS LOCAL + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *-rom68k) # EGCS LOCAL + os=-coff + ;; + *-*bug) # EGCS LOCAL + os=-coff + ;; + *-apple) # EGCS LOCAL + os=-macos + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) # EGCS LOCAL + vendor=hitachi + ;; + -mpw* | -macos*) # EGCS LOCAL + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/usr.bin/ssh/configure b/usr.bin/ssh/configure new file mode 100644 index 00000000000..62007c509de --- /dev/null +++ b/usr.bin/ssh/configure @@ -0,0 +1,5293 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --enable-warnings Enable -Wall if using gcc." +ac_help="$ac_help + --with-gmp[=PATH] Where to find GMP library." +ac_help="$ac_help + --with-idea Use IDEA (not default). + --without-idea Don't use IDEA: avoids patent problems in commercial use" +ac_help="$ac_help + --with-rc4 Include RC4 support. + --without-rc4 Don't include RC4 support (default)" +ac_help="$ac_help + --with-blowfish Include Blowfish support (default). + --without-blowfish Don't include Blowfish support" +ac_help="$ac_help + --with-rsaref Use RSAREF (try to avoid patent problems in U.S.) + --without-rsaref Use normal RSA routines (default). " +ac_help="$ac_help + --with-ssl Use SSL (try to avoid patent problems in U.S.) + --without-ssl Use normal RSA routines (default). " +ac_help="$ac_help + --with-rsh=PATH Specify where to find rsh. + --without-rsh Do not use rsh under any conditions. " +ac_help="$ac_help + --with-path=PATH Default path passed to user shell by sshd." +ac_help="$ac_help + --with-etcdir=PATH Directory containing ssh system files (default /etc)." +ac_help="$ac_help + --with-securid[=PATH] Enable support for Security Dynamics SecurID card." +ac_help="$ac_help + --with-zlib Use zlib (default). + --without-zlib Don't use zlib." +ac_help="$ac_help + --with-krb4[=PATH] Compile in Kerberos v4 support." +ac_help="$ac_help + --with-afs Compile in AFS support (requires KTH krb4)." +ac_help="$ac_help + --with-libwrap[=PATH] Compile in libwrap (tcp_wrappers) support." +ac_help="$ac_help + --with-socks[=PATH] Compile with SOCKS firewall traversal support." + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=sshd.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:593: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:617: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:647: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:698: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:730: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 741 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:746: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:772: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:777: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:786: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:805: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:837: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 852 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:858: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 869 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:875: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 886 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:892: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + + +case "$host" in + *-*-sunos4.1.1*) + os_sunos=yes + # Tim Adam <tma@osa.com.au> says speed_t is defined in stdtypes.h + cat >> confdefs.h <<\EOF +#define SPEED_T_IN_STDTYPES_H 1 +EOF + + ;; + *-*-sunos*) + os_sunos=yes + ;; + *-sgi-irix5*) + # Irix stuff from snabb@niksula.hut.fi and tsurmacz@asic.ict.pwr.wroc.pl. + no_libsocket=yes + no_libsun=yes + ;; + *-sgi-irix6*) + # from d-champion@uchicago.edu + no_libsocket=yes + no_libsun=yes + if test "`uname -s`" = "IRIX64"; then + CFLAGS="-32 $CFLAGS" + LDFLAGS="-32 $LDFLAGS" + fi + ;; + *-ibm-aix3.2|*-ibm-aix3.2.0|*-ibm-aix3.2.1|*-ibm-aix3.2.2|*-ibm-aix3.2.3|*-ibm-aix3.2.4) + os_aix=yes + echo $ac_n "checking for getuserattr in -ls""... $ac_c" 1>&6 +echo "configure:946: checking for getuserattr in -ls" >&5 +ac_lib_var=`echo s'_'getuserattr | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ls $LIBS" +cat > conftest.$ac_ext <<EOF +#line 954 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char getuserattr(); + +int main() { +getuserattr() +; return 0; } +EOF +if { (eval echo configure:965: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo s | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-ls $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + ;; + *-ibm-aix*) + os_aix=yes + echo $ac_n "checking for getuserattr in -ls""... $ac_c" 1>&6 +echo "configure:996: checking for getuserattr in -ls" >&5 +ac_lib_var=`echo s'_'getuserattr | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ls $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1004 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char getuserattr(); + +int main() { +getuserattr() +; return 0; } +EOF +if { (eval echo configure:1015: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo s | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-ls $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + ;; + mips-dec-mach3*) + # Mach3 stuff from kivinen@hut.fi + no_vhangup=yes + ;; + *-dec-ultrix*) + # Ultrix stuff from dmckilli@qc.bell.ca, jbotz@orixa.mtholyoke.edu. + cat >> confdefs.h <<\EOF +#define O_NONBLOCK_BROKEN 1 +EOF + + no_vhangup=yes + cat > conftest.$ac_ext <<EOF +#line 1055 "configure" +#include "confdefs.h" +#include <syslog.h> +int main() { +int foo = LOG_DAEMON; +; return 0; } +EOF +if { (eval echo configure:1062: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define NEED_SYS_SYSLOG_H 1 +EOF + +fi +rm -f conftest* + ;; + *-*-hpux*) + # HPUX flags from jgotts@engin.umich.edu + if test -z "$GCC"; then + CFLAGS="$CFLAGS -Aa -D_HPUX_SOURCE" + fi + cat >> confdefs.h <<\EOF +#define HPSUX_NONSTANDARD_X11_KLUDGE 1 +EOF + + ;; + alpha-dec-osf*) + cat >> confdefs.h <<\EOF +#define TTY_GROUP "terminal" +EOF + + echo $ac_n "checking for set_auth_parameters in -lsecurity""... $ac_c" 1>&6 +echo "configure:1091: checking for set_auth_parameters in -lsecurity" >&5 +ac_lib_var=`echo security'_'set_auth_parameters | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsecurity $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1099 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char set_auth_parameters(); + +int main() { +set_auth_parameters() +; return 0; } +EOF +if { (eval echo configure:1110: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo security | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lsecurity $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + echo $ac_n "checking for OSF/1 C2 security package""... $ac_c" 1>&6 +echo "configure:1138: checking for OSF/1 C2 security package" >&5 + osfc2sec=`/usr/sbin/setld -i | grep '^OSFC2SEC'` + if test -n "$osfc2sec"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_OSF1_C2_SECURITY 1 +EOF + + echo $ac_n "checking for set_auth_parameters in -lsecurity""... $ac_c" 1>&6 +echo "configure:1147: checking for set_auth_parameters in -lsecurity" >&5 +ac_lib_var=`echo security'_'set_auth_parameters | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsecurity $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1155 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char set_auth_parameters(); + +int main() { +set_auth_parameters() +; return 0; } +EOF +if { (eval echo configure:1166: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lsecurity" +else + echo "$ac_t""no" 1>&6 +{ echo "configure: error: "Could not find libsecurity even though C2 security installed."" 1>&2; exit 1; } +fi + + CONFOBJS="$CONFOBJS osfc2.o" + else + echo "$ac_t""no" 1>&6 + fi + ;; + *-*-nextstep*) + # Nextstep support from a person who wants to remain anonymous + no_termios=yes + cat >> confdefs.h <<\EOF +#define SPEED_T_IN_STDTYPES_H 1 +EOF + + ;; + *-*-linux*) + # Linux shadow password support (Andrew.Macpherson.1248566@bnr.co.uk) + if test -f /etc/shadow && test -f /etc/login.defs; then + echo "$ac_t""Using linux John Haugh shadow passwords and pw_encrypt for password encryption" 1>&6 + cat >> confdefs.h <<\EOF +#define crypt pw_encrypt +EOF + + LIBS="$LIBS -lshadow" + fi + ;; + i*86-*-bsdi*) + no_pipe=yes + ;; + i*86-unknown-bsd*) + # Assume 386BSD. pgut01@cs.auckland.ac.nz reported this makes it compile. + cat >> confdefs.h <<\EOF +#define __FreeBSD__ 1 +EOF + + ;; + m68k-sony-newsos*) + # From snabb@niksula.hut.fi + no_vhangup=yes + ;; + m88k-dg-dgux*) + cat >> confdefs.h <<\EOF +#define BROKEN_INET_ADDR 1 +EOF + + ;; + *-cray-unicos*) + CFLAGS="$CFLAGS -DCRAY_STACKSEG_END=_getb67" + ;; + *-*-sysv4*) + echo $ac_n "checking for openlog in -lgen""... $ac_c" 1>&6 +echo "configure:1236: checking for openlog in -lgen" >&5 +ac_lib_var=`echo gen'_'openlog | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lgen $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1244 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char openlog(); + +int main() { +openlog() +; return 0; } +EOF +if { (eval echo configure:1255: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo gen | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lgen $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + ;; + *-*-machten*) + cat >> confdefs.h <<\EOF +#define USE_STRLEN_FOR_AF_UNIX 1 +EOF + + ;; + i*86-unknown-sco*) + # From moi@dio.com + cat >> confdefs.h <<\EOF +#define HAVE_SCO_ETC_SHADOW 1 +EOF + + cat >> confdefs.h <<\EOF +#define SCO 1 +EOF + + no_ranlib=yes + LIBS="-L/usr/lib/libp -lprot -lx $LIBS" + ;; + *-convex-bsd*) + # From mark.martinec@nsc.ijs.si + # On Convex, getpwnam sets pw_passwd if running as root + no_shadows_password_checking=yes + ;; + *-*-freebsd*) + # From Ollivier Robert: FreeBSD and NetBSD use master.passwd, but set + # pw_passwd automatically when running as root. + no_shadow_password_checking=yes + ;; + *-*-netbsd*) + # From Ollivier Robert: FreeBSD and NetBSD use master.passwd, but set + # pw_passwd automatically when running as root. + no_shadow_password_checking=yes + ;; + *-*-openbsd*) + no_shadow_password_checking=yes + ;; + *) + ;; +esac + +# Socket pairs appear to be broken on several systems. I don't know exactly +# where, so I'll use pipes everywhere for now. +cat >> confdefs.h <<\EOF +#define USE_PIPES 1 +EOF + + +echo $ac_n "checking that the compiler works""... $ac_c" 1>&6 +echo "configure:1332: checking that the compiler works" >&5 +if test "$cross_compiling" = yes; then + { echo "configure: error: Could not compile and run even a trivial ANSI C program - check CC." 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 1337 "configure" +#include "confdefs.h" + main(int ac, char **av) { return 0; } +EOF +if { (eval echo configure:1341: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + echo "$ac_t""no" 1>&6 + { echo "configure: error: Could not compile and run even a trivial ANSI C program - check CC." 1>&2; exit 1; } +fi +rm -fr conftest* +fi + + +if test -z "$no_pipe"; then +if test -n "$GCC"; then + echo $ac_n "checking if the compiler understands -pipe""... $ac_c" 1>&6 +echo "configure:1358: checking if the compiler understands -pipe" >&5 + OLDCC="$CC" + CC="$CC -pipe" + cat > conftest.$ac_ext <<EOF +#line 1362 "configure" +#include "confdefs.h" + +int main() { + +; return 0; } +EOF +if { (eval echo configure:1369: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CC="$OLDCC" + echo "$ac_t""no" 1>&6 +fi +rm -f conftest* +fi +fi + +# Check whether --enable-warnings or --disable-warnings was given. +if test "${enable_warnings+set}" = set; then + enableval="$enable_warnings" + if test -n "$GCC"; then + echo "$ac_t""Adding -Wall to CFLAGS." 1>&6 + CFLAGS="$CFLAGS -Wall" + fi +fi + + +if test -z "$no_vhangup"; then + for ac_func in vhangup +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1397: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1402 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1425: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +fi + +if test -z "$no_setsid"; then + for ac_func in setsid +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1455: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1460 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1483: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +fi + +echo $ac_n "checking where to find mandatory GMP library""... $ac_c" 1>&6 +echo "configure:1510: checking where to find mandatory GMP library" >&5 +# Check whether --with-gmp or --without-gmp was given. +if test "${with_gmp+set}" = set; then + withval="$with_gmp" + case "$withval" in + no) + echo "GMP is mandatory! Aborting!" + exit 1 + ;; + *) + ;; + esac +else + with_gmp=yes + +fi + +# gmp continued +echo argument="$with_gmp" +case "$with_gmp" in +yes) + for ac_hdr in gmp.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1535: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1540 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1545: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + if test "$ac_cv_header_gmp_h" != yes; then + echo "Can't find include file gmp.h! Aborting!" + echo "You must first build and install GMP, please read the file INSTALL" + exit 1 + fi + echo $ac_n "checking for main in -lgmp""... $ac_c" 1>&6 +echo "configure:1577: checking for main in -lgmp" >&5 +ac_lib_var=`echo gmp'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lgmp $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1585 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +EOF +if { (eval echo configure:1592: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo gmp | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lgmp $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + if test "$ac_cv_lib_gmp_main" != yes; then + echo "Can't find library gmp (libgmp.a)! Aborting" + echo "You must first build and install GMP, please read the file INSTALL" + exit 1 + fi + GMPINCS="" + GMPLIBS="-lgmp" + ;; +*) + GMPINCS="-I$with_gmp/include" + GMPLIBS="-L$with_gmp/lib -lgmp" + ;; +esac + +for ac_func in _getpty clock fchmod getdtablesize gethostname getrusage +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1636: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1641 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1664: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_func in gettimeofday initgroups innetgr memcpy openpty popen seteuid +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1691: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1696 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1719: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_func in setlogin setluid setrlimit strchr times ulimit umask vsnprintf +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1746: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1751 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1774: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 +echo "configure:1800: checking return type of signal handlers" >&5 +if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1805 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <signal.h> +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int main() { +int i; +; return 0; } +EOF +if { (eval echo configure:1822: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_signal=void +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_signal=int +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_type_signal" 1>&6 +cat >> confdefs.h <<EOF +#define RETSIGTYPE $ac_cv_type_signal +EOF + + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1841: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1846 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1854: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1871 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1889 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 1910 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1921: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:1945: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1950 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:1978: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1983 "configure" +#include "confdefs.h" +#include <sys/types.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:2012: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2017 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for mode_t""... $ac_c" 1>&6 +echo "configure:2045: checking for mode_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2050 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_mode_t=yes +else + rm -rf conftest* + ac_cv_type_mode_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_mode_t" 1>&6 +if test $ac_cv_type_mode_t = no; then + cat >> confdefs.h <<\EOF +#define mode_t int +EOF + +fi + +echo $ac_n "checking for st_blksize in struct stat""... $ac_c" 1>&6 +echo "configure:2078: checking for st_blksize in struct stat" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2083 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/stat.h> +int main() { +struct stat s; s.st_blksize; +; return 0; } +EOF +if { (eval echo configure:2091: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_st_blksize=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_st_blksize=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_st_blksize" 1>&6 +if test $ac_cv_struct_st_blksize = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ST_BLKSIZE 1 +EOF + +fi + + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2113: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2118 "configure" +#include "confdefs.h" + +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2167: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for inline""... $ac_c" 1>&6 +echo "configure:2188: checking for inline" >&5 +if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat > conftest.$ac_ext <<EOF +#line 2195 "configure" +#include "confdefs.h" + +int main() { +} $ac_kw foo() { +; return 0; } +EOF +if { (eval echo configure:2202: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_inline=$ac_kw; break +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +done + +fi + +echo "$ac_t""$ac_cv_c_inline" 1>&6 +case "$ac_cv_c_inline" in + inline | yes) ;; + no) cat >> confdefs.h <<\EOF +#define inline +EOF + ;; + *) cat >> confdefs.h <<EOF +#define inline $ac_cv_c_inline +EOF + ;; +esac + +echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 +echo "configure:2228: checking whether byte ordering is bigendian" >&5 +if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +cat > conftest.$ac_ext <<EOF +#line 2235 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/param.h> +int main() { + +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif +; return 0; } +EOF +if { (eval echo configure:2246: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + # It does; now see whether it defined to BIG_ENDIAN or not. +cat > conftest.$ac_ext <<EOF +#line 2250 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/param.h> +int main() { + +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif +; return 0; } +EOF +if { (eval echo configure:2261: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_bigendian=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_bigendian=no +fi +rm -f conftest* +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +if test $ac_cv_c_bigendian = unknown; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 2281 "configure" +#include "confdefs.h" +main () { + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +} +EOF +if { (eval echo configure:2294: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_bigendian=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_bigendian=yes +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_bigendian" 1>&6 +if test $ac_cv_c_bigendian = yes; then + cat >> confdefs.h <<\EOF +#define WORDS_BIGENDIAN 1 +EOF + +fi + +echo $ac_n "checking size of long""... $ac_c" 1>&6 +echo "configure:2318: checking size of long" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 2326 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(long)); + exit(0); +} +EOF +if { (eval echo configure:2337: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_long=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_long=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_long" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_LONG $ac_cv_sizeof_long +EOF + + +echo $ac_n "checking size of int""... $ac_c" 1>&6 +echo "configure:2357: checking size of int" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 2365 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(int)); + exit(0); +} +EOF +if { (eval echo configure:2376: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_int=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_int=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_int" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_INT $ac_cv_sizeof_int +EOF + + +echo $ac_n "checking size of short""... $ac_c" 1>&6 +echo "configure:2396: checking size of short" >&5 +if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 2404 "configure" +#include "confdefs.h" +#include <stdio.h> +main() +{ + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(short)); + exit(0); +} +EOF +if { (eval echo configure:2415: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_sizeof_short=`cat conftestval` +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_short=0 +fi +rm -fr conftest* +fi + +fi +echo "$ac_t""$ac_cv_sizeof_short" 1>&6 +cat >> confdefs.h <<EOF +#define SIZEOF_SHORT $ac_cv_sizeof_short +EOF + + + +if test -z "$no_termios"; then + for ac_hdr in termios.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2440: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2445 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2450: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:2479: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2484 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2492: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 2509 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 2527 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 2548 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:2559: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 +echo "configure:2583: checking for sys/wait.h that is POSIX.1 compatible" >&5 +if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2588 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/wait.h> +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif +int main() { +int s; +wait (&s); +s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; +; return 0; } +EOF +if { (eval echo configure:2604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_sys_wait_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_sys_wait_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 +if test $ac_cv_header_sys_wait_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_WAIT_H 1 +EOF + +fi + +for ac_hdr in unistd.h rusage.h sys/time.h lastlog.h utmp.h utmpx.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2628: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2633 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2638: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in sgtty.h sys/select.h sys/ioctl.h sys/filio.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2668: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2673 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2678: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in paths.h usersec.h utime.h netinet/in_systm.h ulimit.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2708: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2713 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2718: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:2745: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2750 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:2759: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:2784: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2789 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:2797: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + ac_header_dirent=$ac_hdr; break +else + echo "$ac_t""no" 1>&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:2822: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2830 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir(); + +int main() { +opendir() +; return 0; } +EOF +if { (eval echo configure:2841: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:2863: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2871 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char opendir(); + +int main() { +opendir() +; return 0; } +EOF +if { (eval echo configure:2882: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6 +echo "configure:2905: checking whether stat file-mode macros are broken" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2910 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/stat.h> + +#if defined(S_ISBLK) && defined(S_IFDIR) +# if S_ISBLK (S_IFDIR) +You lose. +# endif +#endif + +#if defined(S_ISBLK) && defined(S_IFCHR) +# if S_ISBLK (S_IFCHR) +You lose. +# endif +#endif + +#if defined(S_ISLNK) && defined(S_IFREG) +# if S_ISLNK (S_IFREG) +You lose. +# endif +#endif + +#if defined(S_ISSOCK) && defined(S_IFREG) +# if S_ISSOCK (S_IFREG) +You lose. +# endif +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "You lose" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_header_stat_broken=yes +else + rm -rf conftest* + ac_cv_header_stat_broken=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_header_stat_broken" 1>&6 +if test $ac_cv_header_stat_broken = yes; then + cat >> confdefs.h <<\EOF +#define STAT_MACROS_BROKEN 1 +EOF + +fi + +cat > conftest.$ac_ext <<EOF +#line 2961 "configure" +#include "confdefs.h" +#include <utmp.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ut_pid" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_PID_IN_UTMP 1 +EOF + +fi +rm -f conftest* + +cat > conftest.$ac_ext <<EOF +#line 2976 "configure" +#include "confdefs.h" +#include <utmp.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ut_name" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_NAME_IN_UTMP 1 +EOF + +fi +rm -f conftest* + +cat > conftest.$ac_ext <<EOF +#line 2991 "configure" +#include "confdefs.h" +#include <utmp.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ut_id" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_ID_IN_UTMP 1 +EOF + +fi +rm -f conftest* + +cat > conftest.$ac_ext <<EOF +#line 3006 "configure" +#include "confdefs.h" +#include <utmp.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ut_host" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_HOST_IN_UTMP 1 +EOF + +fi +rm -f conftest* + +cat > conftest.$ac_ext <<EOF +#line 3021 "configure" +#include "confdefs.h" +#include <utmp.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ut_addr" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_ADDR_IN_UTMP 1 +EOF + +fi +rm -f conftest* + + +cat > conftest.$ac_ext <<EOF +#line 3037 "configure" +#include "confdefs.h" +#include <utmpx.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ut_session" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_UT_SESSION 1 +EOF + +fi +rm -f conftest* + +cat > conftest.$ac_ext <<EOF +#line 3052 "configure" +#include "confdefs.h" +#include <utmpx.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ut_syslen" >/dev/null 2>&1; then + rm -rf conftest* + cat >> confdefs.h <<\EOF +#define HAVE_UT_SYSLEN 1 +EOF + +fi +rm -f conftest* + + +echo $ac_n "checking for crypt in -lc""... $ac_c" 1>&6 +echo "configure:3068: checking for crypt in -lc" >&5 +ac_lib_var=`echo c'_'crypt | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lc $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3076 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char crypt(); + +int main() { +crypt() +; return 0; } +EOF +if { (eval echo configure:3087: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + true +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6 +echo "configure:3106: checking for crypt in -lcrypt" >&5 +ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lcrypt $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3114 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char crypt(); + +int main() { +crypt() +; return 0; } +EOF +if { (eval echo configure:3125: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/^a-zA-Z0-9_/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lcrypt $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6 +echo "configure:3155: checking for main in -lnsl" >&5 +ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3163 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +EOF +if { (eval echo configure:3170: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lnsl $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$no_libsocket"; then + echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 +echo "configure:3199: checking for socket in -lsocket" >&5 +ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3207 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket(); + +int main() { +socket() +; return 0; } +EOF +if { (eval echo configure:3218: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lsocket $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +fi +if test -z "$no_libsun"; then + echo $ac_n "checking for getpwnam in -lsun""... $ac_c" 1>&6 +echo "configure:3248: checking for getpwnam in -lsun" >&5 +ac_lib_var=`echo sun'_'getpwnam | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsun $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3256 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char getpwnam(); + +int main() { +getpwnam() +; return 0; } +EOF +if { (eval echo configure:3267: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo sun | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lsun $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +fi +echo $ac_n "checking for login in -lutil""... $ac_c" 1>&6 +echo "configure:3296: checking for login in -lutil" >&5 +ac_lib_var=`echo util'_'login | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lutil $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3304 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char login(); + +int main() { +login() +; return 0; } +EOF +if { (eval echo configure:3315: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_LIBUTIL_LOGIN 1 +EOF + + LIBS="$LIBS -lutil" +else + echo "$ac_t""no" 1>&6 +fi + + +echo $ac_n "checking for main in -ldes""... $ac_c" 1>&6 +echo "configure:3341: checking for main in -ldes" >&5 +ac_lib_var=`echo des'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldes $LIBS" +cat > conftest.$ac_ext <<EOF +#line 3349 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +EOF +if { (eval echo configure:3356: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo des | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-ldes $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + +for ac_func in strerror memmove remove random putenv socketpair +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3387: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3392 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3415: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +LIBOBJS="$LIBOBJS ${ac_func}.${ac_objext}" +fi +done + + + +echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 +echo "configure:3443: checking whether ln -s works" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata +if ln -s X conftestdata 2>/dev/null +then + rm -f conftestdata + ac_cv_prog_LN_S="ln -s" +else + ac_cv_prog_LN_S=ln +fi +fi +LN_S="$ac_cv_prog_LN_S" +if test "$ac_cv_prog_LN_S" = "ln -s"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:3475: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -z "$no_ranlib"; then + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3531: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +else + RANLIB=":" +fi +for ac_prog in makedepend makedep +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3566: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_MAKEDEP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$MAKEDEP"; then + ac_cv_prog_MAKEDEP="$MAKEDEP" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_MAKEDEP="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +MAKEDEP="$ac_cv_prog_MAKEDEP" +if test -n "$MAKEDEP"; then + echo "$ac_t""$MAKEDEP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$MAKEDEP" && break +done +test -n "$MAKEDEP" || MAKEDEP="makedepend" + +for ac_prog in wish8.0 wish wishx wish4.1 true +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3601: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_WISH'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$WISH" in + /*) + ac_cv_path_WISH="$WISH" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_WISH="$WISH" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_WISH="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +WISH="$ac_cv_path_WISH" +if test -n "$WISH"; then + echo "$ac_t""$WISH" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$WISH" && break +done + +if test `basename $WISH` = "true"; then + echo "configure: warning: the wish program was not found - ssh-askpass will not work." 1>&2 + WISH="/usr/local/bin/wish" +fi +# Extract the first word of "xauth", so it can be a program name with args. +set dummy xauth; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3643: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_XAUTH_PATH'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$XAUTH_PATH" in + /*) + ac_cv_path_XAUTH_PATH="$XAUTH_PATH" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_XAUTH_PATH="$XAUTH_PATH" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH:/usr/X11R6/bin" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_XAUTH_PATH="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +XAUTH_PATH="$ac_cv_path_XAUTH_PATH" +if test -n "$XAUTH_PATH"; then + echo "$ac_t""$XAUTH_PATH" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -n "$XAUTH_PATH"; then + cat >> confdefs.h <<EOF +#define XAUTH_PATH "$XAUTH_PATH" +EOF + +fi + +echo $ac_n "checking for pseudo ttys""... $ac_c" 1>&6 +echo "configure:3683: checking for pseudo ttys" >&5 +if test -c /dev/ptmx && test -c /dev/pts/0 +then + cat >> confdefs.h <<\EOF +#define HAVE_DEV_PTMX 1 +EOF + + echo "$ac_t""streams ptys" 1>&6 +else +if test -c /dev/pts && test -c /dev/ptc +then + cat >> confdefs.h <<\EOF +#define HAVE_DEV_PTS_AND_PTC 1 +EOF + + echo "$ac_t""/dev/pts and /dev/ptc" 1>&6 +else + echo "$ac_t""bsd-style ptys" 1>&6 +fi +fi + +echo $ac_n "checking for /etc/default/login""... $ac_c" 1>&6 +echo "configure:3705: checking for /etc/default/login" >&5 +if test -f /etc/default/login; then + cat >> confdefs.h <<\EOF +#define HAVE_ETC_DEFAULT_LOGIN 1 +EOF + + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$no_shadows_password_checking"; then + echo $ac_n "checking for shadow passwords""... $ac_c" 1>&6 +echo "configure:3718: checking for shadow passwords" >&5 + if test -f /etc/shadow; then + cat >> confdefs.h <<\EOF +#define HAVE_ETC_SHADOW 1 +EOF + + echo "$ac_t""/etc/shadow" 1>&6 + elif test -n "$os_aix"; then + cat >> confdefs.h <<\EOF +#define HAVE_ETC_SECURITY_PASSWD 1 +EOF + + echo "$ac_t""/etc/security/passwd" 1>&6 + elif test -n "$os_sunos"; then + cat >> confdefs.h <<\EOF +#define HAVE_ETC_SECURITY_PASSWD_ADJUNCT 1 +EOF + + echo "$ac_t""/etc/security/passwd.adjunct" 1>&6 + else + echo "$ac_t""no" 1>&6 + fi +fi + +echo $ac_n "checking location of mail spool files""... $ac_c" 1>&6 +echo "configure:3743: checking location of mail spool files" >&5 +for dir in /var/spool/mail /var/mail /usr/spool/mail /usr/mail NEWMAIL +do + if test "$dir" = "NEWMAIL"; then + cat >> confdefs.h <<\EOF +#define HAVE_TILDE_NEWMAIL 1 +EOF + + echo "$ac_t""\$HOME/newmail" 1>&6 + echo "configure: warning: mail spool directory was not found: assuming you use \$HOME/newmail" 1>&2 + elif test -d $dir; then + cat >> confdefs.h <<EOF +#define MAIL_SPOOL_DIRECTORY "$dir" +EOF + + echo "$ac_t""$dir" 1>&6 + break + fi +done + +echo $ac_n "checking location of utmp""... $ac_c" 1>&6 +echo "configure:3764: checking location of utmp" >&5 +if test -f /var/run/utmp; then + cat >> confdefs.h <<\EOF +#define SSH_UTMP "/var/run/utmp" +EOF + + echo "$ac_t""/var/run/utmp" 1>&6 +elif test -f /var/log/utmp; then + cat >> confdefs.h <<\EOF +#define SSH_UTMP "/var/log/utmp" +EOF + + echo "$ac_t""/var/log/utmp" 1>&6 +elif test -f /var/adm/utmp; then + cat >> confdefs.h <<\EOF +#define SSH_UTMP "/var/adm/utmp" +EOF + + echo "$ac_t""/var/adm/utmp" 1>&6 +elif test -f /usr/adm/utmp; then + cat >> confdefs.h <<\EOF +#define SSH_UTMP "/usr/adm/utmp" +EOF + + echo "$ac_t""/usr/adm/utmp" 1>&6 +elif test -f /etc/utmp; then + cat >> confdefs.h <<\EOF +#define SSH_UTMP "/etc/utmp" +EOF + + echo "$ac_t""/etc/utmp" 1>&6 +else + echo "$ac_t""not found" 1>&6 +fi + +echo $ac_n "checking location of wtmp""... $ac_c" 1>&6 +echo "configure:3800: checking location of wtmp" >&5 +if test -f /var/log/wtmp; then + cat >> confdefs.h <<\EOF +#define SSH_WTMP "/var/log/wtmp" +EOF + + echo "$ac_t""/var/log/wtmp" 1>&6 +elif test -f /var/adm/wtmp; then + cat >> confdefs.h <<\EOF +#define SSH_WTMP "/var/adm/wtmp" +EOF + + echo "$ac_t""/var/adm/wtmp" 1>&6 +elif test -f /usr/adm/wtmp; then + cat >> confdefs.h <<\EOF +#define SSH_WTMP "/usr/adm/wtmp" +EOF + + echo "$ac_t""/usr/adm/wtmp" 1>&6 +elif test -f /etc/wtmp; then + cat >> confdefs.h <<\EOF +#define SSH_WTMP "/etc/wtmp" +EOF + + echo "$ac_t""/etc/wtmp" 1>&6 +else + cat >> confdefs.h <<\EOF +#define SSH_WTMP "/var/adm/wtmp" +EOF + + echo "$ac_t""not found" 1>&6 +fi + +echo $ac_n "checking location of lastlog""... $ac_c" 1>&6 +echo "configure:3834: checking location of lastlog" >&5 +if test -f /var/log/lastlog || test -d /var/log/lastlog; then + cat >> confdefs.h <<\EOF +#define SSH_LASTLOG "/var/log/lastlog" +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_LASTLOG 1 +EOF + + LASTLOG=/var/log/lastlog + echo "$ac_t""/var/log/lastlog" 1>&6 +elif test -f /var/adm/lastlog || test -d /var/adm/lastlog; then + cat >> confdefs.h <<\EOF +#define SSH_LASTLOG "/var/adm/lastlog" +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_LASTLOG 1 +EOF + + LASTLOG=/var/adm/lastlog + echo "$ac_t""/var/adm/lastlog" 1>&6 +elif test -f /usr/adm/lastlog || test -d /usr/adm/lastlog; then + cat >> confdefs.h <<\EOF +#define SSH_LASTLOG "/usr/adm/lastlog" +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_LASTLOG 1 +EOF + + LASTLOG=/usr/adm/lastlog + echo "$ac_t""/usr/adm/lastlog" 1>&6 +elif test -f /etc/lastlog || test -d /etc/lastlog; then + cat >> confdefs.h <<\EOF +#define SSH_LASTLOG "/etc/lastlog" +EOF + + cat >> confdefs.h <<\EOF +#define HAVE_LASTLOG 1 +EOF + + LASTLOG=/etc/lastlog + echo "$ac_t""/etc/lastlog" 1>&6 +else + echo "$ac_t""not found" 1>&6 + cat >> confdefs.h <<\EOF +#define SSH_LASTLOG "/var/log/lastlog" +EOF + + LASTLOG=/var/log/lastlog +fi + +echo $ac_n "checking whether $LASTLOG is a directory""... $ac_c" 1>&6 +echo "configure:3889: checking whether $LASTLOG is a directory" >&5 +if test -d $LASTLOG +then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define LASTLOG_IS_DIR 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking whether to include the IDEA encryption algorithm""... $ac_c" 1>&6 +echo "configure:3902: checking whether to include the IDEA encryption algorithm" >&5 +# Check whether --with-idea or --without-idea was given. +if test "${with_idea+set}" = set; then + withval="$with_idea" + case "$withval" in + yes) + echo "$ac_t""yes" 1>&6 + CONFOBJS="$CONFOBJS idea.o" + cat >> confdefs.h <<\EOF +#define WITH_IDEA 1 +EOF + + ;; + *) + echo "$ac_t""no" 1>&6 + ;; + esac +else + echo "$ac_t""no" 1>&6 + +fi + + +echo $ac_n "checking whether to include the RC4 encryption algorithm""... $ac_c" 1>&6 +echo "configure:3926: checking whether to include the RC4 encryption algorithm" >&5 +# Check whether --with-rc4 or --without-rc4 was given. +if test "${with_rc4+set}" = set; then + withval="$with_rc4" + case "$withval" in + yes) + echo "$ac_t""yes" 1>&6 + CONFOBJS="$CONFOBJS rc4.o" + cat >> confdefs.h <<\EOF +#define WITH_RC4 1 +EOF + + ;; + *) + echo "$ac_t""no" 1>&6 + ;; + esac +else + echo "$ac_t""no" 1>&6 + +fi + + +echo $ac_n "checking whether to include the Blowfish encryption algorithm""... $ac_c" 1>&6 +echo "configure:3950: checking whether to include the Blowfish encryption algorithm" >&5 +# Check whether --with-blowfish or --without-blowfish was given. +if test "${with_blowfish+set}" = set; then + withval="$with_blowfish" + case "$withval" in + no) + ;; + *) + with_blowfish=yes + ;; + esac +else + with_blowfish=yes + +fi + + +case "$with_blowfish" in +yes) + cat >> confdefs.h <<\EOF +#define WITH_BLOWFISH 1 +EOF + + CONFOBJS="$CONFOBJS bf_skey.o bf_enc.o" + echo "$ac_t""yes" 1>&6 + ;; +no) + echo "$ac_t""no" 1>&6 + ;; +esac + +echo $ac_n "checking whether to use rsaref""... $ac_c" 1>&6 +echo "configure:3982: checking whether to use rsaref" >&5 +# Check whether --with-rsaref or --without-rsaref was given. +if test "${with_rsaref+set}" = set; then + withval="$with_rsaref" + case "$withval" in + no) + echo "$ac_t""no" 1>&6 + ;; + *) + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define RSAREF 1 +EOF + + RSAREFDEP="rsaref2/source/librsaref.a" + LIBS="-lrsaref $LIBS" + LDFLAGS="-Lrsaref2/source $LDFLAGS" + ;; + esac +else + echo "$ac_t""no" 1>&6 + +fi + + +echo $ac_n "checking whether to use ssl""... $ac_c" 1>&6 +echo "configure:4008: checking whether to use ssl" >&5 +# Check whether --with-ssl or --without-ssl was given. +if test "${with_ssl+set}" = set; then + withval="$with_ssl" + case "$withval" in + no) + echo "$ac_t""no" 1>&6 + ;; + *) + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define DO_SSL 1 +EOF + + LIBS="-lcrypto $LIBS" + ;; + esac +else + echo "$ac_t""no" 1>&6 + +fi + + +echo $ac_n "checking whether to use rsh""... $ac_c" 1>&6 +echo "configure:4032: checking whether to use rsh" >&5 +# Check whether --with-rsh or --without-rsh was given. +if test "${with_rsh+set}" = set; then + withval="$with_rsh" + case "$withval" in + no) + echo "$ac_t""no" 1>&6 + ;; + yes) + echo "$ac_t""yes" 1>&6 + for ac_prog in remsh rsh +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4047: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_RSH_PATH'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$RSH_PATH" in + /*) + ac_cv_path_RSH_PATH="$RSH_PATH" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_RSH_PATH="$RSH_PATH" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_RSH_PATH="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +RSH_PATH="$ac_cv_path_RSH_PATH" +if test -n "$RSH_PATH"; then + echo "$ac_t""$RSH_PATH" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$RSH_PATH" && break +done + + cat >> confdefs.h <<EOF +#define RSH_PATH "$RSH_PATH" +EOF + + ;; + *) + echo "$ac_t""$withval" 1>&6 + cat >> confdefs.h <<EOF +#define RSH_PATH "$withval" +EOF + + ;; + esac +else + echo "$ac_t""yes" 1>&6 + for ac_prog in remsh rsh +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:4102: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_RSH_PATH'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$RSH_PATH" in + /*) + ac_cv_path_RSH_PATH="$RSH_PATH" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_RSH_PATH="$RSH_PATH" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_RSH_PATH="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +RSH_PATH="$ac_cv_path_RSH_PATH" +if test -n "$RSH_PATH"; then + echo "$ac_t""$RSH_PATH" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$RSH_PATH" && break +done + + cat >> confdefs.h <<EOF +#define RSH_PATH "$RSH_PATH" +EOF + + +fi + + +# Code to permit setting default path for users (alden@math.ohio-state.edu) +echo $ac_n "checking default path""... $ac_c" 1>&6 +echo "configure:4147: checking default path" >&5 +# Check whether --with-path or --without-path was given. +if test "${with_path+set}" = set; then + withval="$with_path" + case "$withval" in + no) + echo "$ac_t""use system default" 1>&6 + ;; + *) + echo "$ac_t""$withval" 1>&6 + cat >> confdefs.h <<EOF +#define DEFAULT_PATH "$withval" +EOF + + ;; + esac +else + echo "$ac_t""use system default" 1>&6 + +fi + + +echo $ac_n "checking etcdir""... $ac_c" 1>&6 +echo "configure:4170: checking etcdir" >&5 +# Check whether --with-etcdir or --without-etcdir was given. +if test "${with_etcdir+set}" = set; then + withval="$with_etcdir" + case "$withval" in + no) + { echo "configure: error: Need ETCDIR." 1>&2; exit 1; } + ;; + yes) + ETCDIR="/etc" + echo "$ac_t""/etc" 1>&6 + ;; + *) + ETCDIR="$withval" + echo "$ac_t""$withval" 1>&6 + ;; + esac +else + ETCDIR="/etc" + echo "$ac_t""/etc" 1>&6 + +fi + + +echo $ac_n "checking whether to support SecurID""... $ac_c" 1>&6 +echo "configure:4195: checking whether to support SecurID" >&5 +# Check whether --with-securid or --without-securid was given. +if test "${with_securid+set}" = set; then + withval="$with_securid" + case "$withval" in + no) + echo "$ac_t""no" 1>&6 + ;; + yes) + echo "$ac_t""yes" 1>&6 + if test '!' -f /usr/ace/sdiclient.a; then + { echo "configure: error: SecurID sdiclient.a not found in /usr/ace: you must supply the path." 1>&2; exit 1; } + fi + echo "$ac_t""yes" 1>&6 + echo "$ac_t""Assuming SecurID headers and libraries are in /usr/ace." 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_SECURID 1 +EOF + + CFLAGS="$CFLAGS -I/usr/ace" + LIBS="/usr/ace/sdiclient.a $LIBS" + ;; + *) + echo "$ac_t""yes" 1>&6 + if test '!' -f $withval/sdiclient.a; then + { echo "configure: error: SecurID sdiclient.a not found in $withval: please supply the correct path." 1>&2; exit 1; } + fi + echo "$ac_t""Assuming SecurID headers and libraries are in $withval." 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_SECURID 1 +EOF + + CFLAGS="$CFLAGS -I$withval" + LIBS="$withval/sdiclient.a $LIBS" + ;; + esac +else + echo "$ac_t""no" 1>&6 + +fi + + +echo $ac_n "checking whether to include compression support""... $ac_c" 1>&6 +echo "configure:4238: checking whether to include compression support" >&5 +# Check whether --with-zlib or --without-zlib was given. +if test "${with_zlib+set}" = set; then + withval="$with_zlib" + case "$withval" in + no) + ;; + *) + with_zlib=yes + ;; + esac +else + with_zlib=yes + +fi + + +case "$with_zlib" in +yes) + echo "$ac_t""yes" 1>&6 + for ac_hdr in zlib.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:4262: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 4267 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:4272: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + if test "$ac_cv_header_zlib_h" != yes; then + echo "Can't find zlib.h, disable with --without-zlib" + exit 1 + fi + echo $ac_n "checking for main in -lz""... $ac_c" 1>&6 +echo "configure:4303: checking for main in -lz" >&5 +ac_lib_var=`echo z'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lz $LIBS" +cat > conftest.$ac_ext <<EOF +#line 4311 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +EOF +if { (eval echo configure:4318: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo z | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lz $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + if test "$ac_cv_lib_z_main" != yes; then + echo "Can't find library z (libz.a), disable with --without-zlib" + exit 1 + fi + CONFOBJS="$CONFOBJS compress.o" + cat >> confdefs.h <<\EOF +#define WITH_ZLIB 1 +EOF + + ;; +no) + echo "$ac_t""no" 1>&6 + ;; +esac + +echo $ac_n "checking whether to use Kerberos v4""... $ac_c" 1>&6 +echo "configure:4361: checking whether to use Kerberos v4" >&5 +# Check whether --with-krb4 or --without-krb4 was given. +if test "${with_krb4+set}" = set; then + withval="$with_krb4" + case "$withval" in + yes) + ;; + no) + ;; + *) + ;; + esac +else + with_krb4=default + +fi + +# krb4 continued +case "$with_krb4" in +no) + echo "$ac_t""no" 1>&6 + ;; +yes) + echo "$ac_t""yes" 1>&6 + for ac_hdr in krb.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:4389: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 4394 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:4399: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + if test "$ac_cv_header_krb_h" != yes; then + echo "Can't find include file krb.h! Aborting!" + exit 1 + fi + echo $ac_n "checking for main in -lkrb""... $ac_c" 1>&6 +echo "configure:4430: checking for main in -lkrb" >&5 +ac_lib_var=`echo krb'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lkrb $LIBS" +cat > conftest.$ac_ext <<EOF +#line 4438 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +EOF +if { (eval echo configure:4445: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo krb | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lkrb $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + if test "$ac_cv_lib_krb_main" != yes; then + echo "Can't find library krb (libkrb.a)! Aborting" + exit 1 + fi + cat >> confdefs.h <<\EOF +#define KRB4 1 +EOF + + KRB4_AUTH="auth-krb4.o" + KRB4_ROOT="" + KRB4_INCS="" + KRB4_LIBS="-lkrb -ldes" + echo $ac_n "checking for dn_expand in -lresolv""... $ac_c" 1>&6 +echo "configure:4485: checking for dn_expand in -lresolv" >&5 +ac_lib_var=`echo resolv'_'dn_expand | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lresolv $LIBS" +cat > conftest.$ac_ext <<EOF +#line 4493 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dn_expand(); + +int main() { +dn_expand() +; return 0; } +EOF +if { (eval echo configure:4504: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + KRB4_LIBS="$KRB4_LIBS -lresolv" +else + echo "$ac_t""no" 1>&6 +fi + + ;; +default) + for ac_hdr in krb.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:4530: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 4535 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:4540: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + echo $ac_n "checking for main in -lkrb""... $ac_c" 1>&6 +echo "configure:4567: checking for main in -lkrb" >&5 +ac_lib_var=`echo krb'_'main | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lkrb $LIBS" +cat > conftest.$ac_ext <<EOF +#line 4575 "configure" +#include "confdefs.h" + +int main() { +main() +; return 0; } +EOF +if { (eval echo configure:4582: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo krb | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lkrb $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + if test "$ac_cv_header_krb_h" = yes -a "$ac_cv_lib_krb_main" = yes; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define KRB4 1 +EOF + + KRB4_AUTH="auth-krb4.o" + KRB4_ROOT="" + KRB4_INCS="" + KRB4_LIBS="-lkrb -ldes" + echo $ac_n "checking for dn_expand in -lresolv""... $ac_c" 1>&6 +echo "configure:4620: checking for dn_expand in -lresolv" >&5 +ac_lib_var=`echo resolv'_'dn_expand | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lresolv $LIBS" +cat > conftest.$ac_ext <<EOF +#line 4628 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dn_expand(); + +int main() { +dn_expand() +; return 0; } +EOF +if { (eval echo configure:4639: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + KRB4_LIBS="$KRB4_LIBS -lresolv" +else + echo "$ac_t""no" 1>&6 +fi + + else + echo "$ac_t""no" 1>&6 + fi + ;; +*) + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define KRB4 1 +EOF + + KRB4_AUTH="auth-krb4.o" + KRB4_ROOT="$with_krb4" + KRB4_INCS="-I\$(KRB4_ROOT)/include" + KRB4_LIBS="-L\$(KRB4_ROOT)/lib -lkrb -ldes" + echo $ac_n "checking for dn_expand in -lresolv""... $ac_c" 1>&6 +echo "configure:4674: checking for dn_expand in -lresolv" >&5 +ac_lib_var=`echo resolv'_'dn_expand | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lresolv $LIBS" +cat > conftest.$ac_ext <<EOF +#line 4682 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dn_expand(); + +int main() { +dn_expand() +; return 0; } +EOF +if { (eval echo configure:4693: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + KRB4_LIBS="$KRB4_LIBS -lresolv" +else + echo "$ac_t""no" 1>&6 +fi + + ;; +esac + +echo $ac_n "checking whether to use AFS""... $ac_c" 1>&6 +echo "configure:4717: checking whether to use AFS" >&5 +# Check whether --with-afs or --without-afs was given. +if test "${with_afs+set}" = set; then + withval="$with_afs" + if test "$with_afs" = no; then + echo "$ac_t""no" 1>&6 + else + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define AFS 1 +EOF + + cat >> confdefs.h <<\EOF +#define KERBEROS_TGT_PASSING 1 +EOF + + RADIX="radix.o" + if test "$with_krb4" = no; then + echo "$ac_t""no" 1>&6 + echo "configure: warning: "AFS requires Kerberos v4 support."" 1>&2 + else + KRB4_LIBS="${KRB4_LIBS} -lkafs" + if test -n "$os_aix"; then + KRB4_LIBS="${KRB4_LIBS} -lld" + fi + fi +fi + +fi + + +echo $ac_n "checking whether to use libwrap""... $ac_c" 1>&6 +echo "configure:4749: checking whether to use libwrap" >&5 +# Check whether --with-libwrap or --without-libwrap was given. +if test "${with_libwrap+set}" = set; then + withval="$with_libwrap" + case "$withval" in + no) + echo "$ac_t""no" 1>&6 + ;; + yes) + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define LIBWRAP 1 +EOF + + LIBS="-lwrap $LIBS" + cat > conftest.$ac_ext <<EOF +#line 4765 "configure" +#include "confdefs.h" + int allow_severity; int deny_severity; +int main() { + hosts_access(); +; return 0; } +EOF +if { (eval echo configure:4772: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: Could not find the libwrap.a library. You must first install tcp_wrappers." 1>&2; exit 1; } +fi +rm -f conftest* + ;; + *) + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define LIBWRAP 1 +EOF + + LIBS="$withval $LIBS" + cat > conftest.$ac_ext <<EOF +#line 4790 "configure" +#include "confdefs.h" + int allow_severity; int deny_severity; +int main() { + hosts_access(); +; return 0; } +EOF +if { (eval echo configure:4797: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: Could not find the $withval library. You must first install tcp_wrappers." 1>&2; exit 1; } +fi +rm -f conftest* + ;; + esac +else + echo "$ac_t""no" 1>&6 + +fi + + +echo $ac_n "checking whether to support SOCKS""... $ac_c" 1>&6 +echo "configure:4815: checking whether to support SOCKS" >&5 +# Check whether --with-socks or --without-socks was given. +if test "${with_socks+set}" = set; then + withval="$with_socks" + case "$withval" in + no) + echo "$ac_t""no" 1>&6 + ;; + *) + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define SOCKS 1 +EOF + + cat >> confdefs.h <<\EOF +#define connect Rconnect +EOF + + cat >> confdefs.h <<\EOF +#define getsockname Rgetsockname +EOF + + cat >> confdefs.h <<\EOF +#define bind Rbind +EOF + + cat >> confdefs.h <<\EOF +#define accept Raccept +EOF + + cat >> confdefs.h <<\EOF +#define listen Rlisten +EOF + + cat >> confdefs.h <<\EOF +#define select Rselect +EOF + + if test "x$withval" = "xyes"; then + withval="-lsocks" + fi + LIBS="$withval $LIBS" + cat > conftest.$ac_ext <<EOF +#line 4858 "configure" +#include "confdefs.h" + +int main() { + Rconnect(); +; return 0; } +EOF +if { (eval echo configure:4865: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + { echo "configure: error: Could not find the $withval library. You must first install socks." 1>&2; exit 1; } +fi +rm -f conftest* + ;; + esac +else + echo "$ac_t""no" 1>&6 + +fi + + +PIDDIR="/var/run" +echo $ac_n "checking where to put sshd.pid""... $ac_c" 1>&6 +echo "configure:4884: checking where to put sshd.pid" >&5 +if test '!' -d $PIDDIR; then + PIDDIR="$ETCDIR" +fi +echo "$ac_t""$PIDDIR" 1>&6 + +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + + + + + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile sshd.8 ssh.1 config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@GMPINCS@%$GMPINCS%g +s%@GMPLIBS@%$GMPLIBS%g +s%@LIBOBJS@%$LIBOBJS%g +s%@LN_S@%$LN_S%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@RANLIB@%$RANLIB%g +s%@MAKEDEP@%$MAKEDEP%g +s%@WISH@%$WISH%g +s%@XAUTH_PATH@%$XAUTH_PATH%g +s%@RSH_PATH@%$RSH_PATH%g +s%@KRB4_AUTH@%$KRB4_AUTH%g +s%@KRB4_ROOT@%$KRB4_ROOT%g +s%@KRB4_INCS@%$KRB4_INCS%g +s%@KRB4_LIBS@%$KRB4_LIBS%g +s%@RADIX@%$RADIX%g +s%@ETCDIR@%$ETCDIR%g +s%@PIDDIR@%$PIDDIR%g +s%@RSAREFDEP@%$RSAREFDEP%g +s%@CONFOBJS@%$CONFOBJS%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile sshd.8 ssh.1"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <<EOF + CONFIG_HEADERS="config.h" +EOF +cat >> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <<EOF + +EOF +cat >> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/usr.bin/ssh/configure.in b/usr.bin/ssh/configure.in new file mode 100644 index 00000000000..84b06b0990e --- /dev/null +++ b/usr.bin/ssh/configure.in @@ -0,0 +1,815 @@ +# +# configure.in +# +# Author: Tatu Ylonen <ylo@cs.hut.fi> +# +# Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +# All rights reserved +# +# Created: Wed Mar 22 18:02:48 1995 ylo +# +# $Id: configure.in,v 1.1 1999/09/26 20:53:35 deraadt Exp $ +# + +AC_INIT(sshd.c) +AC_CONFIG_HEADER(config.h) +AC_PREREQ(2.4) + +AC_CANONICAL_HOST + +AC_PROG_CC +AC_PROG_CPP + +case "$host" in + *-*-sunos4.1.1*) + os_sunos=yes + # Tim Adam <tma@osa.com.au> says speed_t is defined in stdtypes.h + AC_DEFINE(SPEED_T_IN_STDTYPES_H) + ;; + *-*-sunos*) + os_sunos=yes + ;; + *-sgi-irix5*) + # Irix stuff from snabb@niksula.hut.fi and tsurmacz@asic.ict.pwr.wroc.pl. + no_libsocket=yes + no_libsun=yes + ;; + *-sgi-irix6*) + # from d-champion@uchicago.edu + no_libsocket=yes + no_libsun=yes + if test "`uname -s`" = "IRIX64"; then + CFLAGS="-32 $CFLAGS" + LDFLAGS="-32 $LDFLAGS" + fi + ;; + *-ibm-aix3.2|*-ibm-aix3.2.0|*-ibm-aix3.2.1|*-ibm-aix3.2.2|*-ibm-aix3.2.3|*-ibm-aix3.2.4) + os_aix=yes + AC_CHECK_LIB(s, getuserattr) + ;; + *-ibm-aix*) + os_aix=yes + AC_CHECK_LIB(s, getuserattr) + ;; + mips-dec-mach3*) + # Mach3 stuff from kivinen@hut.fi + no_vhangup=yes + ;; + *-dec-ultrix*) + # Ultrix stuff from dmckilli@qc.bell.ca, jbotz@orixa.mtholyoke.edu. + AC_DEFINE(O_NONBLOCK_BROKEN) + no_vhangup=yes + AC_TRY_COMPILE([#include <syslog.h>], + [int foo = LOG_DAEMON; ], + , + AC_DEFINE(NEED_SYS_SYSLOG_H)) + ;; + *-*-hpux*) + # HPUX flags from jgotts@engin.umich.edu + if test -z "$GCC"; then + CFLAGS="$CFLAGS -Aa -D_HPUX_SOURCE" + fi + AC_DEFINE(HPSUX_NONSTANDARD_X11_KLUDGE) + ;; + alpha-dec-osf*) + AC_DEFINE(TTY_GROUP, "terminal") + AC_CHECK_LIB(security, set_auth_parameters) + AC_MSG_CHECKING(for OSF/1 C2 security package) + osfc2sec=`/usr/sbin/setld -i | grep '^OSFC2SEC'` + if test -n "$osfc2sec"; then + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_OSF1_C2_SECURITY) + AC_CHECK_LIB(security, set_auth_parameters, + LIBS="$LIBS -lsecurity", + AC_MSG_ERROR("Could not find libsecurity even though C2 security installed.")) + CONFOBJS="$CONFOBJS osfc2.o" + else + AC_MSG_RESULT(no) + fi + ;; + *-*-nextstep*) + # Nextstep support from a person who wants to remain anonymous + no_termios=yes + AC_DEFINE(SPEED_T_IN_STDTYPES_H) + ;; + *-*-linux*) + # Linux shadow password support (Andrew.Macpherson.1248566@bnr.co.uk) + if test -f /etc/shadow && test -f /etc/login.defs; then + AC_MSG_RESULT(Using linux John Haugh shadow passwords and pw_encrypt for password encryption) + AC_DEFINE(crypt,pw_encrypt) + LIBS="$LIBS -lshadow" + fi + ;; + i*86-*-bsdi*) + no_pipe=yes + ;; + i*86-unknown-bsd*) + # Assume 386BSD. pgut01@cs.auckland.ac.nz reported this makes it compile. + AC_DEFINE(__FreeBSD__) + ;; + m68k-sony-newsos*) + # From snabb@niksula.hut.fi + no_vhangup=yes + ;; + m88k-dg-dgux*) + AC_DEFINE(BROKEN_INET_ADDR) + ;; + *-cray-unicos*) + CFLAGS="$CFLAGS -DCRAY_STACKSEG_END=_getb67" + ;; + *-*-sysv4*) + AC_CHECK_LIB(gen, openlog) + ;; + *-*-machten*) + AC_DEFINE(USE_STRLEN_FOR_AF_UNIX) + ;; + i*86-unknown-sco*) + # From moi@dio.com + AC_DEFINE(HAVE_SCO_ETC_SHADOW) + AC_DEFINE(SCO) + no_ranlib=yes + LIBS="-L/usr/lib/libp -lprot -lx $LIBS" + ;; + *-convex-bsd*) + # From mark.martinec@nsc.ijs.si + # On Convex, getpwnam sets pw_passwd if running as root + no_shadows_password_checking=yes + ;; + *-*-freebsd*) + # From Ollivier Robert: FreeBSD and NetBSD use master.passwd, but set + # pw_passwd automatically when running as root. + no_shadow_password_checking=yes + ;; + *-*-netbsd*) + # From Ollivier Robert: FreeBSD and NetBSD use master.passwd, but set + # pw_passwd automatically when running as root. + no_shadow_password_checking=yes + ;; + *-*-openbsd*) + no_shadow_password_checking=yes + ;; + *) + ;; +esac + +# Socket pairs appear to be broken on several systems. I don't know exactly +# where, so I'll use pipes everywhere for now. +AC_DEFINE(USE_PIPES) + +AC_MSG_CHECKING([that the compiler works]) +AC_TRY_RUN([ main(int ac, char **av) { return 0; } ], + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no) + AC_MSG_ERROR(Could not compile and run even a trivial ANSI C program - check CC.), + AC_MSG_ERROR(Could not compile and run even a trivial ANSI C program - check CC.)) + +if test -z "$no_pipe"; then +if test -n "$GCC"; then + AC_MSG_CHECKING([if the compiler understands -pipe]) + OLDCC="$CC" + CC="$CC -pipe" + AC_TRY_COMPILE(,, + AC_MSG_RESULT(yes), + CC="$OLDCC" + AC_MSG_RESULT(no)) +fi +fi + +AC_ARG_ENABLE(warnings, +[ --enable-warnings Enable -Wall if using gcc.], +[ if test -n "$GCC"; then + AC_MSG_RESULT(Adding -Wall to CFLAGS.) + CFLAGS="$CFLAGS -Wall" + fi]) + +if test -z "$no_vhangup"; then + AC_CHECK_FUNCS(vhangup) +fi + +if test -z "$no_setsid"; then + AC_CHECK_FUNCS(setsid) +fi + +AC_MSG_CHECKING(where to find mandatory GMP library) +AC_ARG_WITH(gmp, +[ --with-gmp[=PATH] Where to find GMP library.], +[ case "$withval" in + no) + echo "GMP is mandatory! Aborting!" + exit 1 + ;; + *) + ;; + esac ], +[ with_gmp=yes ] +) +# gmp continued +echo argument="$with_gmp" +case "$with_gmp" in +yes) + AC_CHECK_HEADERS(gmp.h) + if test "$ac_cv_header_gmp_h" != yes; then + echo "Can't find include file gmp.h! Aborting!" + echo "You must first build and install GMP, please read the file INSTALL" + exit 1 + fi + AC_CHECK_LIB(gmp, main) + if test "$ac_cv_lib_gmp_main" != yes; then + echo "Can't find library gmp (libgmp.a)! Aborting" + echo "You must first build and install GMP, please read the file INSTALL" + exit 1 + fi + GMPINCS="" + GMPLIBS="-lgmp" + ;; +*) + GMPINCS="-I$with_gmp/include" + GMPLIBS="-L$with_gmp/lib -lgmp" + ;; +esac +AC_SUBST(GMPINCS) dnl +AC_SUBST(GMPLIBS) dnl + +AC_CHECK_FUNCS(_getpty clock fchmod getdtablesize gethostname getrusage) +AC_CHECK_FUNCS(gettimeofday initgroups innetgr memcpy openpty popen seteuid) +AC_CHECK_FUNCS(setlogin setluid setrlimit strchr times ulimit umask vsnprintf) + +AC_TYPE_SIGNAL +AC_TYPE_SIZE_T +AC_TYPE_UID_T +AC_TYPE_OFF_T +AC_TYPE_MODE_T +AC_STRUCT_ST_BLKSIZE + +AC_C_CONST +AC_C_INLINE +AC_C_BIGENDIAN +AC_CHECK_SIZEOF(long) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(short) + +if test -z "$no_termios"; then + AC_CHECK_HEADERS(termios.h) +fi + +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(unistd.h rusage.h sys/time.h lastlog.h utmp.h utmpx.h) +AC_CHECK_HEADERS(sgtty.h sys/select.h sys/ioctl.h sys/filio.h) +AC_CHECK_HEADERS(paths.h usersec.h utime.h netinet/in_systm.h ulimit.h) +AC_HEADER_TIME +AC_HEADER_DIRENT +AC_HEADER_STAT +AC_EGREP_HEADER(ut_pid, utmp.h, AC_DEFINE(HAVE_PID_IN_UTMP)) +AC_EGREP_HEADER(ut_name, utmp.h, AC_DEFINE(HAVE_NAME_IN_UTMP)) +AC_EGREP_HEADER(ut_id, utmp.h, AC_DEFINE(HAVE_ID_IN_UTMP)) +AC_EGREP_HEADER(ut_host, utmp.h, AC_DEFINE(HAVE_HOST_IN_UTMP)) +AC_EGREP_HEADER(ut_addr, utmp.h, AC_DEFINE(HAVE_ADDR_IN_UTMP)) + +AC_EGREP_HEADER(ut_session, utmpx.h, AC_DEFINE(HAVE_UT_SESSION)) +AC_EGREP_HEADER(ut_syslen, utmpx.h, AC_DEFINE(HAVE_UT_SYSLEN)) + +AC_CHECK_LIB(c, crypt, [true], AC_CHECK_LIB(crypt, crypt)) +AC_CHECK_LIB(nsl, main) +if test -z "$no_libsocket"; then + AC_CHECK_LIB(socket, socket) +fi +if test -z "$no_libsun"; then + AC_CHECK_LIB(sun, getpwnam) +fi +AC_CHECK_LIB(util, login, AC_DEFINE(HAVE_LIBUTIL_LOGIN) + LIBS="$LIBS -lutil") + +AC_CHECK_LIB(des, main) + +AC_REPLACE_FUNCS(strerror memmove remove random putenv socketpair) + +AC_PROG_LN_S +AC_PROG_INSTALL +if test -z "$no_ranlib"; then + AC_PROG_RANLIB +else + RANLIB=":" +fi +AC_PROGRAMS_CHECK(MAKEDEP, makedepend makedep, makedepend) +AC_PATH_PROGS(WISH, wish8.0 wish wishx wish4.1 true) +if test `basename $WISH` = "true"; then + AC_MSG_WARN(the wish program was not found - ssh-askpass will not work.) + WISH="/usr/local/bin/wish" +fi +AC_PATH_PROG(XAUTH_PATH, xauth, , $PATH:/usr/X11R6/bin) +if test -n "$XAUTH_PATH"; then + AC_DEFINE_UNQUOTED(XAUTH_PATH, "$XAUTH_PATH") +fi + +AC_MSG_CHECKING(for pseudo ttys) +if test -c /dev/ptmx && test -c /dev/pts/0 +then + AC_DEFINE(HAVE_DEV_PTMX) + AC_MSG_RESULT(streams ptys) +else +if test -c /dev/pts && test -c /dev/ptc +then + AC_DEFINE(HAVE_DEV_PTS_AND_PTC) + AC_MSG_RESULT(/dev/pts and /dev/ptc) +else + AC_MSG_RESULT(bsd-style ptys) +fi +fi + +AC_MSG_CHECKING(for /etc/default/login) +if test -f /etc/default/login; then + AC_DEFINE(HAVE_ETC_DEFAULT_LOGIN) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +if test -z "$no_shadows_password_checking"; then + AC_MSG_CHECKING(for shadow passwords) + if test -f /etc/shadow; then + AC_DEFINE(HAVE_ETC_SHADOW) + AC_MSG_RESULT(/etc/shadow) + elif test -n "$os_aix"; then + AC_DEFINE(HAVE_ETC_SECURITY_PASSWD) + AC_MSG_RESULT(/etc/security/passwd) + elif test -n "$os_sunos"; then + AC_DEFINE(HAVE_ETC_SECURITY_PASSWD_ADJUNCT) + AC_MSG_RESULT(/etc/security/passwd.adjunct) + else + AC_MSG_RESULT(no) + fi +fi + +AC_MSG_CHECKING(location of mail spool files) +for dir in /var/spool/mail /var/mail /usr/spool/mail /usr/mail NEWMAIL +do + if test "$dir" = "NEWMAIL"; then + AC_DEFINE(HAVE_TILDE_NEWMAIL) + AC_MSG_RESULT(\$HOME/newmail) + AC_MSG_WARN(mail spool directory was not found: assuming you use \$HOME/newmail) + elif test -d $dir; then + AC_DEFINE_UNQUOTED(MAIL_SPOOL_DIRECTORY, "$dir") + AC_MSG_RESULT($dir) + break + fi +done + +AC_MSG_CHECKING(location of utmp) +if test -f /var/run/utmp; then + AC_DEFINE(SSH_UTMP, "/var/run/utmp") + AC_MSG_RESULT(/var/run/utmp) +elif test -f /var/log/utmp; then + AC_DEFINE(SSH_UTMP, "/var/log/utmp") + AC_MSG_RESULT(/var/log/utmp) +elif test -f /var/adm/utmp; then + AC_DEFINE(SSH_UTMP, "/var/adm/utmp") + AC_MSG_RESULT(/var/adm/utmp) +elif test -f /usr/adm/utmp; then + AC_DEFINE(SSH_UTMP, "/usr/adm/utmp") + AC_MSG_RESULT(/usr/adm/utmp) +elif test -f /etc/utmp; then + AC_DEFINE(SSH_UTMP, "/etc/utmp") + AC_MSG_RESULT(/etc/utmp) +else + AC_MSG_RESULT(not found) +fi + +AC_MSG_CHECKING(location of wtmp) +if test -f /var/log/wtmp; then + AC_DEFINE(SSH_WTMP, "/var/log/wtmp") + AC_MSG_RESULT(/var/log/wtmp) +elif test -f /var/adm/wtmp; then + AC_DEFINE(SSH_WTMP, "/var/adm/wtmp") + AC_MSG_RESULT(/var/adm/wtmp) +elif test -f /usr/adm/wtmp; then + AC_DEFINE(SSH_WTMP, "/usr/adm/wtmp") + AC_MSG_RESULT(/usr/adm/wtmp) +elif test -f /etc/wtmp; then + AC_DEFINE(SSH_WTMP, "/etc/wtmp") + AC_MSG_RESULT(/etc/wtmp) +else + AC_DEFINE(SSH_WTMP, "/var/adm/wtmp") + AC_MSG_RESULT(not found) +fi + +AC_MSG_CHECKING(location of lastlog) +if test -f /var/log/lastlog || test -d /var/log/lastlog; then + AC_DEFINE(SSH_LASTLOG, "/var/log/lastlog") + AC_DEFINE(HAVE_LASTLOG) + LASTLOG=/var/log/lastlog + AC_MSG_RESULT(/var/log/lastlog) +elif test -f /var/adm/lastlog || test -d /var/adm/lastlog; then + AC_DEFINE(SSH_LASTLOG, "/var/adm/lastlog") + AC_DEFINE(HAVE_LASTLOG) + LASTLOG=/var/adm/lastlog + AC_MSG_RESULT(/var/adm/lastlog) +elif test -f /usr/adm/lastlog || test -d /usr/adm/lastlog; then + AC_DEFINE(SSH_LASTLOG, "/usr/adm/lastlog") + AC_DEFINE(HAVE_LASTLOG) + LASTLOG=/usr/adm/lastlog + AC_MSG_RESULT(/usr/adm/lastlog) +elif test -f /etc/lastlog || test -d /etc/lastlog; then + AC_DEFINE(SSH_LASTLOG, "/etc/lastlog") + AC_DEFINE(HAVE_LASTLOG) + LASTLOG=/etc/lastlog + AC_MSG_RESULT(/etc/lastlog) +else + AC_MSG_RESULT(not found) + AC_DEFINE(SSH_LASTLOG, "/var/log/lastlog") + LASTLOG=/var/log/lastlog +fi + +AC_MSG_CHECKING(whether $LASTLOG is a directory) +if test -d $LASTLOG +then + AC_MSG_RESULT(yes) + AC_DEFINE(LASTLOG_IS_DIR) +else + AC_MSG_RESULT(no) +fi + +AC_MSG_CHECKING(whether to include the IDEA encryption algorithm) +AC_ARG_WITH(idea, +[ --with-idea Use IDEA (not default). + --without-idea Don't use IDEA: avoids patent problems in commercial use], +[ case "$withval" in + yes) + AC_MSG_RESULT(yes) + CONFOBJS="$CONFOBJS idea.o" + AC_DEFINE(WITH_IDEA) + ;; + *) + AC_MSG_RESULT(no) + ;; + esac ], + AC_MSG_RESULT(no) +) + +AC_MSG_CHECKING(whether to include the RC4 encryption algorithm) +AC_ARG_WITH(rc4, +[ --with-rc4 Include RC4 support. + --without-rc4 Don't include RC4 support (default)], +[ case "$withval" in + yes) + AC_MSG_RESULT(yes) + CONFOBJS="$CONFOBJS rc4.o" + AC_DEFINE(WITH_RC4) + ;; + *) + AC_MSG_RESULT(no) + ;; + esac ], + AC_MSG_RESULT(no) +) + +AC_MSG_CHECKING(whether to include the Blowfish encryption algorithm) +AC_ARG_WITH(blowfish, +[ --with-blowfish Include Blowfish support (default). + --without-blowfish Don't include Blowfish support], +[ case "$withval" in + no) + ;; + *) + with_blowfish=yes + ;; + esac ], + with_blowfish=yes +) + +case "$with_blowfish" in +yes) + AC_DEFINE(WITH_BLOWFISH) + CONFOBJS="$CONFOBJS bf_skey.o bf_enc.o" + AC_MSG_RESULT(yes) + ;; +no) + AC_MSG_RESULT(no) + ;; +esac + +AC_MSG_CHECKING(whether to use rsaref) +AC_ARG_WITH(rsaref, +[ --with-rsaref Use RSAREF (try to avoid patent problems in U.S.) + --without-rsaref Use normal RSA routines (default). ], +[ case "$withval" in + no) + AC_MSG_RESULT(no) + ;; + *) + AC_MSG_RESULT(yes) + AC_DEFINE(RSAREF) + RSAREFDEP="rsaref2/source/librsaref.a" + LIBS="-lrsaref $LIBS" + LDFLAGS="-Lrsaref2/source $LDFLAGS" + ;; + esac ], + AC_MSG_RESULT(no) +) + +AC_MSG_CHECKING(whether to use ssl) +AC_ARG_WITH(ssl, +[ --with-ssl Use SSL (try to avoid patent problems in U.S.) + --without-ssl Use normal RSA routines (default). ], +[ case "$withval" in + no) + AC_MSG_RESULT(no) + ;; + *) + AC_MSG_RESULT(yes) + AC_DEFINE(DO_SSL) + LIBS="-lcrypto $LIBS" + ;; + esac ], + AC_MSG_RESULT(no) +) + +AC_MSG_CHECKING(whether to use rsh) +AC_ARG_WITH(rsh, +[ --with-rsh=PATH Specify where to find rsh. + --without-rsh Do not use rsh under any conditions. ], +[ case "$withval" in + no) + AC_MSG_RESULT(no) + ;; + yes) + AC_MSG_RESULT(yes) + AC_PATH_PROGS(RSH_PATH, remsh rsh) + AC_DEFINE_UNQUOTED(RSH_PATH, "$RSH_PATH") + ;; + *) + AC_MSG_RESULT($withval) + AC_DEFINE_UNQUOTED(RSH_PATH, "$withval") + ;; + esac ], + [ AC_MSG_RESULT(yes) + AC_PATH_PROGS(RSH_PATH, remsh rsh) + AC_DEFINE_UNQUOTED(RSH_PATH, "$RSH_PATH") ] +) + +# Code to permit setting default path for users (alden@math.ohio-state.edu) +AC_MSG_CHECKING(default path) +AC_ARG_WITH(path, +[ --with-path=PATH Default path passed to user shell by sshd.], +[ case "$withval" in + no) + AC_MSG_RESULT(use system default) + ;; + *) + AC_MSG_RESULT($withval) + AC_DEFINE_UNQUOTED(DEFAULT_PATH, "$withval") + ;; + esac ], + AC_MSG_RESULT(use system default) +) + +AC_MSG_CHECKING(etcdir) +AC_ARG_WITH(etcdir, +[ --with-etcdir=PATH Directory containing ssh system files (default /etc).], +[ case "$withval" in + no) + AC_MSG_ERROR(Need ETCDIR.) + ;; + yes) + ETCDIR="/etc" + AC_MSG_RESULT(/etc) + ;; + *) + ETCDIR="$withval" + AC_MSG_RESULT($withval) + ;; + esac ], + ETCDIR="/etc" + AC_MSG_RESULT(/etc) +) + +AC_MSG_CHECKING(whether to support SecurID) +AC_ARG_WITH(securid, +[ --with-securid[=PATH] Enable support for Security Dynamics SecurID card.], +[ case "$withval" in + no) + AC_MSG_RESULT(no) + ;; + yes) + AC_MSG_RESULT(yes) + if test '!' -f /usr/ace/sdiclient.a; then + AC_ERROR(SecurID sdiclient.a not found in /usr/ace: you must supply the path.) + fi + AC_MSG_RESULT(yes) + AC_MSG_RESULT(Assuming SecurID headers and libraries are in /usr/ace.) + AC_DEFINE(HAVE_SECURID) + CFLAGS="$CFLAGS -I/usr/ace" + LIBS="/usr/ace/sdiclient.a $LIBS" + ;; + *) + AC_MSG_RESULT(yes) + if test '!' -f $withval/sdiclient.a; then + AC_ERROR(SecurID sdiclient.a not found in $withval: please supply the correct path.) + fi + AC_MSG_RESULT(Assuming SecurID headers and libraries are in $withval.) + AC_DEFINE(HAVE_SECURID) + CFLAGS="$CFLAGS -I$withval" + LIBS="$withval/sdiclient.a $LIBS" + ;; + esac ], + AC_MSG_RESULT(no) +) + +AC_MSG_CHECKING(whether to include compression support) +AC_ARG_WITH(zlib, +[ --with-zlib Use zlib (default). + --without-zlib Don't use zlib.], +[ case "$withval" in + no) + ;; + *) + with_zlib=yes + ;; + esac ], + with_zlib=yes +) + +case "$with_zlib" in +yes) + AC_MSG_RESULT(yes) + AC_CHECK_HEADERS(zlib.h) + if test "$ac_cv_header_zlib_h" != yes; then + echo "Can't find zlib.h, disable with --without-zlib" + exit 1 + fi + AC_CHECK_LIB(z, main) + if test "$ac_cv_lib_z_main" != yes; then + echo "Can't find library z (libz.a), disable with --without-zlib" + exit 1 + fi + CONFOBJS="$CONFOBJS compress.o" + AC_DEFINE(WITH_ZLIB) + ;; +no) + AC_MSG_RESULT(no) + ;; +esac + +AC_MSG_CHECKING(whether to use Kerberos v4) +AC_ARG_WITH(krb4, +[ --with-krb4[=PATH] Compile in Kerberos v4 support.], +[ case "$withval" in + yes) + ;; + no) + ;; + *) + ;; + esac ], +[ with_krb4=default ] +) +# krb4 continued +case "$with_krb4" in +no) + AC_MSG_RESULT(no) + ;; +yes) + AC_MSG_RESULT(yes) + AC_CHECK_HEADERS(krb.h) + if test "$ac_cv_header_krb_h" != yes; then + echo "Can't find include file krb.h! Aborting!" + exit 1 + fi + AC_CHECK_LIB(krb, main) + if test "$ac_cv_lib_krb_main" != yes; then + echo "Can't find library krb (libkrb.a)! Aborting" + exit 1 + fi + AC_DEFINE(KRB4) + KRB4_AUTH="auth-krb4.o" + KRB4_ROOT="" + KRB4_INCS="" + KRB4_LIBS="-lkrb -ldes" + AC_CHECK_LIB(resolv, dn_expand, KRB4_LIBS="$KRB4_LIBS -lresolv") + ;; +default) + AC_CHECK_HEADERS(krb.h) + AC_CHECK_LIB(krb, main) + if test "$ac_cv_header_krb_h" = yes -a "$ac_cv_lib_krb_main" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(KRB4) + KRB4_AUTH="auth-krb4.o" + KRB4_ROOT="" + KRB4_INCS="" + KRB4_LIBS="-lkrb -ldes" + AC_CHECK_LIB(resolv, dn_expand, KRB4_LIBS="$KRB4_LIBS -lresolv") + else + AC_MSG_RESULT(no) + fi + ;; +*) + AC_MSG_RESULT(yes) + AC_DEFINE(KRB4) + KRB4_AUTH="auth-krb4.o" + KRB4_ROOT="$with_krb4" + KRB4_INCS="-I\$(KRB4_ROOT)/include" + KRB4_LIBS="-L\$(KRB4_ROOT)/lib -lkrb -ldes" + AC_CHECK_LIB(resolv, dn_expand, KRB4_LIBS="$KRB4_LIBS -lresolv") + ;; +esac +AC_SUBST(KRB4_AUTH) dnl +AC_SUBST(KRB4_ROOT) dnl +AC_SUBST(KRB4_INCS) dnl +AC_SUBST(KRB4_LIBS) dnl + +AC_MSG_CHECKING(whether to use AFS) +AC_ARG_WITH(afs, +[ --with-afs Compile in AFS support (requires KTH krb4).], +if test "$with_afs" = no; then + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + AC_DEFINE(AFS) + AC_DEFINE(KERBEROS_TGT_PASSING) + RADIX="radix.o" + if test "$with_krb4" = no; then + AC_MSG_RESULT(no) + AC_MSG_WARN("AFS requires Kerberos v4 support.") + else + KRB4_LIBS="${KRB4_LIBS} -lkafs" + if test -n "$os_aix"; then + KRB4_LIBS="${KRB4_LIBS} -lld" + fi + fi +fi +) +AC_SUBST(RADIX)dnl + +AC_MSG_CHECKING(whether to use libwrap) +AC_ARG_WITH(libwrap, +[ --with-libwrap[=PATH] Compile in libwrap (tcp_wrappers) support.], +[ case "$withval" in + no) + AC_MSG_RESULT(no) + ;; + yes) + AC_MSG_RESULT(yes) + AC_DEFINE(LIBWRAP) + LIBS="-lwrap $LIBS" + AC_TRY_LINK([ int allow_severity; int deny_severity; ], + [ hosts_access(); ], + [], + [ AC_MSG_ERROR(Could not find the libwrap.a library. You must first install tcp_wrappers.) ]) + ;; + *) + AC_MSG_RESULT(yes) + AC_DEFINE(LIBWRAP) + LIBS="$withval $LIBS" + AC_TRY_LINK([ int allow_severity; int deny_severity; ], + [ hosts_access(); ], + [], + [ AC_MSG_ERROR(Could not find the $withval library. You must first install tcp_wrappers.) ]) + ;; + esac ], + AC_MSG_RESULT(no) +) + +AC_MSG_CHECKING(whether to support SOCKS) +AC_ARG_WITH(socks, +[ --with-socks[=PATH] Compile with SOCKS firewall traversal support.], +[ case "$withval" in + no) + AC_MSG_RESULT(no) + ;; + *) + AC_MSG_RESULT(yes) + AC_DEFINE(SOCKS) + AC_DEFINE(connect, Rconnect) + AC_DEFINE(getsockname, Rgetsockname) + AC_DEFINE(bind, Rbind) + AC_DEFINE(accept, Raccept) + AC_DEFINE(listen, Rlisten) + AC_DEFINE(select, Rselect) + if test "x$withval" = "xyes"; then + withval="-lsocks" + fi + LIBS="$withval $LIBS" + AC_TRY_LINK([], + [ Rconnect(); ], + [], + [ AC_MSG_ERROR(Could not find the $withval library. You must first install socks.) ]) + ;; + esac ], + AC_MSG_RESULT(no) +) + +PIDDIR="/var/run" +AC_MSG_CHECKING(where to put sshd.pid) +if test '!' -d $PIDDIR; then + PIDDIR="$ETCDIR" +fi +AC_MSG_RESULT($PIDDIR) + +AC_ARG_PROGRAM + +AC_SUBST(ETCDIR) +AC_SUBST(PIDDIR) +AC_SUBST(RSAREFDEP) +AC_SUBST(CONFOBJS) + +AC_OUTPUT(Makefile sshd.8 ssh.1) diff --git a/usr.bin/ssh/crc32.c b/usr.bin/ssh/crc32.c new file mode 100644 index 00000000000..7473e278279 --- /dev/null +++ b/usr.bin/ssh/crc32.c @@ -0,0 +1,120 @@ +/* The implementation here was originally done by Gary S. Brown. I have + borrowed the tables directly, and made some minor changes to the + crc32-function (including changing the interface). //ylo */ + +#include "includes.h" +RCSID("$Id: crc32.c,v 1.1 1999/09/26 20:53:35 deraadt Exp $"); + +#include "crc32.h" + + /* ============================================================= */ + /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ + /* code or tables extracted from it, as desired without restriction. */ + /* */ + /* First, the polynomial itself and its table of feedback terms. The */ + /* polynomial is */ + /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ + /* */ + /* Note that we take it "backwards" and put the highest-order term in */ + /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ + /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ + /* the MSB being 1. */ + /* */ + /* Note that the usual hardware shift register implementation, which */ + /* is what we're using (we're merely optimizing it by doing eight-bit */ + /* chunks at a time) shifts bits into the lowest-order term. In our */ + /* implementation, that means shifting towards the right. Why do we */ + /* do it this way? Because the calculated CRC must be transmitted in */ + /* order from highest-order term to lowest-order term. UARTs transmit */ + /* characters in order from LSB to MSB. By storing the CRC this way, */ + /* we hand it to the UART in the order low-byte to high-byte; the UART */ + /* sends each low-bit to hight-bit; and the result is transmission bit */ + /* by bit from highest- to lowest-order term without requiring any bit */ + /* shuffling on our part. Reception works similarly. */ + /* */ + /* The feedback terms table consists of 256, 32-bit entries. Notes: */ + /* */ + /* The table can be generated at runtime if desired; code to do so */ + /* is shown later. It might not be obvious, but the feedback */ + /* terms simply represent the results of eight shift/xor opera- */ + /* tions for all combinations of data and CRC register values. */ + /* */ + /* The values must be right-shifted by eight bits by the "updcrc" */ + /* logic; the shift must be unsigned (bring in zeroes). On some */ + /* hardware you could probably optimize the shift in assembler by */ + /* using byte-swap instructions. */ + /* polynomial $edb88320 */ + /* */ + /* -------------------------------------------------------------------- */ + +static unsigned long crc32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL + }; + +/* Return a 32-bit CRC of the contents of the buffer. */ + +unsigned long crc32(const unsigned char *s, unsigned int len) +{ + unsigned int i; + unsigned long crc32val; + + crc32val = 0; + for (i = 0; i < len; i ++) + { + crc32val = + crc32_tab[(crc32val ^ s[i]) & 0xff] ^ + (crc32val >> 8); + } + return crc32val; +} diff --git a/usr.bin/ssh/crc32.h b/usr.bin/ssh/crc32.h new file mode 100644 index 00000000000..dbc0a2fb1e7 --- /dev/null +++ b/usr.bin/ssh/crc32.h @@ -0,0 +1,25 @@ +/* + +crc32.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1992 Tatu Ylonen, Espoo, Finland + All rights reserved + +Created: Tue Feb 11 14:37:27 1992 ylo + +Functions for computing 32-bit CRC. + +*/ + +/* RCSID("$Id: crc32.h,v 1.1 1999/09/26 20:53:35 deraadt Exp $"); */ + +#ifndef CRC32_H +#define CRC32_H + +/* This computes a 32 bit CRC of the data in the buffer, and returns the + CRC. The polynomial used is 0xedb88320. */ +unsigned long crc32(const unsigned char *buf, unsigned int len); + +#endif /* CRC32_H */ diff --git a/usr.bin/ssh/fdlim.h b/usr.bin/ssh/fdlim.h new file mode 100644 index 00000000000..eec041b2c5b --- /dev/null +++ b/usr.bin/ssh/fdlim.h @@ -0,0 +1,69 @@ +/* + +fdlim.h + +Author: David Mazieres <dm@lcs.mit.edu> + Contributed to be part of ssh. + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Tue Aug 22 17:21:32 1995 ylo + +*/ + +/* RCSID("$Id: fdlim.h,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); */ + +#ifndef FDLIM_H +#define FDLIM_H + +static int +fdlim_get (int hard) +{ +#ifdef RLIMIT_NOFILE + struct rlimit rlfd; + if (getrlimit (RLIMIT_NOFILE, &rlfd) < 0) + return (-1); +#ifdef RLIM_INFINITY /* not defined on HPSUX */ + if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY) + return 10000; + else + return hard ? rlfd.rlim_max : rlfd.rlim_cur; +#else /* RLIM_INFINITY */ + return hard ? rlfd.rlim_max : rlfd.rlim_cur; +#endif /* RLIM_INFINITY */ +#else /* !RLIMIT_NOFILE */ +#ifdef HAVE_GETDTABLESIZE + return (getdtablesize ()); +#else /* !HAVE_GETDTABLESIZE */ +#ifdef _SC_OPEN_MAX + return (sysconf (_SC_OPEN_MAX)); +#else /* !_SC_OPEN_MAX */ +#ifdef NOFILE + return (NOFILE); +#else /* !NOFILE */ + return (25); +#endif /* !NOFILE */ +#endif /* !_SC_OPEN_MAX */ +#endif /* !HAVE_GETDTABLESIZE */ +#endif /* !RLIMIT_NOFILE */ +} + +static int +fdlim_set (int lim) { +#ifdef RLIMIT_NOFILE + struct rlimit rlfd; + if (lim <= 0) + return (-1); + if (getrlimit (RLIMIT_NOFILE, &rlfd) < 0) + return (-1); + rlfd.rlim_cur = lim; + if (setrlimit (RLIMIT_NOFILE, &rlfd) < 0) + return (-1); + return (0); +#else /* !RLIMIT_NOFILE */ + return (-1); +#endif /* !RLIMIT_NOFILE */ +} + +#endif /* FDLIM_H */ diff --git a/usr.bin/ssh/gen_minfd.c b/usr.bin/ssh/gen_minfd.c new file mode 100644 index 00000000000..6d1bbcd2317 --- /dev/null +++ b/usr.bin/ssh/gen_minfd.c @@ -0,0 +1,123 @@ +/* + +gen_minfd.c + +Author: David Mazieres <dm@lcs.mit.edu> + Contributed to be part of ssh. + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Tue Aug 22 17:22:57 1995 ylo +Last modified: Tue Aug 22 17:44:32 1995 ylo + +*/ + +#include "includes.h" +#include <sys/resource.h> +#include "fdlim.h" + +static char *self; + +static void +child_test (char *fdstr) +{ + int fd = atoi (fdstr); + if (fcntl (fd, F_GETFL, NULL) < 0) { + exit (1); + } + exit (0); +} + +static int +run_child (char *shell, int fd) +{ + char cmd[128]; + int pid; + int status; + + if (dup2 (0, fd) < 0) { + perror ("dup2"); + return (-1); + } + + sprintf (cmd, "%s -fd %d", self, fd); + + fflush (stdout); + pid = fork (); + if (! pid) { + close (1); /* prevent any garbage from entering the output */ + dup (2); + execlp (shell, shell, "-c", cmd, NULL); + exit (1); + } + close (fd); + if (wait (&status) != pid) { + fprintf (stderr, "wrong/no child??\n"); + exit (1); + } + return (status ? -1 : 0); +} + +static int +do_shell (char *shell) +{ + int fd, min, max; + + min = 3; + max = fdlim_get (0) - 1; + if (max < 0) { + printf ("fdlim_get: bad value\n"); + exit (1); + } + + if (run_child (shell, max) + && run_child (shell, --max)) /* bizarre ultrix weirdness */ + return (-1); + + while (min + 1 < max) { + fd = (min + max) / 2; + if (run_child (shell, fd)) + min = fd; + else + max = fd; + } + return (max); +} + +int +main (int argc, char **argv) +{ + int fd; + int i; + char *p; + + if (argc == 3 && !strcmp (argv[1], "-fd")) + child_test (argv[2]); + self = argv[0]; + + fd = fdlim_get (1); + if (fd < 0) { + fprintf (stderr, "fdlim_get: bad value\n"); + exit (1); + } + fdlim_set (fd); + printf ("/* maximum file descriptors = %d */\n\n", fd); + printf ("struct Min_Auth_Fd {\n" + " int fd;\n" + " char shell[32];\n" + "};\n\n" + "static struct Min_Auth_Fd mafd[] = {\n"); + for (i = 1; i < argc; i++) { + fd = do_shell (argv[i]); + if ((p = strrchr (argv[i], '/'))) + p++; + else + p = argv[i]; + if (fd > 0) + printf (" { %d, \"%s\" },\n", fd, p); + } + printf (" { 0, \"\" },\n};\n\n" + "#define MAFD_MAX (sizeof (mafd) / sizeof (mafd[0]) - 1)\n"); + return (0); +} diff --git a/usr.bin/ssh/getput.h b/usr.bin/ssh/getput.h new file mode 100644 index 00000000000..1c255bdbaa4 --- /dev/null +++ b/usr.bin/ssh/getput.h @@ -0,0 +1,64 @@ +/* + +getput.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Wed Jun 28 22:36:30 1995 ylo + +Macros for storing and retrieving data in msb first and lsb first order. + +*/ + +/* RCSID("$Id: getput.h,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); */ + +#ifndef GETPUT_H +#define GETPUT_H + +/*------------ macros for storing/extracting msb first words -------------*/ + +#define GET_32BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 24) | \ + ((unsigned long)(unsigned char)(cp)[1] << 16) | \ + ((unsigned long)(unsigned char)(cp)[2] << 8) | \ + ((unsigned long)(unsigned char)(cp)[3])) + +#define GET_16BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 8) | \ + ((unsigned long)(unsigned char)(cp)[1])) + +#define PUT_32BIT(cp, value) do { \ + (cp)[0] = (value) >> 24; \ + (cp)[1] = (value) >> 16; \ + (cp)[2] = (value) >> 8; \ + (cp)[3] = (value); } while (0) + +#define PUT_16BIT(cp, value) do { \ + (cp)[0] = (value) >> 8; \ + (cp)[1] = (value); } while (0) + +/*------------ macros for storing/extracting lsb first words -------------*/ + +#define GET_32BIT_LSB_FIRST(cp) \ + (((unsigned long)(unsigned char)(cp)[0]) | \ + ((unsigned long)(unsigned char)(cp)[1] << 8) | \ + ((unsigned long)(unsigned char)(cp)[2] << 16) | \ + ((unsigned long)(unsigned char)(cp)[3] << 24)) + +#define GET_16BIT_LSB_FIRST(cp) \ + (((unsigned long)(unsigned char)(cp)[0]) | \ + ((unsigned long)(unsigned char)(cp)[1] << 8)) + +#define PUT_32BIT_LSB_FIRST(cp, value) do { \ + (cp)[0] = (value); \ + (cp)[1] = (value) >> 8; \ + (cp)[2] = (value) >> 16; \ + (cp)[3] = (value) >> 24; } while (0) + +#define PUT_16BIT_LSB_FIRST(cp, value) do { \ + (cp)[0] = (value); \ + (cp)[1] = (value) >> 8; } while (0) + +#endif /* GETPUT_H */ + diff --git a/usr.bin/ssh/host_config.sample b/usr.bin/ssh/host_config.sample new file mode 100644 index 00000000000..3d9d600de6f --- /dev/null +++ b/usr.bin/ssh/host_config.sample @@ -0,0 +1,29 @@ +# This is ssh client systemwide configuration file. This file provides +# defaults for users, and the values can be changed in per-user configuration +# files or on the command line. + +# Configuration data is parsed as follows: +# 1. command line options +# 2. user-specific file +# 3. system-wide file +# Any configuration value is only changed the first time it is set. +# Thus, host-specific definitions should be at the beginning of the +# configuration file, and defaults at the end. + +# Site-wide defaults for various options + +# Host * +# ForwardAgent yes +# ForwardX11 yes +# RhostsAuthentication yes +# RhostsRSAAuthentication yes +# RSAAuthentication yes +# PasswordAuthentication yes +# FallBackToRsh yes +# UseRsh no +# BatchMode no +# StrictHostKeyChecking no +# IdentityFile ~/.ssh/identity +# Port 22 +# Cipher idea +# EscapeChar ~ diff --git a/usr.bin/ssh/hostfile.c b/usr.bin/ssh/hostfile.c new file mode 100644 index 00000000000..27c56af2eb7 --- /dev/null +++ b/usr.bin/ssh/hostfile.c @@ -0,0 +1,275 @@ +/* + +hostfile.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Thu Jun 29 07:10:56 1995 ylo + +Functions for manipulating the known hosts files. + +*/ + +#include "includes.h" +RCSID("$Id: hostfile.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#include "packet.h" +#include "ssh.h" + +/* Reads a multiple-precision integer in hex from the buffer, and advances the + pointer. The integer must already be initialized. This function is + permitted to modify the buffer. This leaves *cpp to point just beyond + the last processed (and maybe modified) character. Note that this may + modify the buffer containing the number. */ + +int auth_rsa_read_mp_int(char **cpp, MP_INT *value) +{ + char *cp = *cpp; + int len, old; + + /* Skip any leading whitespace. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Check that it begins with a hex digit. */ + if (*cp < '0' || *cp > '9') + return 0; + + /* Save starting position. */ + *cpp = cp; + + /* Move forward until all hex digits skipped. */ + for (; *cp >= '0' && *cp <= '9'; cp++) + ; + + /* Compute the length of the hex number. */ + len = cp - *cpp; + + /* Save the old terminating character, and replace it by \0. */ + old = *cp; + *cp = 0; + + /* Parse the number. */ + if (mpz_set_str(value, *cpp, 10) != 0) + return 0; + + /* Restore old terminating character. */ + *cp = old; + + /* Move beyond the number and return success. */ + *cpp = cp; + return 1; +} + +/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer + over the key. Skips any whitespace at the beginning and at end. */ + +int auth_rsa_read_key(char **cpp, unsigned int *bitsp, MP_INT *e, MP_INT *n) +{ + unsigned int bits; + char *cp; + + /* Skip leading whitespace. */ + for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Get number of bits. */ + if (*cp < '0' || *cp > '9') + return 0; /* Bad bit count... */ + for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) + bits = 10 * bits + *cp - '0'; + + /* Get public exponent. */ + if (!auth_rsa_read_mp_int(&cp, e)) + return 0; + + /* Get public modulus. */ + if (!auth_rsa_read_mp_int(&cp, n)) + return 0; + + /* Skip trailing whitespace. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Return results. */ + *cpp = cp; + *bitsp = bits; + return 1; +} + +/* Tries to match the host name (which must be in all lowercase) against the + comma-separated sequence of subpatterns (each possibly preceded by ! to + indicate negation). Returns true if there is a positive match; zero + otherwise. */ + +int match_hostname(const char *host, const char *pattern, unsigned int len) +{ + char sub[1024]; + int negated; + int got_positive; + unsigned int i, subi; + + got_positive = 0; + for (i = 0; i < len;) + { + /* Check if the subpattern is negated. */ + if (pattern[i] == '!') + { + negated = 1; + i++; + } + else + negated = 0; + + /* Extract the subpattern up to a comma or end. Convert the subpattern + to lowercase. */ + for (subi = 0; + i < len && subi < sizeof(sub) - 1 && pattern[i] != ','; + subi++, i++) + sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i]; + /* If subpattern too long, return failure (no match). */ + if (subi >= sizeof(sub) - 1) + return 0; + + /* If the subpattern was terminated by a comma, skip the comma. */ + if (i < len && pattern[i] == ',') + i++; + + /* Null-terminate the subpattern. */ + sub[subi] = '\0'; + + /* Try to match the subpattern against the host name. */ + if (match_pattern(host, sub)) + if (negated) + return 0; /* Fail if host matches any negated subpattern. */ + else + got_positive = 1; + } + + /* Return success if got a positive match. If there was a negative match, + we have already returned zero and never get here. */ + return got_positive; +} + +/* Checks whether the given host (which must be in all lowercase) is + already in the list of our known hosts. + Returns HOST_OK if the host is known and has the specified key, + HOST_NEW if the host is not known, and HOST_CHANGED if the host is known + but used to have a different host key. */ + +HostStatus check_host_in_hostfile(const char *filename, + const char *host, unsigned int bits, + MP_INT *e, MP_INT *n) +{ + FILE *f; + char line[8192]; + MP_INT ke, kn; + unsigned int kbits, hostlen; + char *cp, *cp2; + HostStatus end_return; + struct stat st; + + /* Open the file containing the list of known hosts. */ + f = fopen(filename, "r"); + if (!f) + { + if (stat(filename, &st) >= 0) + { + packet_send_debug("Could not open %.900s for reading.", filename); + packet_send_debug("If your home directory is on an NFS volume, it may need to be world-readable."); + } + return HOST_NEW; + } + + /* Initialize mp-int variables. */ + mpz_init(&ke); + mpz_init(&kn); + + /* Cache the length of the host name. */ + hostlen = strlen(host); + + /* Return value when the loop terminates. This is set to HOST_CHANGED if + we have seen a different key for the host and have not found the proper + one. */ + end_return = HOST_NEW; + + /* Go trough the file. */ + while (fgets(line, sizeof(line), f)) + { + cp = line; + + /* Skip any leading whitespace. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Ignore comment lines and empty lines. */ + if (!*cp || *cp == '#' || *cp == '\n') + continue; + + /* Find the end of the host name portion. */ + for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) + ; + + /* Check if the host name matches. */ + if (!match_hostname(host, cp, (unsigned int)(cp2 - cp))) + continue; + + /* Got a match. Skip host name. */ + cp = cp2; + + /* Extract the key from the line. This will skip any leading + whitespace. Ignore badly formatted lines. */ + if (!auth_rsa_read_key(&cp, &kbits, &ke, &kn)) + continue; + + /* Check if the current key is the same as the previous one. */ + if (kbits == bits && mpz_cmp(&ke, e) == 0 && mpz_cmp(&kn, n) == 0) + { + /* Ok, they match. */ + mpz_clear(&ke); + mpz_clear(&kn); + fclose(f); + return HOST_OK; + } + + /* They do not match. We will continue to go through the file; however, + we note that we will not return that it is new. */ + end_return = HOST_CHANGED; + } + /* Clear variables and close the file. */ + mpz_clear(&ke); + mpz_clear(&kn); + fclose(f); + + /* Return either HOST_NEW or HOST_CHANGED, depending on whether we saw a + different key for the host. */ + return end_return; +} + +/* Appends an entry to the host file. Returns false if the entry + could not be appended. */ + +int add_host_to_hostfile(const char *filename, const char *host, + unsigned int bits, MP_INT *e, MP_INT *n) +{ + FILE *f; + + /* Open the file for appending. */ + f = fopen(filename, "a"); + if (!f) + return 0; + + /* Print the host name and key to the file. */ + fprintf(f, "%s %u ", host, bits); + mpz_out_str(f, 10, e); + fprintf(f, " "); + mpz_out_str(f, 10, n); + fprintf(f, "\n"); + + /* Close the file. */ + fclose(f); + return 1; +} diff --git a/usr.bin/ssh/includes.h b/usr.bin/ssh/includes.h new file mode 100644 index 00000000000..d0f32525e1f --- /dev/null +++ b/usr.bin/ssh/includes.h @@ -0,0 +1,263 @@ +/* + +includes.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Thu Mar 23 16:29:37 1995 ylo + +This file includes most of the needed system headers. + +*/ + +/* RCSID("$Id: includes.h,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); */ + +#ifndef INCLUDES_H +#define INCLUDES_H + +/* Note: autoconf documentation tells to use the <...> syntax and have -I. */ +#include <config.h> + +#include "version.h" + +typedef unsigned short word16; + +#if SIZEOF_LONG == 4 +typedef unsigned long word32; +#else +#if SIZEOF_INT == 4 +typedef unsigned int word32; +#else +#if SIZEOF_SHORT >= 4 +typedef unsigned short word32; +#else +YOU_LOSE +#endif +#endif +#endif + +#ifdef SCO +/* this is defined so that winsize gets ifdef'd in termio.h */ +#define _IBCS2 +#endif + +#if defined(__mips) +/* Mach3 on MIPS defines conflicting garbage. */ +#define uint32 hidden_uint32 +#endif /* __mips */ +#include <sys/types.h> +#if defined(__mips) +#undef uint32 +#endif /* __mips */ + +#if defined(bsd_44) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__PARAGON__) +#include <sys/param.h> +#include <machine/endian.h> +#endif +#if defined(linux) +#include <endian.h> +#endif + +#include <stdio.h> +#include <ctype.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> +#include <assert.h> +#include <signal.h> + +#ifdef sparc +#undef HAVE_SYS_IOCTL_H +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif /* HAVE_SYS_IOCTL_H */ + +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#define USING_TERMIOS +#endif /* HAVE_TERMIOS_H */ + +#if defined(HAVE_SGTTY_H) && !defined(USING_TERMIOS) +#include <sgtty.h> +#define USING_SGTTY +#endif + +#if !defined(USING_SGTTY) && !defined(USING_TERMIOS) + ERROR_NO_TERMIOS_OR_SGTTY +#endif + +#ifdef STDC_HEADERS +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#else /* STDC_HEADERS */ +/* stdarg.h is present almost everywhere, and comes with gcc; I am too lazy + to make things work with both it and varargs. */ +#include <stdarg.h> +#ifndef HAVE_STRCHR +#define strchr index +#define strrchr rindex +#endif +char *strchr(), *strrchr(); +#ifndef HAVE_MEMCPY +#define memcpy(d, s, n) bcopy((s), (d), (n)) +#define memmove(d, s, n) bcopy((s), (d), (n)) +#define memset(d, ch, n) bzero((d), (n)) /* We only memset to 0. */ +#define memcmp(a, b, n) bcmp((a), (b), (n)) +#endif +#endif /* STDC_HEADERS */ + +#include <sys/socket.h> +#include <netinet/in.h> +#ifdef HAVE_NETINET_IN_SYSTM_H +#include <netinet/in_systm.h> +#else /* Some old linux systems at least have in_system.h instead. */ +#include <netinet/in_system.h> +#endif /* HAVE_NETINET_IN_SYSTM_H */ +#ifdef SCO +/* SCO does not have a un.h and there is no appropriate substitute. */ +/* Latest news: it doesn't have AF_UNIX at all, but this allows + it to compile, and outgoing forwarded connections appear to work. */ +struct sockaddr_un { + short sun_family; /* AF_UNIX */ + char sun_path[108]; /* path name (gag) */ +}; +/* SCO needs sys/stream.h and sys/ptem.h */ +#include <sys/stream.h> +#include <sys/ptem.h> +#else /* SCO */ +#include <sys/un.h> +#endif /* SCO */ +#if !defined(__PARAGON__) +#include <netinet/ip.h> +#endif /* !__PARAGON__ */ +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <netdb.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif /* HAVE_SYS_SELECT_H */ + +#include <pwd.h> +#include <grp.h> +#ifdef HAVE_GETSPNAM +#include <shadow.h> +#endif /* HAVE_GETSPNAM */ + +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#else /* HAVE_SYS_WAIT_H */ +#if !defined(WNOHANG) /* && (defined(bsd43) || defined(vax)) */ +#define WNOHANG 1 +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(X) ((unsigned)(X) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(X) (((X) & 255) == 0) +#endif +#ifndef WIFSIGNALED +#define WIFSIGNALED(X) ((((X) & 255) != 0x255 && ((X) & 255) != 0)) +#endif +#ifndef WTERMSIG +#define WTERMSIG(X) ((X) & 255) +#endif +#endif /* HAVE_SYS_WAIT_H */ + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ + +#ifdef TIME_WITH_SYS_TIME +#ifndef SCO +/* I excluded <sys/time.h> to avoid redefinition of timeval + which SCO puts in both <sys/select.h> and <sys/time.h> */ +#include <sys/time.h> +#endif /* SCO */ +#include <time.h> +#else /* TIME_WITH_SYS_TIME */ +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#else /* HAVE_SYS_TIME_H */ +#include <time.h> +#endif /* HAVE_SYS_TIME_H */ +#endif /* TIME_WITH_SYS_TIME */ + +#ifdef HAVE_PATHS_H +#include <paths.h> +#endif + +#if HAVE_DIRENT_H +#include <dirent.h> +#define NAMLEN(dirent) strlen((dirent)->d_name) +#else +#define dirent direct +#define NAMLEN(dirent) (dirent)->d_namlen +#if HAVE_SYS_NDIR_H +#include <sys/ndir.h> +#endif +#if HAVE_SYS_DIR_H +#include <sys/dir.h> +#endif +#if HAVE_NDIR_H +#include <ndir.h> +#endif +#endif + +#ifdef HAVE_SETRLIMIT +#include <sys/resource.h> +#endif + +#ifndef HAVE_VSNPRINTF +#define vsnprintf(buf, len, fmt, args) vsprintf(buf, fmt, args) +#endif + +/* These POSIX macros are not defined in every system. */ + +#ifndef S_IRWXU +#define S_IRWXU 00700 /* read, write, execute: owner */ +#define S_IRUSR 00400 /* read permission: owner */ +#define S_IWUSR 00200 /* write permission: owner */ +#define S_IXUSR 00100 /* execute permission: owner */ +#define S_IRWXG 00070 /* read, write, execute: group */ +#define S_IRGRP 00040 /* read permission: group */ +#define S_IWGRP 00020 /* write permission: group */ +#define S_IXGRP 00010 /* execute permission: group */ +#define S_IRWXO 00007 /* read, write, execute: other */ +#define S_IROTH 00004 /* read permission: other */ +#define S_IWOTH 00002 /* write permission: other */ +#define S_IXOTH 00001 /* execute permission: other */ +#endif /* S_IRWXU */ + +#ifndef S_ISUID +#define S_ISUID 0x800 +#endif /* S_ISUID */ +#ifndef S_ISGID +#define S_ISGID 0x400 +#endif /* S_ISGID */ + +#ifndef S_ISDIR +/* NextStep apparently fails to define this. */ +#define S_ISDIR(mode) (((mode)&(_S_IFMT))==(_S_IFDIR)) +#endif + +#ifdef STAT_MACROS_BROKEN +/* Some systems have broken S_ISDIR etc. macros in sys/stat.h. Please ask + your vendor to fix them. You can then remove the line below, but only + after you have sent a complaint to your vendor. */ +WARNING_MACROS_IN_SYS_STAT_H_ARE_BROKEN_ON_YOUR_SYSTEM_READ_INCLUDES_H +#endif /* STAT_MACROS_BROKEN */ + +#if USE_STRLEN_FOR_AF_UNIX +#define AF_UNIX_SIZE(unaddr) \ + (sizeof((unaddr).sun_family) + strlen((unaddr).sun_path) + 1) +#else +#define AF_UNIX_SIZE(unaddr) sizeof(unaddr) +#endif + +#endif /* INCLUDES_H */ diff --git a/usr.bin/ssh/install-sh b/usr.bin/ssh/install-sh new file mode 100644 index 00000000000..89fc9b098b8 --- /dev/null +++ b/usr.bin/ssh/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/usr.bin/ssh/log-client.c b/usr.bin/ssh/log-client.c new file mode 100644 index 00000000000..651f991e3f1 --- /dev/null +++ b/usr.bin/ssh/log-client.c @@ -0,0 +1,137 @@ +/* + +log-client.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Mon Mar 20 21:13:40 1995 ylo + +Client-side versions of debug(), log(), etc. These print to stderr. + +*/ + +#include "includes.h" +RCSID("$Id: log-client.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#include "xmalloc.h" +#include "ssh.h" + +static int log_debug = 0; +static int log_quiet = 0; + +void log_init(char *av0, int on_stderr, int debug, int quiet, + SyslogFacility facility) +{ + log_debug = debug; + log_quiet = quiet; +} + +void log(const char *fmt, ...) +{ + va_list args; + + if (log_quiet) + return; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); +} + +void debug(const char *fmt, ...) +{ + va_list args; + if (log_quiet || !log_debug) + return; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); +} + +void error(const char *fmt, ...) +{ + va_list args; + if (log_quiet) + return; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); +} + +struct fatal_cleanup +{ + struct fatal_cleanup *next; + void (*proc)(void *); + void *context; +}; + +static struct fatal_cleanup *fatal_cleanups = NULL; + +/* Registers a cleanup function to be called by fatal() before exiting. */ + +void fatal_add_cleanup(void (*proc)(void *), void *context) +{ + struct fatal_cleanup *cu; + + cu = xmalloc(sizeof(*cu)); + cu->proc = proc; + cu->context = context; + cu->next = fatal_cleanups; + fatal_cleanups = cu; +} + +/* Removes a cleanup frunction to be called at fatal(). */ + +void fatal_remove_cleanup(void (*proc)(void *context), void *context) +{ + struct fatal_cleanup **cup, *cu; + + for (cup = &fatal_cleanups; *cup; cup = &cu->next) + { + cu = *cup; + if (cu->proc == proc && cu->context == context) + { + *cup = cu->next; + xfree(cu); + return; + } + } + fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n", + (unsigned long)proc, (unsigned long)context); +} + +/* Function to display an error message and exit. This is in this file because + this needs to restore terminal modes before exiting. See log-client.c + for other related functions. */ + +void fatal(const char *fmt, ...) +{ + va_list args; + struct fatal_cleanup *cu, *next_cu; + static int fatal_called = 0; + + if (!fatal_called) + { + fatal_called = 1; + + /* Call cleanup functions. */ + for (cu = fatal_cleanups; cu; cu = next_cu) + { + next_cu = cu->next; + (*cu->proc)(cu->context); + } + } + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + exit(255); +} + +/* fatal() is in ssh.c so that it can properly reset terminal modes. */ diff --git a/usr.bin/ssh/log-server.c b/usr.bin/ssh/log-server.c new file mode 100644 index 00000000000..a5086b5df91 --- /dev/null +++ b/usr.bin/ssh/log-server.c @@ -0,0 +1,242 @@ +/* + +log-server.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Mon Mar 20 21:19:30 1995 ylo + +Server-side versions of debug(), log(), etc. These normally send the output +to the system log. + +*/ + +#include "includes.h" +RCSID("$Id: log-server.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#include <syslog.h> +#ifdef NEED_SYS_SYSLOG_H +#include <sys/syslog.h> +#endif /* NEED_SYS_SYSLOG_H */ +#include "packet.h" +#include "xmalloc.h" +#include "ssh.h" + +static int log_debug = 0; +static int log_quiet = 0; +static int log_on_stderr = 0; + +/* Initialize the log. + av0 program name (should be argv[0]) + on_stderr print also on stderr + debug send debugging messages to system log + quiet don\'t log anything + */ + +void log_init(char *av0, int on_stderr, int debug, int quiet, + SyslogFacility facility) +{ + int log_facility; + + switch (facility) + { + case SYSLOG_FACILITY_DAEMON: + log_facility = LOG_DAEMON; + break; + case SYSLOG_FACILITY_USER: + log_facility = LOG_USER; + break; + case SYSLOG_FACILITY_AUTH: + log_facility = LOG_AUTH; + break; + case SYSLOG_FACILITY_LOCAL0: + log_facility = LOG_LOCAL0; + break; + case SYSLOG_FACILITY_LOCAL1: + log_facility = LOG_LOCAL1; + break; + case SYSLOG_FACILITY_LOCAL2: + log_facility = LOG_LOCAL2; + break; + case SYSLOG_FACILITY_LOCAL3: + log_facility = LOG_LOCAL3; + break; + case SYSLOG_FACILITY_LOCAL4: + log_facility = LOG_LOCAL4; + break; + case SYSLOG_FACILITY_LOCAL5: + log_facility = LOG_LOCAL5; + break; + case SYSLOG_FACILITY_LOCAL6: + log_facility = LOG_LOCAL6; + break; + case SYSLOG_FACILITY_LOCAL7: + log_facility = LOG_LOCAL7; + break; + default: + fprintf(stderr, "Unrecognized internal syslog facility code %d\n", + (int)facility); + exit(1); + } + + log_debug = debug; + log_quiet = quiet; + log_on_stderr = on_stderr; + closelog(); /* Close any previous log. */ + openlog(av0, LOG_PID, log_facility); +} + +#define MSGBUFSIZE 1024 + +#ifdef HAVE_VSNPRINTF +#define DECL_MSGBUF char msgbuf[MSGBUFSIZE] +#else +static char msgbuf[MSGBUFSIZE]; +#define DECL_MSGBUF +#endif + +/* Log this message (information that usually should go to the log). */ + +void log(const char *fmt, ...) +{ + va_list args; + DECL_MSGBUF; + if (log_quiet) + return; + va_start(args, fmt); + vsnprintf(msgbuf, MSGBUFSIZE, fmt, args); + va_end(args); + if (log_on_stderr) + fprintf(stderr, "log: %s\n", msgbuf); + syslog(LOG_INFO, "log: %.500s", msgbuf); +} + +/* Debugging messages that should not be logged during normal operation. */ + +void debug(const char *fmt, ...) +{ + va_list args; + DECL_MSGBUF; + if (!log_debug || log_quiet) + return; + va_start(args, fmt); + vsnprintf(msgbuf, MSGBUFSIZE, fmt, args); + va_end(args); + if (log_on_stderr) + fprintf(stderr, "debug: %s\n", msgbuf); + syslog(LOG_DEBUG, "debug: %.500s", msgbuf); +} + +/* Error messages that should be logged. */ + +void error(const char *fmt, ...) +{ + va_list args; + DECL_MSGBUF; + if (log_quiet) + return; + va_start(args, fmt); + vsnprintf(msgbuf, MSGBUFSIZE, fmt, args); + va_end(args); + if (log_on_stderr) + fprintf(stderr, "error: %s\n", msgbuf); + syslog(LOG_ERR, "error: %.500s", msgbuf); +} + +struct fatal_cleanup +{ + struct fatal_cleanup *next; + void (*proc)(void *); + void *context; +}; + +static struct fatal_cleanup *fatal_cleanups = NULL; + +/* Registers a cleanup function to be called by fatal() before exiting. */ + +void fatal_add_cleanup(void (*proc)(void *), void *context) +{ + struct fatal_cleanup *cu; + + cu = xmalloc(sizeof(*cu)); + cu->proc = proc; + cu->context = context; + cu->next = fatal_cleanups; + fatal_cleanups = cu; +} + +/* Removes a cleanup frunction to be called at fatal(). */ + +void fatal_remove_cleanup(void (*proc)(void *context), void *context) +{ + struct fatal_cleanup **cup, *cu; + + for (cup = &fatal_cleanups; *cup; cup = &cu->next) + { + cu = *cup; + if (cu->proc == proc && cu->context == context) + { + *cup = cu->next; + xfree(cu); + return; + } + } + fatal("fatal_remove_cleanup: no such cleanup function: 0x%lx 0x%lx\n", + (unsigned long)proc, (unsigned long)context); +} + +/* Fatal messages. This function never returns. */ + +void fatal(const char *fmt, ...) +{ + va_list args; + struct fatal_cleanup *cu, *next_cu; + static int fatal_called = 0; +#if defined(KRB4) + extern char *ticket; +#endif /* KRB4 */ + DECL_MSGBUF; + + if (log_quiet) + exit(1); + va_start(args, fmt); + vsnprintf(msgbuf, MSGBUFSIZE, fmt, args); + va_end(args); + if (log_on_stderr) + fprintf(stderr, "fatal: %s\n", msgbuf); + syslog(LOG_ERR, "fatal: %.500s", msgbuf); + + if (fatal_called) + exit(1); + fatal_called = 1; + + /* Call cleanup functions. */ + for (cu = fatal_cleanups; cu; cu = next_cu) + { + next_cu = cu->next; + debug("Calling cleanup 0x%lx(0x%lx)", + (unsigned long)cu->proc, (unsigned long)cu->context); + (*cu->proc)(cu->context); + } +#if defined(KRB4) + /* If you forwarded a ticket you get one shot for proper + authentication. */ + /* If tgt was passed unlink file */ + if (ticket) + { + if (strcmp(ticket,"none")) + /* ticket -> FILE:path */ + unlink(ticket + 5); + else + ticket = NULL; + } +#endif /* KRB4 */ + + /* If local XAUTHORITY was created, remove it. */ + if (xauthfile) unlink(xauthfile); + + exit(1); +} diff --git a/usr.bin/ssh/login.c b/usr.bin/ssh/login.c new file mode 100644 index 00000000000..6386d45f99f --- /dev/null +++ b/usr.bin/ssh/login.c @@ -0,0 +1,399 @@ +/* + +login.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Fri Mar 24 14:51:08 1995 ylo + +This file performs some of the things login(1) normally does. We cannot +easily use something like login -p -h host -f user, because there are +several different logins around, and it is hard to determined what kind of +login the current system has. Also, we want to be able to execute commands +on a tty. + +*/ + +#include "includes.h" +RCSID("$Id: login.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#ifdef HAVE_UTMP_H +#include <utmp.h> +#ifdef HAVE_LASTLOG_H +#include <lastlog.h> /* Some have the definitions in utmp.h. */ +#endif /* HAVE_LASTLOG_H */ +#endif /* HAVE_UTMP_H */ +#ifdef HAVE_UTMPX_H +#include <utmpx.h> +#endif /* HAVE_UTMPX_H */ +#ifdef HAVE_USERSEC_H +#include <usersec.h> +#endif /* HAVE_USERSEC_H */ +#include "ssh.h" + +/* Returns the time when the user last logged in. Returns 0 if the + information is not available. This must be called before record_login. + The host the user logged in from will be returned in buf. */ + +#ifdef LASTLOG_IS_DIR +unsigned long get_last_login_time(uid_t uid, const char *name, + char *buf, unsigned int bufsize) +{ +#if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG) + struct lastlog ll; + char lastlogfile[500]; + int fd; + +#ifdef _PATH_LASTLOG + sprintf(lastlogfile, "%.200s/%.200s", _PATH_LASTLOG, name); +#else +#ifdef LASTLOG_FILE + sprintf(lastlogfile, "%.200s/%.200s", LASTLOG_FILE, name); +#else + sprintf(lastlogfile, "%.200s/%.200s", SSH_LASTLOG, name); +#endif +#endif + + strcpy(buf, ""); + + fd = open(lastlogfile, O_RDONLY); + if (fd < 0) + return 0; + if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) + { + close(fd); + return 0; + } + close(fd); + if (bufsize > sizeof(ll.ll_host) + 1) + bufsize = sizeof(ll.ll_host) + 1; + strncpy(buf, ll.ll_host, bufsize - 1); + buf[bufsize - 1] = 0; + return ll.ll_time; + +#else /* HAVE_LASTLOG_H || HAVE_LASTLOG */ + + return 0; + +#endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */ +} + +#else /* LASTLOG_IS_DIR */ + +/* Returns the time when the user last logged in (or 0 if no previous login + is found). The name of the host used last time is returned in buf. */ + +unsigned long get_last_login_time(uid_t uid, const char *logname, + char *buf, unsigned int bufsize) +{ +#if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG) + + struct lastlog ll; + char *lastlog; + int fd; + +#ifdef _PATH_LASTLOG + lastlog = _PATH_LASTLOG; +#else +#ifdef LASTLOG_FILE + lastlog = LASTLOG_FILE; +#else + lastlog = SSH_LASTLOG; +#endif +#endif + + strcpy(buf, ""); + + fd = open(lastlog, O_RDONLY); + if (fd < 0) + return 0; + lseek(fd, (off_t)((long)uid * sizeof(ll)), 0); + if (read(fd, &ll, sizeof(ll)) != sizeof(ll)) + { + close(fd); + return 0; + } + close(fd); + if (bufsize > sizeof(ll.ll_host) + 1) + bufsize = sizeof(ll.ll_host) + 1; + strncpy(buf, ll.ll_host, bufsize - 1); + buf[bufsize - 1] = 0; + return ll.ll_time; + +#else /* HAVE_LASTLOG_H || HAVE_LASTLOG */ + +#ifdef HAVE_USERSEC_H + + char *lasthost; + int lasttime; + if (setuserdb(S_READ) < 0) + return 0; + if (getuserattr((char *)logname, S_LASTTIME, &lasttime, SEC_INT) < 0) + { + enduserdb(); + return 0; + } + if (getuserattr((char *)logname, S_LASTHOST, &lasthost, SEC_CHAR) < 0) + { + enduserdb(); + return 0; + } + strncpy(buf, lasthost, bufsize); + buf[bufsize - 1] = 0; + if (enduserdb() < 0) + return 0; + return lasttime; + +#else /* HAVE_USERSEC_H */ + + return 0; + +#endif /* HAVE_USERSEC_H */ + +#endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */ +} +#endif /* LASTLOG_IS_DIR */ + +/* Records that the user has logged in. I these parts of operating systems + were more standardized. */ + +void record_login(int pid, const char *ttyname, const char *user, uid_t uid, + const char *host, struct sockaddr_in *addr) +{ + int fd; + +#if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG) + struct lastlog ll; + char *lastlog; +#ifdef LASTLOG_IS_DIR + char lastlogfile[100]; +#endif /* LASTLOG_IS_DIR */ +#endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */ + +#if defined(HAVE_UTMP_H) && !defined(HAVE_UTMPX_H) + struct utmp u, u2; + off_t offset; + const char *utmp, *wtmp; + + /* Construct an utmp/wtmp entry. */ + memset(&u, 0, sizeof(u)); +#ifdef DEAD_PROCESS + if (strcmp(user, "") == 0) + u.ut_type = DEAD_PROCESS; /* logout */ + else + u.ut_type = USER_PROCESS; +#endif /* LOGIN_PROCESS */ +#ifdef HAVE_PID_IN_UTMP + u.ut_pid = pid; +#endif /* PID_IN_UTMP */ +#ifdef HAVE_ID_IN_UTMP +#ifdef __sgi + strncpy(u.ut_id, ttyname + 8, sizeof(u.ut_id)); /* /dev/ttyq99 -> q99 */ +#else /* __sgi */ + if (sizeof(u.ut_id) > 4) + strncpy(u.ut_id, ttyname + 5, sizeof(u.ut_id)); + else + strncpy(u.ut_id, ttyname + strlen(ttyname) - 2, sizeof(u.ut_id)); +#endif /* __sgi */ +#endif /* HAVE_ID_IN_UTMP */ + strncpy(u.ut_line, ttyname + 5, sizeof(u.ut_line)); + u.ut_time = time(NULL); +#ifdef HAVE_NAME_IN_UTMP + strncpy(u.ut_name, user, sizeof(u.ut_name)); +#else /* HAVE_NAME_IN_UTMP */ + strncpy(u.ut_user, user, sizeof(u.ut_user)); +#endif /* HAVE_NAME_IN_UTMP */ +#ifdef HAVE_HOST_IN_UTMP + strncpy(u.ut_host, host, sizeof(u.ut_host)); +#endif /* HAVE_HOST_IN_UTMP */ +#ifdef HAVE_ADDR_IN_UTMP + if (addr) + memcpy(&u.ut_addr, &addr->sin_addr, sizeof(u.ut_addr)); + else + memset(&u.ut_addr, 0, sizeof(u.ut_addr)); +#endif + + /* Figure out the file names. */ +#ifdef _PATH_UTMP + utmp = _PATH_UTMP; + wtmp = _PATH_WTMP; +#else +#ifdef UTMP_FILE + utmp = UTMP_FILE; + wtmp = WTMP_FILE; +#else + utmp = SSH_UTMP; + wtmp = SSH_WTMP; +#endif +#endif + +#ifdef HAVE_LIBUTIL_LOGIN + login(&u); +#else /* HAVE_LIBUTIL_LOGIN */ + /* Append an entry to wtmp. */ + fd = open(wtmp, O_WRONLY|O_APPEND); + if (fd >= 0) + { + if (write(fd, &u, sizeof(u)) != sizeof(u)) + log("Could not write %.100s: %.100s", wtmp, strerror(errno)); + close(fd); + } + + /* Replace the proper entry in utmp, as identified by ut_line. Append a + new entry if the line could not be found. */ + fd = open(utmp, O_RDWR); + if (fd >= 0) + { + while (1) + { + offset = lseek(fd, (off_t)0L, 1); + if (read(fd, &u2, sizeof(u2)) != sizeof(u2)) + { + lseek(fd, offset, 0); + if (write(fd, &u, sizeof(u)) != sizeof(u)) + log("Could not append to %.100s: %.100s", + utmp, strerror(errno)); + break; + } + if (strncmp(u2.ut_line, ttyname + 5, sizeof(u2.ut_line)) == 0) + { + lseek(fd, offset, 0); + if (write(fd, &u, sizeof(u)) != sizeof(u)) + log("Could not write to %.100s: %.100s", + utmp, strerror(errno)); + break; + } + } + close(fd); + } +#endif /* HAVE_LIBUTIL_LOGIN */ +#endif /* HAVE_UTMP_H && !HAVE_UTMPX_H */ + +#ifdef HAVE_UTMPX_H + { + struct utmpx ux, *uxp; + memset(&ux, 0, sizeof(ux)); + strncpy(ux.ut_line, ttyname + 5, sizeof(ux.ut_line)); + uxp = getutxline(&ux); + if (uxp) + ux = *uxp; + strncpy(ux.ut_user, user, sizeof(ux.ut_user)); +#ifdef __sgi + strncpy(ux.ut_id, ttyname + 8, sizeof(ux.ut_id)); /* /dev/ttyq99 -> q99 */ +#else /* __sgi */ + if (sizeof(ux.ut_id) > 4) + strncpy(ux.ut_id, ttyname + 5, sizeof(ux.ut_id)); + else + strncpy(ux.ut_id, ttyname + strlen(ttyname) - 2, sizeof(ux.ut_id)); +#endif /* __sgi */ + ux.ut_pid = pid; + if (strcmp(user, "") == 0) + ux.ut_type = DEAD_PROCESS; + else + ux.ut_type = USER_PROCESS; + gettimeofday(&ux.ut_tv, NULL); +#if HAVE_UT_SESSION + ux.ut_session = pid; +#endif + strncpy(ux.ut_host, host, sizeof(ux.ut_host)); + ux.ut_host[sizeof(ux.ut_host) - 1] = 0; +#ifdef HAVE_UT_SYSLEN + ux.ut_syslen = strlen(ux.ut_host); +#endif + pututxline(&ux); +#ifdef WTMPX_FILE + updwtmpx(WTMPX_FILE, &ux); +#endif + endutxent(); + } +#endif /* HAVE_UTMPX_H */ + +#if defined(HAVE_LASTLOG_H) || defined(HAVE_LASTLOG) + +#ifdef _PATH_LASTLOG + lastlog = _PATH_LASTLOG; +#else +#ifdef LASTLOG_FILE + lastlog = LASTLOG_FILE; +#else + lastlog = SSH_LASTLOG; +#endif +#endif + + /* Update lastlog unless actually recording a logout. */ + if (strcmp(user, "") != 0) + { + /* It is safer to bzero the lastlog structure first because some + systems might have some extra fields in it (e.g. SGI) */ + memset(&ll, 0, sizeof(ll)); + + /* Update lastlog. */ + ll.ll_time = time(NULL); + strncpy(ll.ll_line, ttyname + 5, sizeof(ll.ll_line)); + strncpy(ll.ll_host, host, sizeof(ll.ll_host)); +#ifdef LASTLOG_IS_DIR + sprintf(lastlogfile, "%.100s/%.100s", lastlog, user); + fd = open(lastlogfile, O_WRONLY | O_CREAT, 0644); + if (fd >= 0) + { + if (write(fd, &ll, sizeof(ll)) != sizeof(ll)) + log("Could not write %.100s: %.100s", + lastlogfile, strerror(errno)); + close(fd); + } + else + { + log("Could not open %.100s: %.100s", lastlogfile, strerror(errno)); + } +#else /* LASTLOG_IS_DIR */ + fd = open(lastlog, O_RDWR); + if (fd >= 0) + { + lseek(fd, (off_t)((long)uid * sizeof(ll)), 0); + if (write(fd, &ll, sizeof(ll)) != sizeof(ll)) + log("Could not write %.100s: %.100s", lastlog, strerror(errno)); + close(fd); + } +#endif /* LASTLOG_IS_DIR */ + } +#endif /* HAVE_LASTLOG_H || HAVE_LASTLOG */ + +#ifdef HAVE_USERSEC_H + + if (strcmp(user, "") != 0) + { + int lasttime = time(NULL); + if (setuserdb(S_WRITE) < 0) + log("setuserdb S_WRITE failed: %.100s", strerror(errno)); + if (putuserattr((char *)user, S_LASTTIME, (void *)lasttime, SEC_INT) < 0) + log("putuserattr S_LASTTIME failed: %.100s", strerror(errno)); + if (putuserattr((char *)user, S_LASTTTY, (void *)(ttyname + 5), + SEC_CHAR) < 0) + log("putuserattr S_LASTTTY %.900s failed: %.100s", + ttyname, strerror(errno)); + if (putuserattr((char *)user, S_LASTHOST, (void *)host, SEC_CHAR) < 0) + log("putuserattr S_LASTHOST %.900s failed: %.100s", + host, strerror(errno)); + if (putuserattr((char *)user, 0, NULL, SEC_COMMIT) < 0) + log("putuserattr SEC_COMMIT failed: %.100s", strerror(errno)); + if (enduserdb() < 0) + log("enduserdb failed: %.100s", strerror(errno)); + } +#endif +} + +/* Records that the user has logged out. */ + +void record_logout(int pid, const char *ttyname) +{ +#ifdef HAVE_LIBUTIL_LOGIN + const char *line = ttyname + 5; /* /dev/ttyq8 -> ttyq8 */ + if (logout(line)) + logwtmp(line, "", ""); +#else /* HAVE_LIBUTIL_LOGIN */ + record_login(pid, ttyname, "", -1, "", NULL); +#endif /* HAVE_LIBUTIL_LOGIN */ +} diff --git a/usr.bin/ssh/match.c b/usr.bin/ssh/match.c new file mode 100644 index 00000000000..a5cab2877e4 --- /dev/null +++ b/usr.bin/ssh/match.c @@ -0,0 +1,78 @@ +/* + +match.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Thu Jun 22 01:17:50 1995 ylo + +Simple pattern matching, with '*' and '?' as wildcards. + +*/ + +#include "includes.h" +RCSID("$Id: match.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#include "ssh.h" + +/* Returns true if the given string matches the pattern (which may contain + ? and * as wildcards), and zero if it does not match. */ + +int match_pattern(const char *s, const char *pattern) +{ + while (1) + { + /* If at end of pattern, accept if also at end of string. */ + if (!*pattern) + return !*s; + + /* Process '*'. */ + if (*pattern == '*') + { + /* Skip the asterisk. */ + pattern++; + + /* If at end of pattern, accept immediately. */ + if (!*pattern) + return 1; + + /* If next character in pattern is known, optimize. */ + if (*pattern != '?' && *pattern != '*') + { + /* Look instances of the next character in pattern, and try + to match starting from those. */ + for (; *s; s++) + if (*s == *pattern && + match_pattern(s + 1, pattern + 1)) + return 1; + /* Failed. */ + return 0; + } + + /* Move ahead one character at a time and try to match at each + position. */ + for (; *s; s++) + if (match_pattern(s, pattern)) + return 1; + /* Failed. */ + return 0; + } + + /* There must be at least one more character in the string. If we are + at the end, fail. */ + if (!*s) + return 0; + + /* Check if the next character of the string is acceptable. */ + if (*pattern != '?' && *pattern != *s) + return 0; + + /* Move to the next character, both in string and in pattern. */ + s++; + pattern++; + } + /*NOTREACHED*/ +} diff --git a/usr.bin/ssh/minfd.c b/usr.bin/ssh/minfd.c new file mode 100644 index 00000000000..a074acbf265 --- /dev/null +++ b/usr.bin/ssh/minfd.c @@ -0,0 +1,96 @@ +/* + +minfd.c + +Author: David Mazieres <dm@lcs.mit.edu> + Contributed to be part of ssh. + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Tue Aug 22 17:25:30 1995 ylo + +*/ + +#include "includes.h" +RCSID("$Id: minfd.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#include <sys/resource.h> /* Needed by fdlim.h */ +#include "fdlim.h" +#include "minfd.h" + +#ifdef _PATH_BSHELL +#define DEFAULT_SHELL _PATH_BSHELL +#else +#define DEFAULT_SHELL "/bin/sh" +#endif + +static int +_get_permanent_fd(const char *shellpath) +{ + const char *shell; + struct passwd *pwd; + int fdmin; + int fdlim; + int fd; + int i; + + if (!shellpath) + { + if (!shellpath) + shellpath = getenv("SHELL"); + if (!shellpath) + if ((pwd = getpwuid(getuid()))) + shellpath = pwd->pw_shell; + if (!shellpath) + shellpath = DEFAULT_SHELL; + } + if ((shell = strrchr(shellpath, '/'))) + shell++; + else + shell = shellpath; + + for (i = 0; strcmp(mafd[i].shell, shell); i++) + if (i == MAFD_MAX - 1) + return -1; + + fdmin = mafd[i].fd; + fdlim = fdlim_get(0); + + if (fdmin < fdlim) + { + /* First try to find a file descriptor as high as possible without + upping the limit */ + fd = fdlim - 1; + while (fd >= fdmin) + { + if (fcntl(fd, F_GETFL, NULL) < 0) + return fd; + fd--; + } + } + + fd = fdlim; + for (;;) + { + if (fdlim_set(fd + 1) < 0) + return -1; + if (fcntl(fd, F_GETFL, NULL) < 0) + break; + fd++; + } + return fd; +} + +int +get_permanent_fd(const char *shellpath) +{ + static int fd = -2; + + if (fd >= -1) + return fd; + fd = _get_permanent_fd(shellpath); + if (fd < 0) + fd = -1; + return fd; +} diff --git a/usr.bin/ssh/mpaux.c b/usr.bin/ssh/mpaux.c new file mode 100644 index 00000000000..78ff1f93d68 --- /dev/null +++ b/usr.bin/ssh/mpaux.c @@ -0,0 +1,93 @@ +/* + +mpaux.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sun Jul 16 04:29:30 1995 ylo + +This file contains various auxiliary functions related to multiple +precision integers. + +*/ + +#include "includes.h" +RCSID("$Id: mpaux.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#include <gmp.h> +#include "getput.h" +#include "xmalloc.h" +#include "ssh_md5.h" + +/* Converts a multiple-precision integer into bytes to be stored in the buffer. + The buffer will contain the value of the integer, msb first. */ + +void mp_linearize_msb_first(unsigned char *buf, unsigned int len, + MP_INT *value) +{ + unsigned int i; + MP_INT aux; + mpz_init_set(&aux, value); + for (i = len; i >= 4; i -= 4) + { + unsigned int limb = mpz_get_ui(&aux); + PUT_32BIT(buf + i - 4, limb); + mpz_div_2exp(&aux, &aux, 32); + } + for (; i > 0; i--) + { + buf[i - 1] = mpz_get_ui(&aux); + mpz_div_2exp(&aux, &aux, 8); + } + mpz_clear(&aux); +} + +/* Extract a multiple-precision integer from buffer. The value is stored + in the buffer msb first. */ + +void mp_unlinearize_msb_first(MP_INT *value, const unsigned char *buf, + unsigned int len) +{ + unsigned int i; + mpz_set_ui(value, 0); + for (i = 0; i + 4 <= len; i += 4) + { + unsigned int limb = GET_32BIT(buf + i); + mpz_mul_2exp(value, value, 32); + mpz_add_ui(value, value, limb); + } + for (; i < len; i++) + { + mpz_mul_2exp(value, value, 8); + mpz_add_ui(value, value, buf[i]); + } +} + +/* Computes a 16-byte session id in the global variable session_id. + The session id is computed by concatenating the linearized, msb + first representations of host_key_n, session_key_n, and the cookie. */ + +void compute_session_id(unsigned char session_id[16], + unsigned char cookie[8], + unsigned int host_key_bits, + MP_INT *host_key_n, + unsigned int session_key_bits, + MP_INT *session_key_n) +{ + unsigned int bytes = (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8 + 8; + unsigned char *buf = xmalloc(bytes); + struct MD5Context md; + + mp_linearize_msb_first(buf, (host_key_bits + 7 ) / 8, host_key_n); + mp_linearize_msb_first(buf + (host_key_bits + 7 ) / 8, + (session_key_bits + 7) / 8, session_key_n); + memcpy(buf + (host_key_bits + 7) / 8 + (session_key_bits + 7) / 8, + cookie, 8); + MD5Init(&md); + MD5Update(&md, buf, bytes); + MD5Final(session_id, &md); + xfree(buf); +} diff --git a/usr.bin/ssh/mpaux.h b/usr.bin/ssh/mpaux.h new file mode 100644 index 00000000000..1a310901786 --- /dev/null +++ b/usr.bin/ssh/mpaux.h @@ -0,0 +1,42 @@ +/* + +mpaux.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sun Jul 16 04:29:30 1995 ylo + +This file contains various auxiliary functions related to multiple +precision integers. + +*/ + +/* RCSID("$Id: mpaux.h,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); */ + +#ifndef MPAUX_H +#define MPAUX_H + +/* Converts a multiple-precision integer into bytes to be stored in the buffer. + The buffer will contain the value of the integer, msb first. */ +void mp_linearize_msb_first(unsigned char *buf, unsigned int len, + MP_INT *value); + +/* Extract a multiple-precision integer from buffer. The value is stored + in the buffer msb first. */ +void mp_unlinearize_msb_first(MP_INT *value, const unsigned char *buf, + unsigned int len); + +/* Computes a 16-byte session id in the global variable session_id. + The session id is computed by concatenating the linearized, msb + first representations of host_key_n, session_key_n, and the cookie. */ +void compute_session_id(unsigned char session_id[16], + unsigned char cookie[8], + unsigned int host_key_bits, + MP_INT *host_key_n, + unsigned int session_key_bits, + MP_INT *session_key_n); + +#endif /* MPAUX_H */ diff --git a/usr.bin/ssh/packet.c b/usr.bin/ssh/packet.c new file mode 100644 index 00000000000..8b3fd513fc3 --- /dev/null +++ b/usr.bin/ssh/packet.c @@ -0,0 +1,732 @@ +/* + +packet.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Mar 18 02:40:40 1995 ylo + +This file contains code implementing the packet protocol and communication +with the other side. This same code is used both on client and server side. + +*/ + +#include "includes.h" +RCSID("$Id: packet.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#include "xmalloc.h" +#include "randoms.h" +#include "buffer.h" +#include "packet.h" +#include "bufaux.h" +#include "ssh.h" +#include "crc32.h" +#include "cipher.h" +#include "getput.h" + +#ifdef WITH_ZLIB +#include "compress.h" +#endif /* WITH_ZLIB */ + +/* This variable contains the file descriptors used for communicating with + the other side. connection_in is used for reading; connection_out + for writing. These can be the same descriptor, in which case it is + assumed to be a socket. */ +static int connection_in = -1; +static int connection_out = -1; + +/* Cipher type. This value is only used to determine whether to pad the + packets with zeroes or random data. */ +static int cipher_type = SSH_CIPHER_NONE; + +/* Protocol flags for the remote side. */ +static unsigned int remote_protocol_flags = 0; + +/* Encryption context for receiving data. This is only used for decryption. */ +static CipherContext receive_context; +/* Encryption coontext for sending data. This is only used for encryption. */ +static CipherContext send_context; + +/* Buffer for raw input data from the socket. */ +static Buffer input; + +/* Buffer for raw output data going to the socket. */ +static Buffer output; + +/* Buffer for the partial outgoing packet being constructed. */ +static Buffer outgoing_packet; + +/* Buffer for the incoming packet currently being processed. */ +static Buffer incoming_packet; + +/* Scratch buffer for packet compression/decompression. */ +static Buffer compression_buffer; + +#ifdef WITH_ZLIB +/* Flag indicating whether packet compression/decompression is enabled. */ +static int packet_compression = 0; +#endif /* WITH_ZLIB */ + +/* Pointer to the random number generator state. */ +static RandomState *random_state; + +/* Flag indicating whether this module has been initialized. */ +static int initialized = 0; + +/* Set to true if the connection is interactive. */ +static int interactive_mode = 0; + +/* Sets the descriptors used for communication. Disables encryption until + packet_set_encryption_key is called. */ + +void packet_set_connection(int fd_in, int fd_out, RandomState *state) +{ + connection_in = fd_in; + connection_out = fd_out; + random_state = state; + cipher_type = SSH_CIPHER_NONE; + cipher_set_key(&send_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 1); + cipher_set_key(&receive_context, SSH_CIPHER_NONE, (unsigned char *)"", 0, 0); + if (!initialized) + { + initialized = 1; + buffer_init(&input); + buffer_init(&output); + buffer_init(&outgoing_packet); + buffer_init(&incoming_packet); + } + + /* Kludge: arrange the close function to be called from fatal(). */ + fatal_add_cleanup((void (*)(void *))packet_close, NULL); +} + +/* Sets the connection into non-blocking mode. */ + +void packet_set_nonblocking() +{ + /* Set the socket into non-blocking mode. */ +#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) + if (fcntl(connection_in, F_SETFL, O_NONBLOCK) < 0) + error("fcntl O_NONBLOCK: %.100s", strerror(errno)); +#else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + if (fcntl(connection_in, F_SETFL, O_NDELAY) < 0) + error("fcntl O_NDELAY: %.100s", strerror(errno)); +#endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + + if (connection_out != connection_in) + { +#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) + if (fcntl(connection_out, F_SETFL, O_NONBLOCK) < 0) + error("fcntl O_NONBLOCK: %.100s", strerror(errno)); +#else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + if (fcntl(connection_out, F_SETFL, O_NDELAY) < 0) + error("fcntl O_NDELAY: %.100s", strerror(errno)); +#endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + } +} + +/* Returns the socket used for reading. */ + +int packet_get_connection_in() +{ + return connection_in; +} + +/* Returns the descriptor used for writing. */ + +int packet_get_connection_out() +{ + return connection_out; +} + +/* Closes the connection and clears and frees internal data structures. */ + +void packet_close() +{ + if (!initialized) + return; + initialized = 0; + if (connection_in == connection_out) + { + shutdown(connection_out, 2); + close(connection_out); + } + else + { + close(connection_in); + close(connection_out); + } + buffer_free(&input); + buffer_free(&output); + buffer_free(&outgoing_packet); + buffer_free(&incoming_packet); +#ifdef WITH_ZLIB + if (packet_compression) + { + buffer_free(&compression_buffer); + buffer_compress_uninit(); + } +#endif /* WITH_ZLIB */ +} + +/* Sets remote side protocol flags. */ + +void packet_set_protocol_flags(unsigned int protocol_flags) +{ + remote_protocol_flags = protocol_flags; + channel_set_options((protocol_flags & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) != 0); +} + +/* Returns the remote protocol flags set earlier by the above function. */ + +unsigned int packet_get_protocol_flags() +{ + return remote_protocol_flags; +} + +#ifdef WITH_ZLIB +/* Starts packet compression from the next packet on in both directions. + Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. */ + +void packet_start_compression(int level) +{ + if (packet_compression) + fatal("Compression already enabled."); + packet_compression = 1; + buffer_init(&compression_buffer); + buffer_compress_init(level); +} +#endif /* WITH_ZLIB */ + +/* Encrypts the given number of bytes, copying from src to dest. + bytes is known to be a multiple of 8. */ + +void packet_encrypt(CipherContext *cc, void *dest, void *src, + unsigned int bytes) +{ + assert((bytes % 8) == 0); + cipher_encrypt(cc, dest, src, bytes); +} + +/* Decrypts the given number of bytes, copying from src to dest. + bytes is known to be a multiple of 8. */ + +void packet_decrypt(CipherContext *cc, void *dest, void *src, + unsigned int bytes) +{ + assert((bytes % 8) == 0); + cipher_decrypt(cc, dest, src, bytes); +} + +/* Causes any further packets to be encrypted using the given key. The same + key is used for both sending and reception. However, both directions + are encrypted independently of each other. */ + +void packet_set_encryption_key(const unsigned char *key, unsigned int keylen, + int cipher, int is_client) +{ + cipher_type = cipher; + if (cipher == SSH_CIPHER_RC4) + { + if (is_client) + { /* In client: use first half for receiving, second for sending. */ + cipher_set_key(&receive_context, cipher, key, keylen / 2, 0); + cipher_set_key(&send_context, cipher, key + keylen / 2, + keylen / 2, 1); + } + else + { /* In server: use first half for sending, second for receiving. */ + cipher_set_key(&receive_context, cipher, key + keylen / 2, + keylen / 2, 0); + cipher_set_key(&send_context, cipher, key, keylen / 2, 1); + } + } + else + { + /* All other ciphers use the same key in both directions for now. */ + cipher_set_key(&receive_context, cipher, key, keylen, 0); + cipher_set_key(&send_context, cipher, key, keylen, 1); + } +} + +/* Starts constructing a packet to send. */ + +void packet_start(int type) +{ + char buf[9]; + + buffer_clear(&outgoing_packet); + memset(buf, 0, 8); + buf[8] = type; + buffer_append(&outgoing_packet, buf, 9); +} + +/* Appends a character to the packet data. */ + +void packet_put_char(int value) +{ + char ch = value; + buffer_append(&outgoing_packet, &ch, 1); +} + +/* Appends an integer to the packet data. */ + +void packet_put_int(unsigned int value) +{ + buffer_put_int(&outgoing_packet, value); +} + +/* Appends a string to packet data. */ + +void packet_put_string(const char *buf, unsigned int len) +{ + buffer_put_string(&outgoing_packet, buf, len); +} + +/* Appends an arbitrary precision integer to packet data. */ + +void packet_put_mp_int(MP_INT *value) +{ + buffer_put_mp_int(&outgoing_packet, value); +} + +/* Finalizes and sends the packet. If the encryption key has been set, + encrypts the packet before sending. */ + +void packet_send() +{ + char buf[8], *cp; + int i, padding, len; + unsigned long checksum; + +#ifdef WITH_ZLIB + /* If using packet compression, compress the payload of the outgoing + packet. */ + if (packet_compression) + { + buffer_clear(&compression_buffer); + buffer_consume(&outgoing_packet, 8); /* Skip padding. */ + buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); /* padding */ + buffer_compress(&outgoing_packet, &compression_buffer); + buffer_clear(&outgoing_packet); + buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), + buffer_len(&compression_buffer)); + } +#endif /* WITH_ZLIB */ + + /* Compute packet length without padding (add checksum, remove padding). */ + len = buffer_len(&outgoing_packet) + 4 - 8; + + /* Insert padding. */ + padding = 8 - len % 8; + if (cipher_type != SSH_CIPHER_NONE) + { + cp = buffer_ptr(&outgoing_packet); + for (i = 0; i < padding; i++) + cp[7 - i] = random_get_byte(random_state); + } + buffer_consume(&outgoing_packet, 8 - padding); + + /* Add check bytes. */ + checksum = crc32((unsigned char *)buffer_ptr(&outgoing_packet), + buffer_len(&outgoing_packet)); + PUT_32BIT(buf, checksum); + buffer_append(&outgoing_packet, buf, 4); + +#ifdef PACKET_DEBUG + fprintf(stderr, "packet_send plain: "); + buffer_dump(&outgoing_packet); +#endif + + /* Append to output. */ + PUT_32BIT(buf, len); + buffer_append(&output, buf, 4); + buffer_append_space(&output, &cp, buffer_len(&outgoing_packet)); + packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet), + buffer_len(&outgoing_packet)); + +#ifdef PACKET_DEBUG + fprintf(stderr, "encrypted: "); buffer_dump(&output); +#endif + + buffer_clear(&outgoing_packet); + + /* Note that the packet is now only buffered in output. It won\'t be + actually sent until packet_write_wait or packet_write_poll is called. */ +} + +/* Waits until a packet has been received, and returns its type. Note that + no other data is processed until this returns, so this function should + not be used during the interactive session. */ + +int packet_read(int *payload_len_ptr) +{ + int type, len; + fd_set set; + char buf[8192]; + + /* Since we are blocking, ensure that all written packets have been sent. */ + packet_write_wait(); + + /* Stay in the loop until we have received a complete packet. */ + for (;;) + { + /* Try to read a packet from the buffer. */ + type = packet_read_poll(payload_len_ptr); + if (type == SSH_SMSG_SUCCESS + || type == SSH_SMSG_FAILURE + || type == SSH_CMSG_EOF + || type == SSH_CMSG_EXIT_CONFIRMATION) + packet_integrity_check(*payload_len_ptr, 0, type); + /* If we got a packet, return it. */ + if (type != SSH_MSG_NONE) + return type; + /* Otherwise, wait for some data to arrive, add it to the buffer, + and try again. */ + FD_ZERO(&set); + FD_SET(connection_in, &set); + /* Wait for some data to arrive. */ + select(connection_in + 1, &set, NULL, NULL, NULL); + /* Read data from the socket. */ + len = read(connection_in, buf, sizeof(buf)); + if (len == 0) + fatal("Connection closed by remote host."); + if (len < 0) + fatal("Read from socket failed: %.100s", strerror(errno)); + /* Append it to the buffer. */ + packet_process_incoming(buf, len); + } + /*NOTREACHED*/ +} + +/* Waits until a packet has been received, verifies that its type matches + that given, and gives a fatal error and exits if there is a mismatch. */ + +void packet_read_expect(int *payload_len_ptr, int expected_type) +{ + int type; + + type = packet_read(payload_len_ptr); + if (type != expected_type) + packet_disconnect("Protocol error: expected packet type %d, got %d", + expected_type, type); +} + +/* Checks if a full packet is available in the data received so far via + packet_process_incoming. If so, reads the packet; otherwise returns + SSH_MSG_NONE. This does not wait for data from the connection. + + SSH_MSG_DISCONNECT is handled specially here. Also, + SSH_MSG_IGNORE messages are skipped by this function and are never returned + to higher levels. + + The returned payload_len does include space consumed by: + Packet length + Padding + Packet type + Check bytes + + + */ + +int packet_read_poll(int *payload_len_ptr) +{ + unsigned int len, padded_len; + unsigned char *ucp; + char buf[8], *cp; + unsigned long checksum, stored_checksum; + + restart: + + /* Check if input size is less than minimum packet size. */ + if (buffer_len(&input) < 4 + 8) + return SSH_MSG_NONE; + /* Get length of incoming packet. */ + ucp = (unsigned char *)buffer_ptr(&input); + len = GET_32BIT(ucp); + if (len < 1 + 2 + 2 || len > 256*1024) + packet_disconnect("Bad packet length %d.", len); + padded_len = (len + 8) & ~7; + + /* Check if the packet has been entirely received. */ + if (buffer_len(&input) < 4 + padded_len) + return SSH_MSG_NONE; + + /* The entire packet is in buffer. */ + + /* Consume packet length. */ + buffer_consume(&input, 4); + + /* Copy data to incoming_packet. */ + buffer_clear(&incoming_packet); + buffer_append_space(&incoming_packet, &cp, padded_len); + packet_decrypt(&receive_context, cp, buffer_ptr(&input), padded_len); + buffer_consume(&input, padded_len); + +#ifdef PACKET_DEBUG + fprintf(stderr, "read_poll plain: "); buffer_dump(&incoming_packet); +#endif + + /* Compute packet checksum. */ + checksum = crc32((unsigned char *)buffer_ptr(&incoming_packet), + buffer_len(&incoming_packet) - 4); + + /* Skip padding. */ + buffer_consume(&incoming_packet, 8 - len % 8); + + /* Test check bytes. */ + assert(len == buffer_len(&incoming_packet)); + ucp = (unsigned char *)buffer_ptr(&incoming_packet) + len - 4; + stored_checksum = GET_32BIT(ucp); + if (checksum != stored_checksum) + packet_disconnect("Corrupted check bytes on input."); + buffer_consume_end(&incoming_packet, 4); + +#ifdef WITH_ZLIB + /* If using packet compression, decompress the packet. */ + if (packet_compression) + { + buffer_clear(&compression_buffer); + buffer_uncompress(&incoming_packet, &compression_buffer); + buffer_clear(&incoming_packet); + buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), + buffer_len(&compression_buffer)); + } +#endif /* WITH_ZLIB */ + + /* Get packet type. */ + buffer_get(&incoming_packet, &buf[0], 1); + + /* Return length of payload (without type field). */ + *payload_len_ptr = buffer_len(&incoming_packet); + + /* Handle disconnect message. */ + if ((unsigned char)buf[0] == SSH_MSG_DISCONNECT) + fatal("%.900s", packet_get_string(NULL)); + + /* Ignore ignore messages. */ + if ((unsigned char)buf[0] == SSH_MSG_IGNORE) + goto restart; + + /* Send debug messages as debugging output. */ + if ((unsigned char)buf[0] == SSH_MSG_DEBUG) + { + debug("Remote: %.900s", packet_get_string(NULL)); + goto restart; + } + + /* Return type. */ + return (unsigned char)buf[0]; +} + +/* Buffers the given amount of input characters. This is intended to be + used together with packet_read_poll. */ + +void packet_process_incoming(const char *buf, unsigned int len) +{ + buffer_append(&input, buf, len); +} + +/* Returns a character from the packet. */ + +unsigned int packet_get_char() +{ + char ch; + buffer_get(&incoming_packet, &ch, 1); + return (unsigned char)ch; +} + +/* Returns an integer from the packet data. */ + +unsigned int packet_get_int() +{ + return buffer_get_int(&incoming_packet); +} + +/* Returns an arbitrary precision integer from the packet data. The integer + must have been initialized before this call. */ + +void packet_get_mp_int(MP_INT *value, int *length_ptr) +{ + *length_ptr = buffer_get_mp_int(&incoming_packet, value); +} + +/* Returns a string from the packet data. The string is allocated using + xmalloc; it is the responsibility of the calling program to free it when + no longer needed. The length_ptr argument may be NULL, or point to an + integer into which the length of the string is stored. */ + +char *packet_get_string(unsigned int *length_ptr) +{ + return buffer_get_string(&incoming_packet, length_ptr); +} + +/* Sends a diagnostic message from the server to the client. This message + can be sent at any time (but not while constructing another message). + The message is printed immediately, but only if the client is being + executed in verbose mode. These messages are primarily intended to + ease debugging authentication problems. The length of the formatted + message must not exceed 1024 bytes. This will automatically call + packet_write_wait. */ + +void packet_send_debug(const char *fmt, ...) +{ + char buf[1024]; + va_list args; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + packet_start(SSH_MSG_DEBUG); + packet_put_string(buf, strlen(buf)); + packet_send(); + packet_write_wait(); +} + +/* Logs the error plus constructs and sends a disconnect + packet, closes the connection, and exits. This function never returns. + The error message should not contain a newline. The length of the + formatted message must not exceed 1024 bytes. */ + +void packet_disconnect(const char *fmt, ...) +{ + char buf[1024]; + va_list args; + static int disconnecting = 0; + if (disconnecting) /* Guard against recursive invocations. */ + fatal("packet_disconnect called recursively."); + disconnecting = 1; + + /* Format the message. Note that the caller must make sure the message + is of limited size. */ + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + /* Send the disconnect message to the other side, and wait for it to get + sent. */ + packet_start(SSH_MSG_DISCONNECT); + packet_put_string(buf, strlen(buf)); + packet_send(); + packet_write_wait(); + + /* Stop listening for connections. */ + channel_stop_listening(); + + /* Close the connection. */ + packet_close(); + + /* Display the error locally and exit. */ + fatal("Local: %.100s", buf); +} + +/* Checks if there is any buffered output, and tries to write some of the + output. */ + +void packet_write_poll() +{ + int len = buffer_len(&output); + if (len > 0) + { + len = write(connection_out, buffer_ptr(&output), len); + if (len <= 0) + if (errno == EAGAIN) + return; + else + fatal("Write failed: %.100s", strerror(errno)); + buffer_consume(&output, len); + } +} + +/* Calls packet_write_poll repeatedly until all pending output data has + been written. */ + +void packet_write_wait() +{ + packet_write_poll(); + while (packet_have_data_to_write()) + { + fd_set set; + FD_ZERO(&set); + FD_SET(connection_out, &set); + select(connection_out + 1, NULL, &set, NULL, NULL); + packet_write_poll(); + } +} + +/* Returns true if there is buffered data to write to the connection. */ + +int packet_have_data_to_write() +{ + return buffer_len(&output) != 0; +} + +/* Returns true if there is not too much data to write to the connection. */ + +int packet_not_very_much_data_to_write() +{ + if (interactive_mode) + return buffer_len(&output) < 16384; + else + return buffer_len(&output) < 128*1024; +} + +/* Informs that the current session is interactive. Sets IP flags for that. */ + +void packet_set_interactive(int interactive, int keepalives) +{ + int on = 1; + + /* Record that we are in interactive mode. */ + interactive_mode = interactive; + + /* Only set socket options if using a socket (as indicated by the descriptors + being the same). */ + if (connection_in != connection_out) + return; + + if (keepalives) + { + /* Set keepalives if requested. */ + if (setsockopt(connection_in, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, + sizeof(on)) < 0) + error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); + } + + if (interactive) + { + /* Set IP options for an interactive connection. Use IPTOS_LOWDELAY + and TCP_NODELAY. */ +#ifdef IPTOS_LOWDELAY + int lowdelay = IPTOS_LOWDELAY; + if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&lowdelay, + sizeof(lowdelay)) < 0) + error("setsockopt IPTOS_LOWDELAY: %.100s", strerror(errno)); +#endif /* IPTOS_LOWDELAY */ + if (setsockopt(connection_in, IPPROTO_TCP, TCP_NODELAY, (void *)&on, + sizeof(on)) < 0) + error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); + } + else + { + /* Set IP options for a non-interactive connection. Use + IPTOS_THROUGHPUT. */ +#ifdef IPTOS_THROUGHPUT + int throughput = IPTOS_THROUGHPUT; + if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, (void *)&throughput, + sizeof(throughput)) < 0) + error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno)); +#endif /* IPTOS_THROUGHPUT */ + } +} + +/* Returns true if the current connection is interactive. */ + +int packet_is_interactive() +{ + return interactive_mode; +} diff --git a/usr.bin/ssh/packet.h b/usr.bin/ssh/packet.h new file mode 100644 index 00000000000..9a39bb9b637 --- /dev/null +++ b/usr.bin/ssh/packet.h @@ -0,0 +1,167 @@ +/* + +packet.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Mar 18 02:02:14 1995 ylo + +Interface for the packet protocol functions. + +*/ + +/* RCSID("$Id: packet.h,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); */ + +#ifndef PACKET_H +#define PACKET_H + +#include <gmp.h> +#include "randoms.h" + +/* Sets the socket used for communication. Disables encryption until + packet_set_encryption_key is called. It is permissible that fd_in + and fd_out are the same descriptor; in that case it is assumed to + be a socket. */ +void packet_set_connection(int fd_in, int fd_out, RandomState *state); + +/* Puts the connection file descriptors into non-blocking mode. */ +void packet_set_nonblocking(void); + +/* Returns the file descriptor used for input. */ +int packet_get_connection_in(void); + +/* Returns the file descriptor used for output. */ +int packet_get_connection_out(void); + +/* Closes the connection (both descriptors) and clears and frees + internal data structures. */ +void packet_close(void); + +/* Causes any further packets to be encrypted using the given key. The same + key is used for both sending and reception. However, both directions + are encrypted independently of each other. Cipher types are + defined in ssh.h. */ +void packet_set_encryption_key(const unsigned char *key, unsigned int keylen, + int cipher_type, int is_client); + +/* Sets remote side protocol flags for the current connection. This can + be called at any time. */ +void packet_set_protocol_flags(unsigned int flags); + +/* Returns the remote protocol flags set earlier by the above function. */ +unsigned int packet_get_protocol_flags(void); + +/* Enables compression in both directions starting from the next packet. */ +void packet_start_compression(int level); + +/* Informs that the current session is interactive. Sets IP flags for optimal + performance in interactive use. */ +void packet_set_interactive(int interactive, int keepalives); + +/* Returns true if the current connection is interactive. */ +int packet_is_interactive(void); + +/* Starts constructing a packet to send. */ +void packet_start(int type); + +/* Appends a character to the packet data. */ +void packet_put_char(int ch); + +/* Appends an integer to the packet data. */ +void packet_put_int(unsigned int value); + +/* Appends an arbitrary precision integer to packet data. */ +void packet_put_mp_int(MP_INT *value); + +/* Appends a string to packet data. */ +void packet_put_string(const char *buf, unsigned int len); + +/* Finalizes and sends the packet. If the encryption key has been set, + encrypts the packet before sending. */ +void packet_send(void); + +/* Waits until a packet has been received, and returns its type. */ +int packet_read(int *payload_len_ptr); + +/* Waits until a packet has been received, verifies that its type matches + that given, and gives a fatal error and exits if there is a mismatch. */ +void packet_read_expect(int *payload_len_ptr, int type); + +/* Checks if a full packet is available in the data received so far via + packet_process_incoming. If so, reads the packet; otherwise returns + SSH_MSG_NONE. This does not wait for data from the connection. + + SSH_MSG_DISCONNECT is handled specially here. Also, + SSH_MSG_IGNORE messages are skipped by this function and are never returned + to higher levels. */ +int packet_read_poll(int *packet_len_ptr); + +/* Buffers the given amount of input characters. This is intended to be + used together with packet_read_poll. */ +void packet_process_incoming(const char *buf, unsigned int len); + +/* Returns a character (0-255) from the packet data. */ +unsigned int packet_get_char(void); + +/* Returns an integer from the packet data. */ +unsigned int packet_get_int(void); + +/* Returns an arbitrary precision integer from the packet data. The integer + must have been initialized before this call. */ +void packet_get_mp_int(MP_INT *value, int *length_ptr); + +/* Returns a string from the packet data. The string is allocated using + xmalloc; it is the responsibility of the calling program to free it when + no longer needed. The length_ptr argument may be NULL, or point to an + integer into which the length of the string is stored. */ +char *packet_get_string(unsigned int *length_ptr); + +/* Logs the error in syslog using LOG_INFO, constructs and sends a disconnect + packet, closes the connection, and exits. This function never returns. + The error message should not contain a newline. The total length of the + message must not exceed 1024 bytes. */ +void packet_disconnect(const char *fmt, ...); + +/* Sends a diagnostic message to the other side. This message + can be sent at any time (but not while constructing another message). + The message is printed immediately, but only if the client is being + executed in verbose mode. These messages are primarily intended to + ease debugging authentication problems. The total length of the message + must not exceed 1024 bytes. This will automatically call + packet_write_wait. If the remote side protocol flags do not indicate + that it supports SSH_MSG_DEBUG, this will do nothing. */ +void packet_send_debug(const char *fmt, ...); + +/* Checks if there is any buffered output, and tries to write some of the + output. */ +void packet_write_poll(void); + +/* Waits until all pending output data has been written. */ +void packet_write_wait(void); + +/* Returns true if there is buffered data to write to the connection. */ +int packet_have_data_to_write(void); + +/* Returns true if there is not too much data to write to the connection. */ +int packet_not_very_much_data_to_write(void); + +/* Stores tty modes from the fd into current packet. */ +void tty_make_modes(int fd); + +/* Parses tty modes for the fd from the current packet. */ +void tty_parse_modes(int fd, int *n_bytes_ptr); + +#define packet_integrity_check(payload_len, expected_len, type) \ +do { \ + int _p = (payload_len), _e = (expected_len); \ + if (_p != _e) { \ + log("Packet integrity error (%d != %d) at %s:%d", \ + _p, _e, __FILE__, __LINE__); \ + packet_disconnect("Packet integrity error. (%d)", (type)); \ + } \ +} while (0) + +#endif /* PACKET_H */ diff --git a/usr.bin/ssh/pty.c b/usr.bin/ssh/pty.c new file mode 100644 index 00000000000..189c570bcbf --- /dev/null +++ b/usr.bin/ssh/pty.c @@ -0,0 +1,313 @@ +/* + +pty.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Fri Mar 17 04:37:25 1995 ylo + +Allocating a pseudo-terminal, and making it the controlling tty. + +*/ + +#include "includes.h" +RCSID("$Id: pty.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#include "pty.h" +#include "ssh.h" + +/* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */ +#if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY) +#undef HAVE_DEV_PTMX +#endif + +#ifdef HAVE_DEV_PTMX +#include <sys/stream.h> +#include <stropts.h> +#include <sys/conf.h> +#endif /* HAVE_DEV_PTMX */ + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +/* Allocates and opens a pty. Returns 0 if no pty could be allocated, + or nonzero if a pty was successfully allocated. On success, open file + descriptors for the pty and tty sides and the name of the tty side are + returned (the buffer must be able to hold at least 64 characters). */ + +int pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) +{ +#ifdef HAVE_OPENPTY + + /* openpty(3) exists in OSF/1 and some other os'es */ + + int i; + + i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL); + + if (i < 0) + { + error("openpty: %.100s", strerror(errno)); + return 0; + } + + return 1; + +#else /* HAVE_OPENPTY */ +#ifdef HAVE__GETPTY + + /* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more + pty's automagically when needed */ + + char *slave; + + slave = _getpty(ptyfd, O_RDWR, 0622, 0); + if (slave == NULL) + { + error("_getpty: %.100s", strerror(errno)); + return 0; + } + strcpy(namebuf, slave); + /* Open the slave side. */ + *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); + if (*ttyfd < 0) + { + error("%.200s: %.100s", namebuf, strerror(errno)); + close(*ptyfd); + return 0; + } + return 1; + +#else /* HAVE__GETPTY */ +#ifdef HAVE_DEV_PTMX + /* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 also has + bsd-style ptys, but they simply do not work.) */ + + int ptm; + char *pts; + + ptm = open("/dev/ptmx", O_RDWR|O_NOCTTY); + if (ptm < 0) + { + error("/dev/ptmx: %.100s", strerror(errno)); + return 0; + } + if (grantpt(ptm) < 0) + { + error("grantpt: %.100s", strerror(errno)); + return 0; + } + if (unlockpt(ptm) < 0) + { + error("unlockpt: %.100s", strerror(errno)); + return 0; + } + pts = ptsname(ptm); + if (pts == NULL) + error("Slave pty side name could not be obtained."); + strcpy(namebuf, pts); + *ptyfd = ptm; + + /* Open the slave side. */ + *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); + if (*ttyfd < 0) + { + error("%.100s: %.100s", namebuf, strerror(errno)); + close(*ptyfd); + return 0; + } + /* Push the appropriate streams modules, as described in Solaris pts(7). */ + if (ioctl(*ttyfd, I_PUSH, "ptem") < 0) + error("ioctl I_PUSH ptem: %.100s", strerror(errno)); + if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0) + error("ioctl I_PUSH ldterm: %.100s", strerror(errno)); + if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0) + error("ioctl I_PUSH ttcompat: %.100s", strerror(errno)); + return 1; + +#else /* HAVE_DEV_PTMX */ +#ifdef HAVE_DEV_PTS_AND_PTC + + /* AIX-style pty code. */ + + const char *name; + + *ptyfd = open("/dev/ptc", O_RDWR|O_NOCTTY); + if (*ptyfd < 0) + { + error("Could not open /dev/ptc: %.100s", strerror(errno)); + return 0; + } + name = ttyname(*ptyfd); + if (!name) + fatal("Open of /dev/ptc returns device for which ttyname fails."); + strcpy(namebuf, name); + *ttyfd = open(name, O_RDWR|O_NOCTTY); + if (*ttyfd < 0) + { + error("Could not open pty slave side %.100s: %.100s", + name, strerror(errno)); + close(*ptyfd); + return 0; + } + return 1; + +#else /* HAVE_DEV_PTS_AND_PTC */ +#ifdef CRAY + char buf[64]; + int i; + + for (i = 0; i < 128; i++) + { + sprintf(buf, "/dev/pty/%03d", i); + *ptyfd = open(buf, O_RDWR|O_NOCTTY); + if (*ptyfd < 0) + continue; + sprintf(namebuf, "/dev/ttyp%03d", i); + /* Open the slave side. */ + *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); + if (*ttyfd < 0) + { + error("%.100s: %.100s", namebuf, strerror(errno)); + close(*ptyfd); + return 0; + } + return 1; + } + return 0; + +#else /* CRAY */ + + /* BSD-style pty code. */ + + char buf[64]; + int i; + const char *ptymajors = + "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const char *ptyminors = "0123456789abcdef"; + int num_minors = strlen(ptyminors); + int num_ptys = strlen(ptymajors) * num_minors; + + for (i = 0; i < num_ptys; i++) + { + sprintf(buf, "/dev/pty%c%c", ptymajors[i / num_minors], + ptyminors[i % num_minors]); + *ptyfd = open(buf, O_RDWR|O_NOCTTY); + if (*ptyfd < 0) + continue; + sprintf(namebuf, "/dev/tty%c%c", ptymajors[i / num_minors], + ptyminors[i % num_minors]); + + /* Open the slave side. */ + *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); + if (*ttyfd < 0) + { + error("%.100s: %.100s", namebuf, strerror(errno)); + close(*ptyfd); + return 0; + } + return 1; + } + return 0; +#endif /* CRAY */ +#endif /* HAVE_DEV_PTS_AND_PTC */ +#endif /* HAVE_DEV_PTMX */ +#endif /* HAVE__GETPTY */ +#endif /* HAVE_OPENPTY */ +} + +/* Releases the tty. Its ownership is returned to root, and permissions to + 0666. */ + +void pty_release(const char *ttyname) +{ + if (chown(ttyname, (uid_t)0, (gid_t)0) < 0) + debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno)); + if (chmod(ttyname, (mode_t)0666) < 0) + debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno)); +} + +/* Makes the tty the processes controlling tty and sets it to sane modes. */ + +void pty_make_controlling_tty(int *ttyfd, const char *ttyname) +{ + int fd; + + /* First disconnect from the old controlling tty. */ +#ifdef TIOCNOTTY + fd = open("/dev/tty", O_RDWR|O_NOCTTY); + if (fd >= 0) + { + (void)ioctl(fd, TIOCNOTTY, NULL); + close(fd); + } +#endif /* TIOCNOTTY */ +#ifdef HAVE_SETSID +#ifdef ultrix + setpgrp(0, 0); +#else /* ultrix */ + if (setsid() < 0) + error("setsid: %.100s", strerror(errno)); +#endif /* ultrix */ +#endif /* HAVE_SETSID */ + + /* Verify that we are successfully disconnected from the controlling tty. */ + fd = open("/dev/tty", O_RDWR|O_NOCTTY); + if (fd >= 0) + { + error("Failed to disconnect from controlling tty."); + close(fd); + } + + /* Make it our controlling tty. */ +#ifdef TIOCSCTTY + debug("Setting controlling tty using TIOCSCTTY."); + /* We ignore errors from this, because HPSUX defines TIOCSCTTY, but returns + EINVAL with these arguments, and there is absolutely no documentation. */ + ioctl(*ttyfd, TIOCSCTTY, NULL); +#endif /* TIOCSCTTY */ + fd = open(ttyname, O_RDWR); + if (fd < 0) + error("%.100s: %.100s", ttyname, strerror(errno)); + else + close(fd); + + /* Verify that we now have a controlling tty. */ + fd = open("/dev/tty", O_WRONLY); + if (fd < 0) + error("open /dev/tty failed - could not set controlling tty: %.100s", + strerror(errno)); + else + { + close(fd); +#ifdef HAVE_VHANGUP + signal(SIGHUP, SIG_IGN); + vhangup(); + signal(SIGHUP, SIG_DFL); + fd = open(ttyname, O_RDWR); + if (fd == -1) + error("pty_make_controlling_tty: reopening controlling tty after vhangup failed for %.100s", + ttyname); + close(*ttyfd); + *ttyfd = fd; +#endif /* HAVE_VHANGUP */ + } +} + +/* Changes the window size associated with the pty. */ + +void pty_change_window_size(int ptyfd, int row, int col, + int xpixel, int ypixel) +{ + struct winsize w; + w.ws_row = row; + w.ws_col = col; + w.ws_xpixel = xpixel; + w.ws_ypixel = ypixel; + (void)ioctl(ptyfd, TIOCSWINSZ, &w); +} + diff --git a/usr.bin/ssh/pty.h b/usr.bin/ssh/pty.h new file mode 100644 index 00000000000..c88ae92718c --- /dev/null +++ b/usr.bin/ssh/pty.h @@ -0,0 +1,40 @@ +/* + +pty.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Fri Mar 17 05:03:28 1995 ylo + +Functions for allocating a pseudo-terminal and making it the controlling +tty. + +*/ + +/* RCSID("$Id: pty.h,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); */ + +#ifndef PTY_H +#define PTY_H + +/* Allocates and opens a pty. Returns 0 if no pty could be allocated, + or nonzero if a pty was successfully allocated. On success, open file + descriptors for the pty and tty sides and the name of the tty side are + returned (the buffer must be able to hold at least 64 characters). */ +int pty_allocate(int *ptyfd, int *ttyfd, char *ttyname); + +/* Releases the tty. Its ownership is returned to root, and permissions to + 0666. */ +void pty_release(const char *ttyname); + +/* Makes the tty the processes controlling tty and sets it to sane modes. + This may need to reopen the tty to get rid of possible eavesdroppers. */ +void pty_make_controlling_tty(int *ttyfd, const char *ttyname); + +/* Changes the window size associated with the pty. */ +void pty_change_window_size(int ptyfd, int row, int col, + int xpixel, int ypixel); + +#endif /* PTY_H */ diff --git a/usr.bin/ssh/radix.c b/usr.bin/ssh/radix.c new file mode 100644 index 00000000000..ca1b82a72db --- /dev/null +++ b/usr.bin/ssh/radix.c @@ -0,0 +1,259 @@ +/* + radix.c + + base-64 encoding pinched from lynx2-7-2, who pinched it from rpem. + Originally written by Mark Riordan 12 August 1990 and 17 Feb 1991 + and placed in the public domain. + + dugsong@UMICH.EDU +*/ + +#include "includes.h" + +#ifdef AFS +#include <krb.h> +#include <kafs.h> + +char six2pr[64] = { + 'A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l','m', + 'n','o','p','q','r','s','t','u','v','w','x','y','z', + '0','1','2','3','4','5','6','7','8','9','+','/' +}; + +unsigned char pr2six[256]; + +int uuencode(unsigned char *bufin, unsigned int nbytes, char *bufcoded) +{ + /* ENC is the basic 1 character encoding function to make a char printing */ +#define ENC(c) six2pr[c] + + register char *outptr = bufcoded; + unsigned int i; + + for (i=0; i<nbytes; i += 3) { + *(outptr++) = ENC(*bufin >> 2); /* c1 */ + *(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /*c2*/ + *(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));/*c3*/ + *(outptr++) = ENC(bufin[2] & 077); /* c4 */ + bufin += 3; + } + if (i == nbytes+1) { + outptr[-1] = '='; + } else if (i == nbytes+2) { + outptr[-1] = '='; + outptr[-2] = '='; + } + *outptr = '\0'; + return(outptr - bufcoded); +} + +int uudecode(const char *bufcoded, unsigned char *bufplain, int outbufsize) +{ + /* single character decode */ +#define DEC(c) pr2six[c] +#define MAXVAL 63 + + static int first = 1; + int nbytesdecoded, j; + const char *bufin = bufcoded; + register unsigned char *bufout = bufplain; + register int nprbytes; + + /* If this is the first call, initialize the mapping table. */ + if (first) { + first = 0; + for(j=0; j<256; j++) pr2six[j] = MAXVAL+1; + for(j=0; j<64; j++) pr2six[(unsigned char)six2pr[j]] = (unsigned char)j; + } + + /* Strip leading whitespace. */ + while (*bufcoded==' ' || *bufcoded == '\t') bufcoded++; + + /* Figure out how many characters are in the input buffer. + If this would decode into more bytes than would fit into + the output buffer, adjust the number of input bytes downwards. */ + bufin = bufcoded; + while (pr2six[(unsigned char)*(bufin++)] <= MAXVAL); + nprbytes = bufin - bufcoded - 1; + nbytesdecoded = ((nprbytes+3)/4) * 3; + if (nbytesdecoded > outbufsize) + nprbytes = (outbufsize*4)/3; + + bufin = bufcoded; + + while (nprbytes > 0) { + *(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4); + *(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2); + *(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3])); + bufin += 4; + nprbytes -= 4; + } + if (nprbytes & 03) { + if (pr2six[bufin[-2]] > MAXVAL) + nbytesdecoded -= 2; + else + nbytesdecoded -= 1; + } + return(nbytesdecoded); +} + +typedef unsigned char my_u_char; +typedef unsigned int my_u_int32_t; +typedef unsigned short my_u_short; + +/* Nasty macros from BIND-4.9.2 */ + +#define GETSHORT(s, cp) { \ + register my_u_char *t_cp = (my_u_char*)(cp); \ + (s) = (((my_u_short)t_cp[0]) << 8) \ + | (((my_u_short)t_cp[1])) \ + ; \ + (cp) += 2; \ +} + +#define GETLONG(l, cp) { \ + register my_u_char *t_cp = (my_u_char*)(cp); \ + (l) = (((my_u_int32_t)t_cp[0]) << 24) \ + | (((my_u_int32_t)t_cp[1]) << 16) \ + | (((my_u_int32_t)t_cp[2]) << 8) \ + | (((my_u_int32_t)t_cp[3])) \ + ; \ + (cp) += 4; \ +} + +#define PUTSHORT(s, cp) { \ + register my_u_short t_s = (my_u_short)(s); \ + register my_u_char *t_cp = (my_u_char*)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += 2; \ +} + +#define PUTLONG(l, cp) { \ + register my_u_int32_t t_l = (my_u_int32_t)(l); \ + register my_u_char *t_cp = (my_u_char*)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += 4; \ +} + +#define GETSTRING(s, p, p_l) { \ + register char* p_targ = (p) + p_l; \ + register char* s_c = (s); \ + register char* p_c = (p); \ + while (*p_c && (p_c < p_targ)) { \ + *s_c++ = *p_c++; \ + } \ + if (p_c == p_targ) { \ + return 1; \ + } \ + *s_c = *p_c++; \ + (p_l) = (p_l) - (p_c - (p)); \ + (p) = p_c; \ +} + + +int creds_to_radix(CREDENTIALS *creds, unsigned char *buf) +{ + char *p, *s; + int len; + char temp[2048]; + + p = temp; + *p++ = 1; /* version */ + s = creds->service; while (*s) *p++ = *s++; *p++ = *s; + s = creds->instance; while (*s) *p++ = *s++; *p++ = *s; + s = creds->realm; while (*s) *p++ = *s++; *p++ = *s; + + s = creds->pname; while (*s) *p++ = *s++; *p++ = *s; + s = creds->pinst; while (*s) *p++ = *s++; *p++ = *s; + /* Null string to repeat the realm. */ + *p++ = '\0'; + + PUTLONG(creds->issue_date,p); + { + unsigned long endTime ; + endTime = (unsigned long)krb_life_to_time(creds->issue_date, + creds->lifetime); + PUTLONG(endTime,p); + } + + memcpy(p,&creds->session, sizeof(creds->session)); + p += sizeof(creds->session); + + PUTSHORT(creds->kvno,p); + PUTLONG(creds->ticket_st.length,p); + + memcpy(p,creds->ticket_st.dat, creds->ticket_st.length); + p += creds->ticket_st.length; + len = p - temp; + + return(uuencode(temp, len, buf)); +} + +int radix_to_creds(const char *buf, CREDENTIALS *creds) +{ + + char *p; + int len, tl; + char version; + char temp[2048]; + + if (!(len = uudecode(buf, temp, sizeof(temp)))) + return 0; + + p = temp; + + /* check version and length! */ + if (len < 1) return 0; + version = *p; p++; len--; + + GETSTRING(creds->service, p, len); + GETSTRING(creds->instance, p, len); + GETSTRING(creds->realm, p, len); + + GETSTRING(creds->pname, p, len); + GETSTRING(creds->pinst, p, len); + /* Ignore possibly different realm. */ + while (*p && len) p++, len--; + if (len == 0) return 0; + p++, len--; + + /* Enough space for remaining fixed-length parts? */ + if (len < (4 + 4 + sizeof(creds->session) + 2 + 4)) + return 0; + + GETLONG(creds->issue_date,p); + len -= 4; + { + unsigned long endTime; + GETLONG(endTime,p); + len -= 4; + creds->lifetime = krb_time_to_life(creds->issue_date, endTime); + } + + memcpy(&creds->session, p, sizeof(creds->session)); + p += sizeof(creds->session); + len -= sizeof(creds->session); + + GETSHORT(creds->kvno,p); + len -= 2; + GETLONG(creds->ticket_st.length,p); + len -= 4; + + tl = creds->ticket_st.length; + if (tl < 0 || tl > len || tl > sizeof(creds->ticket_st.dat)) + return 0; + + memcpy(creds->ticket_st.dat, p, tl); + p += tl; + len -= tl; + + return 1; +} + +#endif /* AFS */ diff --git a/usr.bin/ssh/random.c b/usr.bin/ssh/random.c new file mode 100644 index 00000000000..1487764601b --- /dev/null +++ b/usr.bin/ssh/random.c @@ -0,0 +1,370 @@ +/* Note: file is included because gmp uses functions that use random in its + primality testing functions. //ylo */ + +/* + * Copyright (c) 1983 Regents of the University of California. + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)random.c 5.9 (Berkeley) 2/23/91"; +#endif /* LIBC_SCCS and not lint */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> + +/* + * random.c: + * + * An improved random number generation package. In addition to the standard + * rand()/srand() like interface, this package also has a special state info + * interface. The initstate() routine is called with a seed, an array of + * bytes, and a count of how many bytes are being passed in; this array is + * then initialized to contain information for random number generation with + * that much state information. Good sizes for the amount of state + * information are 32, 64, 128, and 256 bytes. The state can be switched by + * calling the setstate() routine with the same array as was initiallized + * with initstate(). By default, the package runs with 128 bytes of state + * information and generates far better random numbers than a linear + * congruential generator. If the amount of state information is less than + * 32 bytes, a simple linear congruential R.N.G. is used. + * + * Internally, the state information is treated as an array of longs; the + * zeroeth element of the array is the type of R.N.G. being used (small + * integer); the remainder of the array is the state information for the + * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of + * state information, which will allow a degree seven polynomial. (Note: + * the zeroeth word of state information also has some other information + * stored in it -- see setstate() for details). + * + * The random number generation technique is a linear feedback shift register + * approach, employing trinomials (since there are fewer terms to sum up that + * way). In this approach, the least significant bit of all the numbers in + * the state table will act as a linear feedback shift register, and will + * have period 2^deg - 1 (where deg is the degree of the polynomial being + * used, assuming that the polynomial is irreducible and primitive). The + * higher order bits will have longer periods, since their values are also + * influenced by pseudo-random carries out of the lower bits. The total + * period of the generator is approximately deg*(2**deg - 1); thus doubling + * the amount of state information has a vast influence on the period of the + * generator. Note: the deg*(2**deg - 1) is an approximation only good for + * large deg, when the period of the shift register is the dominant factor. + * With deg equal to seven, the period is actually much longer than the + * 7*(2**7 - 1) predicted by this formula. + */ + +/* + * For each of the currently supported random number generators, we have a + * break value on the amount of state information (you need at least this + * many bytes of state info to support this random number generator), a degree + * for the polynomial (actually a trinomial) that the R.N.G. is based on, and + * the separation between the two lower order coefficients of the trinomial. + */ +#define TYPE_0 0 /* linear congruential */ +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +#define TYPE_1 1 /* x**7 + x**3 + 1 */ +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +#define TYPE_2 2 /* x**15 + x + 1 */ +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +#define TYPE_3 3 /* x**31 + x**3 + 1 */ +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +#define TYPE_4 4 /* x**63 + x + 1 */ +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + +/* + * Array versions of the above information to make code run faster -- + * relies on fact that TYPE_i == i. + */ +#define MAX_TYPES 5 /* max number of types above */ + +static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static int seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; + +/* + * Initially, everything is set up as if from: + * + * initstate(1, &randtbl, 128); + * + * Note that this initialization takes advantage of the fact that srandom() + * advances the front and rear pointers 10*rand_deg times, and hence the + * rear pointer which starts at 0 will also end up at zero; thus the zeroeth + * element of the state information, which contains info about the current + * position of the rear pointer is just + * + * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3. + */ + +static long randtbl[DEG_3 + 1] = { + TYPE_3, + 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5, + 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, + 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, + 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, + 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b, + 0x27fb47b9, +}; + +/* + * fptr and rptr are two pointers into the state info, a front and a rear + * pointer. These two pointers are always rand_sep places aparts, as they + * cycle cyclically through the state information. (Yes, this does mean we + * could get away with just one pointer, but the code for random() is more + * efficient this way). The pointers are left positioned as they would be + * from the call + * + * initstate(1, randtbl, 128); + * + * (The position of the rear pointer, rptr, is really 0 (as explained above + * in the initialization of randtbl) because the state table pointer is set + * to point to randtbl[1] (as explained below). + */ +static long *fptr = &randtbl[SEP_3 + 1]; +static long *rptr = &randtbl[1]; + +/* + * The following things are the pointer to the state information table, the + * type of the current generator, the degree of the current polynomial being + * used, and the separation between the two pointers. Note that for efficiency + * of random(), we remember the first location of the state information, not + * the zeroeth. Hence it is valid to access state[-1], which is used to + * store the type of the R.N.G. Also, we remember the last location, since + * this is more efficient than indexing every time to find the address of + * the last element to see if the front and rear pointers have wrapped. + */ +static long *state = &randtbl[1]; +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; +static long *end_ptr = &randtbl[DEG_3 + 1]; + +long random(); + +/* + * srandom: + * + * Initialize the random number generator based on the given seed. If the + * type is the trivial no-state-information type, just remember the seed. + * Otherwise, initializes state[] based on the given "seed" via a linear + * congruential generator. Then, the pointers are set to known locations + * that are exactly rand_sep places apart. Lastly, it cycles the state + * information a given number of times to get rid of any initial dependencies + * introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + * for default usage relies on values produced by this routine. + */ +void +srandom(x) + u_int x; +{ + register int i, j; + + if (rand_type == TYPE_0) + state[0] = x; + else { + j = 1; + state[0] = x; + for (i = 1; i < rand_deg; i++) + state[i] = 1103515245 * state[i - 1] + 12345; + fptr = &state[rand_sep]; + rptr = &state[0]; + for (i = 0; i < 10 * rand_deg; i++) + (void)random(); + } +} + +/* + * initstate: + * + * Initialize the state information in the given array of n bytes for future + * random number generation. Based on the number of bytes we are given, and + * the break values for the different R.N.G.'s, we choose the best (largest) + * one we can and set things up for it. srandom() is then called to + * initialize the state information. + * + * Note that on return from srandom(), we set state[-1] to be the type + * multiplexed with the current value of the rear pointer; this is so + * successive calls to initstate() won't lose this information and will be + * able to restart with setstate(). + * + * Note: the first thing we do is save the current state, if any, just like + * setstate() so that it doesn't matter when initstate is called. + * + * Returns a pointer to the old state. + */ +char * +initstate(seed, arg_state, n) + u_int seed; /* seed for R.N.G. */ + char *arg_state; /* pointer to state array */ + int n; /* # bytes of state info */ +{ + register char *ostate = (char *)(&state[-1]); + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = MAX_TYPES * (rptr - state) + rand_type; + if (n < BREAK_0) { + (void)fprintf(stderr, + "random: not enough state (%d bytes); ignored.\n", n); + return(0); + } + if (n < BREAK_1) { + rand_type = TYPE_0; + rand_deg = DEG_0; + rand_sep = SEP_0; + } else if (n < BREAK_2) { + rand_type = TYPE_1; + rand_deg = DEG_1; + rand_sep = SEP_1; + } else if (n < BREAK_3) { + rand_type = TYPE_2; + rand_deg = DEG_2; + rand_sep = SEP_2; + } else if (n < BREAK_4) { + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + } else { + rand_type = TYPE_4; + rand_deg = DEG_4; + rand_sep = SEP_4; + } + state = &(((long *)arg_state)[1]); /* first location */ + end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */ + srandom(seed); + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = MAX_TYPES*(rptr - state) + rand_type; + return(ostate); +} + +/* + * setstate: + * + * Restore the state from the given state array. + * + * Note: it is important that we also remember the locations of the pointers + * in the current state information, and restore the locations of the pointers + * from the old state information. This is done by multiplexing the pointer + * location into the zeroeth word of the state information. + * + * Note that due to the order in which things are done, it is OK to call + * setstate() with the same state as the current state. + * + * Returns a pointer to the old state information. + */ +char * +setstate(arg_state) + char *arg_state; +{ + register long *new_state = (long *)arg_state; + register int type = new_state[0] % MAX_TYPES; + register int rear = new_state[0] / MAX_TYPES; + char *ostate = (char *)(&state[-1]); + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = MAX_TYPES * (rptr - state) + rand_type; + switch(type) { + case TYPE_0: + case TYPE_1: + case TYPE_2: + case TYPE_3: + case TYPE_4: + rand_type = type; + rand_deg = degrees[type]; + rand_sep = seps[type]; + break; + default: + (void)fprintf(stderr, + "random: state info corrupted; not changed.\n"); + } + state = &new_state[1]; + if (rand_type != TYPE_0) { + rptr = &state[rear]; + fptr = &state[(rear + rand_sep) % rand_deg]; + } + end_ptr = &state[rand_deg]; /* set end_ptr too */ + return(ostate); +} + +/* + * random: + * + * If we are using the trivial TYPE_0 R.N.G., just do the old linear + * congruential bit. Otherwise, we do our fancy trinomial stuff, which is + * the same in all the other cases due to all the global variables that have + * been set up. The basic operation is to add the number at the rear pointer + * into the one at the front pointer. Then both pointers are advanced to + * the next location cyclically in the table. The value returned is the sum + * generated, reduced to 31 bits by throwing away the "least random" low bit. + * + * Note: the code takes advantage of the fact that both the front and + * rear pointers can't wrap on the same call by not testing the rear + * pointer if the front one has wrapped. + * + * Returns a 31-bit random number. + */ +long +random() +{ + long i; + + if (rand_type == TYPE_0) + i = state[0] = (state[0] * 1103515245 + 12345) & 0x7fffffff; + else { + *fptr += *rptr; + i = (*fptr >> 1) & 0x7fffffff; /* chucking least random bit */ + if (++fptr >= end_ptr) { + fptr = state; + ++rptr; + } else if (++rptr >= end_ptr) + rptr = state; + } + return(i); +} + diff --git a/usr.bin/ssh/randoms.c b/usr.bin/ssh/randoms.c new file mode 100644 index 00000000000..249e106293f --- /dev/null +++ b/usr.bin/ssh/randoms.c @@ -0,0 +1,365 @@ +/* + +random.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Mar 4 14:55:57 1995 ylo + +Cryptographically strong random number generation. + +*/ + +#include "includes.h" +RCSID("$Id: randoms.c,v 1.1 1999/09/26 20:53:36 deraadt Exp $"); + +#include "randoms.h" +#include "getput.h" +#include "ssh_md5.h" + +#ifdef HAVE_GETRUSAGE +#include <sys/resource.h> +#ifdef HAVE_RUSAGE_H +#include <sys/rusage.h> +#endif /* HAVE_RUSAGE_H */ +#endif /* HAVE_GETRUSAGE */ + +#ifdef HAVE_TIMES +#include <sys/times.h> +#endif /* HAVE_TIMES */ + +/* Initializes the random number generator, loads any random information + from the given file, and acquires as much environmental noise as it + can to initialize the random number generator. More noise can be + acquired later by calling random_add_noise + random_stir, or by + calling random_get_environmental_noise again later when the environmental + situation has changed. */ + +void random_initialize(RandomState *state, const char *filename) +{ + char buf[8192]; + int f, bytes; + + state->add_position = 0; + state->next_available_byte = sizeof(state->stir_key); + + /* This isn't strictly necessary, but will keep programs like 3rd degree or + purify silent. */ + memset(state, 0, sizeof(state)); + + /* Get noise from the file. */ + random_add_noise(state, filename, strlen(filename)); /* Use the path. */ + f = open(filename, O_RDONLY); + if (f >= 0) + { + state->state[0] += f; + bytes = read(f, buf, sizeof(buf)); + close(f); + if (bytes > 0) + random_add_noise(state, buf, bytes); + memset(buf, 0, sizeof(buf)); + } + else + { + /* Get all possible noise since we have no seed. */ + random_acquire_environmental_noise(state); + random_save(state, filename); + } + + /* Get easily available noise from the environment. */ + random_acquire_light_environmental_noise(state); +} + +void random_xor_noise(RandomState *state, unsigned int i, word32 value) +{ + value ^= GET_32BIT(state->state + 4 * i); + PUT_32BIT(state->state + 4 * i, value); +} + +/* Acquires as much environmental noise as it can. This is probably quite + sufficient on a unix machine, but might be grossly inadequate on a + single-user PC or a Macintosh. + + We test the elapsed real time after each command, and abort if we have + consumed over 30 seconds. */ + +void random_acquire_environmental_noise(RandomState *state) +{ + time_t start_time; + + /* Record the start time. */ + start_time = time(NULL); + + /* Run these first so that other statistics accumulate from these. We stop + collecting more noise when we have spent 30 seconds real time; on a large + system a single executed command is probably enough, whereas on small + systems we must use all possible noise sources. */ + random_get_noise_from_command(state, "ps laxww 2>/dev/null"); + if (time(NULL) - start_time < 30) + random_get_noise_from_command(state, "ps -al 2>/dev/null"); + if (time(NULL) - start_time < 30) + random_get_noise_from_command(state, "ls -alni /tmp/. 2>/dev/null"); + if (time(NULL) - start_time < 30) + random_get_noise_from_command(state, "w 2>/dev/null"); + if (time(NULL) - start_time < 30) + random_get_noise_from_command(state, "netstat -s 2>/dev/null"); + if (time(NULL) - start_time < 30) + random_get_noise_from_command(state, "netstat -an 2>/dev/null"); + if (time(NULL) - start_time < 30) + random_get_noise_from_command(state, "netstat -in 2>/dev/null"); + + /* Get other easily available noise. */ + random_acquire_light_environmental_noise(state); +} + +/* Acquires easily available environmental noise. */ + +void random_acquire_light_environmental_noise(RandomState *state) +{ + int f; + char buf[32]; + int len; + + /* If /dev/random is available, read some data from there in non-blocking + mode and mix it into the pool. */ + f = open("/dev/random", O_RDONLY); + if (f >= 0) + { + /* Set the descriptor into non-blocking mode. */ +#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) + fcntl(f, F_SETFL, O_NONBLOCK); +#else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + fcntl(f, F_SETFL, O_NDELAY); +#endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + len = read(f, buf, sizeof(buf)); + close(f); + if (len > 0) + random_add_noise(state, buf, len); + } + + /* Get miscellaneous noise from various system parameters and statistics. */ + random_xor_noise(state, + (unsigned int)(state->state[0] + 256*state->state[1]) % + (RANDOM_STATE_BYTES / 4), + (word32)time(NULL)); + +#ifdef HAVE_GETTIMEOFDAY + { + struct timeval tv; + gettimeofday(&tv, NULL); + random_xor_noise(state, 0, (word32)tv.tv_usec); + random_xor_noise(state, 1, (word32)tv.tv_sec); +#ifdef HAVE_CLOCK + random_xor_noise(state, 3, (word32)clock()); +#endif /* HAVE_CLOCK */ + } +#endif /* HAVE_GETTIMEOFDAY */ +#ifdef HAVE_TIMES + { + struct tms tm; + random_xor_noise(state, 2, (word32)times(&tm)); + random_xor_noise(state, 4, (word32)(tm.tms_utime ^ (tm.tms_stime << 8) ^ + (tm.tms_cutime << 16) ^ + (tm.tms_cstime << 24))); + } +#endif /* HAVE_TIMES */ +#ifdef HAVE_GETRUSAGE + { + struct rusage ru, cru; + getrusage(RUSAGE_SELF, &ru); + getrusage(RUSAGE_CHILDREN, &cru); + random_xor_noise(state, 0, (word32)(ru.ru_utime.tv_usec + + cru.ru_utime.tv_usec)); + random_xor_noise(state, 2, (word32)(ru.ru_stime.tv_usec + + cru.ru_stime.tv_usec)); + random_xor_noise(state, 5, (word32)(ru.ru_maxrss + cru.ru_maxrss)); + random_xor_noise(state, 6, (word32)(ru.ru_ixrss + cru.ru_ixrss)); + random_xor_noise(state, 7, (word32)(ru.ru_idrss + cru.ru_idrss)); + random_xor_noise(state, 8, (word32)(ru.ru_minflt + cru.ru_minflt)); + random_xor_noise(state, 9, (word32)(ru.ru_majflt + cru.ru_majflt)); + random_xor_noise(state, 10, (word32)(ru.ru_nswap + cru.ru_nswap)); + random_xor_noise(state, 11, (word32)(ru.ru_inblock + cru.ru_inblock)); + random_xor_noise(state, 12, (word32)(ru.ru_oublock + cru.ru_oublock)); + random_xor_noise(state, 13, (word32)((ru.ru_msgsnd ^ ru.ru_msgrcv ^ + ru.ru_nsignals) + + (cru.ru_msgsnd ^ cru.ru_msgrcv ^ + cru.ru_nsignals))); + random_xor_noise(state, 14, (word32)(ru.ru_nvcsw + cru.ru_nvcsw)); + random_xor_noise(state, 15, (word32)(ru.ru_nivcsw + cru.ru_nivcsw)); + } +#endif /* HAVE_GETRUSAGE */ + random_xor_noise(state, 11, (word32)getpid()); + random_xor_noise(state, 12, (word32)getppid()); + random_xor_noise(state, 10, (word32)getuid()); + random_xor_noise(state, 10, (word32)(getgid() << 16)); +#ifdef _POSIX_CHILD_MAX + random_xor_noise(state, 13, (word32)(_POSIX_CHILD_MAX << 16)); +#endif /* _POSIX_CHILD_MAX */ +#ifdef CLK_TCK + random_xor_noise(state, 14, (word32)(CLK_TCK << 16)); +#endif /* CLK_TCK */ + + random_stir(state); +} + +/* Executes the given command, and processes its output as noise. */ + +void random_get_noise_from_command(RandomState *state, const char *cmd) +{ +#ifdef HAVE_POPEN + char line[1000]; + FILE *f; + + f = popen(cmd, "r"); + if (!f) + return; + while (fgets(line, sizeof(line), f)) + random_add_noise(state, line, strlen(line)); + pclose(f); + memset(line, 0, sizeof(line)); +#endif /* HAVE_POPEN */ +} + +/* Adds the contents of the buffer as noise. */ + +void random_add_noise(RandomState *state, const void *buf, unsigned int bytes) +{ + unsigned int pos = state->add_position; + const char *input = buf; + while (bytes > 0) + { + if (pos >= RANDOM_STATE_BYTES) + { + pos = 0; + random_stir(state); + } + state->state[pos] ^= *input; + input++; + bytes--; + pos++; + } + state->add_position = pos; +} + +/* Stirs the random pool to consume any newly acquired noise or to get more + random numbers. + + This works by encrypting the data in the buffer in CFB mode with MD5 as + the cipher. */ + +void random_stir(RandomState *state) +{ + uint32 iv[4]; + unsigned int i; + + /* Start IV from last block of random pool. */ + iv[0] = GET_32BIT(state->state); + iv[1] = GET_32BIT(state->state + 4); + iv[2] = GET_32BIT(state->state + 8); + iv[3] = GET_32BIT(state->state + 12); + + /* First CFB pass. */ + for (i = 0; i < RANDOM_STATE_BYTES; i += 16) + { + MD5Transform(iv, state->stir_key); + iv[0] ^= GET_32BIT(state->state + i); + PUT_32BIT(state->state + i, iv[0]); + iv[1] ^= GET_32BIT(state->state + i + 4); + PUT_32BIT(state->state + i + 4, iv[1]); + iv[2] ^= GET_32BIT(state->state + i + 8); + PUT_32BIT(state->state + i + 8, iv[2]); + iv[3] ^= GET_32BIT(state->state + i + 12); + PUT_32BIT(state->state + i + 12, iv[3]); + } + + /* Get new key. */ + memcpy(state->stir_key, state->state, sizeof(state->stir_key)); + + /* Second CFB pass. */ + for (i = 0; i < RANDOM_STATE_BYTES; i += 16) + { + MD5Transform(iv, state->stir_key); + iv[0] ^= GET_32BIT(state->state + i); + PUT_32BIT(state->state + i, iv[0]); + iv[1] ^= GET_32BIT(state->state + i + 4); + PUT_32BIT(state->state + i + 4, iv[1]); + iv[2] ^= GET_32BIT(state->state + i + 8); + PUT_32BIT(state->state + i + 8, iv[2]); + iv[3] ^= GET_32BIT(state->state + i + 12); + PUT_32BIT(state->state + i + 12, iv[3]); + } + + memset(iv, 0, sizeof(iv)); + + state->add_position = 0; + + /* Some data in the beginning is not returned to aboid giving an observer + complete knowledge of the contents of our random pool. */ + state->next_available_byte = sizeof(state->stir_key); +} + +/* Returns a random byte. Stirs the random pool if necessary. Acquires + new environmental noise approximately every five minutes. */ + +unsigned int random_get_byte(RandomState *state) +{ + if (state->next_available_byte >= RANDOM_STATE_BYTES) + { + /* Get some easily available noise. More importantly, this stirs + the pool. */ + random_acquire_light_environmental_noise(state); + } + assert(state->next_available_byte < RANDOM_STATE_BYTES); + return state->state[state->next_available_byte++]; +} + +/* Saves random data in a disk file. This is used to create a file that + can be used as a random seed on future runs. Only half of the random + data in our pool is written to the file to avoid an observer being + able to deduce the contents of our random pool from the file. */ + +void random_save(RandomState *state, const char *filename) +{ + char buf[RANDOM_STATE_BYTES / 2]; /* Save only half of its bits. */ + int i, f; + + /* Get some environmental noise to make it harder to predict previous + values from saved bits (besides, we have now probably consumed some + resources so the noise may be really useful). This also stirs + the pool. */ + random_acquire_light_environmental_noise(state); + + /* Get as many bytes as is half the size of the pool. I am assuming + this will get enough randomness for it to be very useful, but will + not reveal enough to make it possible to determine previous or future + returns by the generator. */ + for (i = 0; i < sizeof(buf); i++) + buf[i] = random_get_byte(state); + + /* Again get a little noise and stir it to mix the unrevealed half with + those bits that have been saved to a file. There should be enough + unrevealed bits (plus the new noise) to make it infeasible to try to + guess future values from the saved bits. */ + random_acquire_light_environmental_noise(state); + + /* Create and write the file. Failure to create the file is silently + ignored. */ + f = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600); + if (f >= 0) + { + /* Creation successful. Write data to the file. */ + write(f, buf, sizeof(buf)); + close(f); + } + memset(buf, 0, sizeof(buf)); +} + +/* Clears the random number generator data structures. */ + +void random_clear(RandomState *state) +{ + memset(state, 0, sizeof(*state)); +} diff --git a/usr.bin/ssh/randoms.h b/usr.bin/ssh/randoms.h new file mode 100644 index 00000000000..1e99f84a95b --- /dev/null +++ b/usr.bin/ssh/randoms.h @@ -0,0 +1,77 @@ +/* + +random.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Mar 4 14:49:05 1995 ylo + +Cryptographically strong random number generator. + +*/ + +/* RCSID("$Id: randoms.h,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); */ + +#ifndef RANDOM_H +#define RANDOM_H + +#include "ssh_md5.h" + +#define RANDOM_STATE_BITS 8192 +#define RANDOM_STATE_BYTES (RANDOM_STATE_BITS / 8) + +/* Structure for the random state. */ +typedef struct +{ + unsigned char state[RANDOM_STATE_BYTES];/* Pool of random data. */ + unsigned char stir_key[64]; /* Extra data for next stirring. */ + unsigned int next_available_byte; /* Index of next available byte. */ + unsigned int add_position; /* Index to add noise. */ +} RandomState; + +/* Initializes the random number generator, loads any random information + from the given file, and acquires as much environmental noise as it + can to initialize the random number generator. More noise can be + acquired later by calling random_add_noise + random_stir, or by + calling random_get_environmental_noise again later when the environmental + situation has changed. */ +void random_initialize(RandomState *state, const char *filename); + +/* Acquires as much environmental noise as it can. This is probably quite + sufficient on a unix machine, but might be grossly inadequate on a + single-user PC or a Macintosh. This call random_stir automatically. + This call may take many seconds to complete on a busy system. */ +void random_acquire_environmental_noise(RandomState *state); + +/* Acquires easily available noise from the environment. */ +void random_acquire_light_environmental_noise(RandomState *state); + +/* Executes the given command, and processes its output as noise. + random_stir should be called after this. */ +void random_get_noise_from_command(RandomState *state, const char *cmd); + +/* Adds the contents of the buffer as noise. random_stir should be called + after this. */ +void random_add_noise(RandomState *state, const void *buf, unsigned int bytes); + +/* Stirs the random pool to consume any newly acquired noise or to get more + random numbers. This should be called after adding noise to properly + mix the noise into the random pool. */ +void random_stir(RandomState *state); + +/* Returns a random byte. Stirs the random pool if necessary. Acquires + new environmental noise approximately every five minutes. */ +unsigned int random_get_byte(RandomState *state); + +/* Saves some random bits in the file so that it can be used as a source + of randomness for later runs. */ +void random_save(RandomState *state, const char *filename); + +/* Zeroes and frees any data structures associated with the random number + generator. */ +void random_clear(RandomState *state); + +#endif /* RANDOM_H */ diff --git a/usr.bin/ssh/rc4.c b/usr.bin/ssh/rc4.c new file mode 100644 index 00000000000..f85038daf68 --- /dev/null +++ b/usr.bin/ssh/rc4.c @@ -0,0 +1,72 @@ +/* + +Alleged RC4 (based on the Usenet posting in Spring-95) + +*/ + +#include "includes.h" +RCSID("$Id: rc4.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); + +#include "rc4.h" + +void rc4_init(RC4Context *ctx, const unsigned char *key, unsigned int key_len) +{ + unsigned int t, u; + unsigned int keyindex; + unsigned int stateindex; + unsigned char* state; + unsigned int counter; + + assert(key_len > 0); + + state = &ctx->state[0]; + ctx->x = 0; + ctx->y = 0; + for (counter = 0; counter < 256; counter++) + state[counter] = counter; + keyindex = 0; + stateindex = 0; + for (counter = 0; counter < 256; counter++) + { + t = state[counter]; + stateindex = (stateindex + key[keyindex] + t) & 0xff; + u = state[stateindex]; + state[stateindex] = t; + state[counter] = u; + if (++keyindex >= key_len) + keyindex = 0; + } +} + +inline unsigned int rc4_byte(RC4Context *ctx) +{ + unsigned int x; + unsigned int y; + unsigned int sx, sy; + unsigned char *state; + + state = ctx->state; + x = (ctx->x + 1) & 0xff; + sx = state[x]; + y = (sx + ctx->y) & 0xff; + sy = state[y]; + ctx->x = x; + ctx->y = y; + state[y] = sx; + state[x] = sy; + return state[(sx + sy) & 0xff]; +} + +void rc4_encrypt(RC4Context *ctx, unsigned char *dest, + const unsigned char *src, unsigned int len) +{ + unsigned int i; + for (i = 0; i < len; i++) + dest[i] = src[i] ^ rc4_byte(ctx); +} + +void rc4_decrypt(RC4Context *ctx, unsigned char *dest, + const unsigned char *src, unsigned int len) +{ + rc4_encrypt(ctx, dest, src, len); +} diff --git a/usr.bin/ssh/rc4.h b/usr.bin/ssh/rc4.h new file mode 100644 index 00000000000..780089f0cb7 --- /dev/null +++ b/usr.bin/ssh/rc4.h @@ -0,0 +1,34 @@ +/* + +Alleged RC4 (based on the Usenet posting in Spring-95) + +*/ + +/* RCSID("$Id: rc4.h,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); */ + +#ifndef RC4_H +#define RC4_H + +typedef struct +{ + unsigned int x; + unsigned int y; + unsigned char state[256]; +} RC4Context; + +/* Initializes the context and sets the key. */ +void rc4_init(RC4Context *ctx, const unsigned char *key, unsigned int keylen); + +/* Returns the next pseudo-random byte from the RC4 (pseudo-random generator) + stream. */ +unsigned int rc4_byte(RC4Context *ctx); + +/* Encrypts data. */ +void rc4_encrypt(RC4Context *ctx, unsigned char *dest, + const unsigned char *src, unsigned int len); + +/* Decrypts data. */ +void rc4_decrypt(RC4Context *ctx, unsigned char *dest, + const unsigned char *src, unsigned int len); + +#endif /* RC4_H */ diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c new file mode 100644 index 00000000000..48bad9714a7 --- /dev/null +++ b/usr.bin/ssh/readconf.c @@ -0,0 +1,670 @@ +/* + +readconf.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Apr 22 00:03:10 1995 ylo + +Functions for reading the configuration files. + +*/ + +#include "includes.h" +RCSID("$Id: readconf.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); + +#include "ssh.h" +#include "cipher.h" +#include "readconf.h" +#include "xmalloc.h" + +/* Format of the configuration file: + + # Configuration data is parsed as follows: + # 1. command line options + # 2. user-specific file + # 3. system-wide file + # Any configuration value is only changed the first time it is set. + # Thus, host-specific definitions should be at the beginning of the + # configuration file, and defaults at the end. + + # Host-specific declarations. These may override anything above. A single + # host may match multiple declarations; these are processed in the order + # that they are given in. + + Host *.ngs.fi ngs.fi + FallBackToRsh no + + Host fake.com + HostName another.host.name.real.org + User blaah + Port 34289 + ForwardX11 no + ForwardAgent no + + Host books.com + RemoteForward 9999 shadows.cs.hut.fi:9999 + Cipher 3des + + Host fascist.blob.com + Port 23123 + User tylonen + RhostsAuthentication no + PasswordAuthentication no + + Host puukko.hut.fi + User t35124p + ProxyCommand ssh-proxy %h %p + + Host *.fr + UseRsh yes + + Host *.su + Cipher none + PasswordAuthentication no + + # Defaults for various options + Host * + ForwardAgent no + ForwardX11 yes + RhostsAuthentication yes + PasswordAuthentication yes + RSAAuthentication yes + RhostsRSAAuthentication yes + FallBackToRsh no + UseRsh no + StrictHostKeyChecking yes + KeepAlives no + IdentityFile ~/.ssh/identity + Port 22 + Cipher idea + EscapeChar ~ + +*/ + +/* Keyword tokens. */ + +typedef enum +{ + oForwardAgent, oForwardX11, oRhostsAuthentication, + oPasswordAuthentication, oRSAAuthentication, oFallBackToRsh, oUseRsh, +#ifdef KRB4 + oKerberosAuthentication, +#endif /* KRB4 */ +#ifdef KERBEROS_TGT_PASSING + oKerberosTgtPassing, +#endif +#ifdef AFS + oAFSTokenPassing, +#endif + oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, + oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, + oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, + oBatchMode, oStrictHostKeyChecking, oCompression, oCompressionLevel, + oKeepAlives, oTISAuthentication +} OpCodes; + +/* Textual representations of the tokens. */ + +static struct +{ + const char *name; + OpCodes opcode; +} keywords[] = +{ + { "forwardagent", oForwardAgent }, + { "forwardx11", oForwardX11 }, + { "rhostsauthentication", oRhostsAuthentication }, + { "passwordauthentication", oPasswordAuthentication }, + { "rsaauthentication", oRSAAuthentication }, +#ifdef KRB4 + { "kerberosauthentication", oKerberosAuthentication }, +#endif /* KRB4 */ +#ifdef KERBEROS_TGT_PASSING + { "kerberostgtpassing", oKerberosTgtPassing }, +#endif +#ifdef AFS + { "afstokenpassing", oAFSTokenPassing }, +#endif + { "fallbacktorsh", oFallBackToRsh }, + { "usersh", oUseRsh }, + { "identityfile", oIdentityFile }, + { "hostname", oHostName }, + { "proxycommand", oProxyCommand }, + { "port", oPort }, + { "cipher", oCipher }, + { "remoteforward", oRemoteForward }, + { "localforward", oLocalForward }, + { "user", oUser }, + { "host", oHost }, + { "escapechar", oEscapeChar }, + { "rhostsrsaauthentication", oRhostsRSAAuthentication }, + { "globalknownhostsfile", oGlobalKnownHostsFile }, + { "userknownhostsfile", oUserKnownHostsFile }, + { "connectionattempts", oConnectionAttempts }, + { "batchmode", oBatchMode }, + { "stricthostkeychecking", oStrictHostKeyChecking }, + { "compression", oCompression }, + { "compressionlevel", oCompressionLevel }, + { "keepalive", oKeepAlives }, + { "tisauthentication", oTISAuthentication }, + { NULL, 0 } +}; + +/* Characters considered whitespace in strtok calls. */ +#define WHITESPACE " \t\r\n" + + +/* Adds a local TCP/IP port forward to options. Never returns if there + is an error. */ + +void add_local_forward(Options *options, int port, const char *host, + int host_port) +{ + Forward *fwd; + if (options->num_local_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) + fatal("Too many local forwards (max %d).", SSH_MAX_FORWARDS_PER_DIRECTION); + fwd = &options->local_forwards[options->num_local_forwards++]; + fwd->port = port; + fwd->host = xstrdup(host); + fwd->host_port = host_port; +} + +/* Adds a remote TCP/IP port forward to options. Never returns if there + is an error. */ + +void add_remote_forward(Options *options, int port, const char *host, + int host_port) +{ + Forward *fwd; + if (options->num_remote_forwards >= SSH_MAX_FORWARDS_PER_DIRECTION) + fatal("Too many remote forwards (max %d).", + SSH_MAX_FORWARDS_PER_DIRECTION); + fwd = &options->remote_forwards[options->num_remote_forwards++]; + fwd->port = port; + fwd->host = xstrdup(host); + fwd->host_port = host_port; +} + +/* Returns the number of the token pointed to by cp of length len. + Never returns if the token is not known. */ + +static OpCodes parse_token(const char *cp, const char *filename, int linenum) +{ + unsigned int i; + + for (i = 0; keywords[i].name; i++) + if (strcmp(cp, keywords[i].name) == 0) + return keywords[i].opcode; + + fatal("%.200s line %d: Bad configuration option.", + filename, linenum); + /*NOTREACHED*/ + return 0; +} + +/* Processes a single option line as used in the configuration files. + This only sets those values that have not already been set. */ + +void process_config_line(Options *options, const char *host, + char *line, const char *filename, int linenum, + int *activep) +{ + char buf[256], *cp, *string, **charptr; + int opcode, *intptr, value, fwd_port, fwd_host_port; + + /* Skip leading whitespace. */ + cp = line + strspn(line, WHITESPACE); + if (!*cp || *cp == '\n' || *cp == '#') + return; + + /* Get the keyword. (Each line is supposed to begin with a keyword). */ + cp = strtok(cp, WHITESPACE); + { + char *t = cp; + for (; *t != 0; t++) + if ('A' <= *t && *t <= 'Z') + *t = *t - 'A' + 'a'; /* tolower */ + + } + opcode = parse_token(cp, filename, linenum); + + switch (opcode) + { + + case oForwardAgent: + intptr = &options->forward_agent; + parse_flag: + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); + value = 0; /* To avoid compiler warning... */ + if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) + value = 1; + else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) + value = 0; + else + fatal("%.200s line %d: Bad yes/no argument.", filename, linenum); + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oForwardX11: + intptr = &options->forward_x11; + goto parse_flag; + + case oRhostsAuthentication: + intptr = &options->rhosts_authentication; + goto parse_flag; + + case oPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; + + case oRSAAuthentication: + intptr = &options->rsa_authentication; + goto parse_flag; + + case oRhostsRSAAuthentication: + intptr = &options->rhosts_rsa_authentication; + goto parse_flag; + +#ifdef KRB4 + case oKerberosAuthentication: + intptr = &options->kerberos_authentication; + goto parse_flag; +#endif /* KRB4 */ + +#ifdef KERBEROS_TGT_PASSING + case oKerberosTgtPassing: + intptr = &options->kerberos_tgt_passing; + goto parse_flag; +#endif + +#ifdef AFS + case oAFSTokenPassing: + intptr = &options->afs_token_passing; + goto parse_flag; +#endif + + case oFallBackToRsh: + intptr = &options->fallback_to_rsh; + goto parse_flag; + + case oUseRsh: + intptr = &options->use_rsh; + goto parse_flag; + + case oBatchMode: + intptr = &options->batch_mode; + goto parse_flag; + + case oStrictHostKeyChecking: + intptr = &options->strict_host_key_checking; + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing yes/no argument.", + filename, linenum); + value = 0; /* To avoid compiler warning... */ + if (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0) + value = 1; + else if (strcmp(cp, "no") == 0 || strcmp(cp, "false") == 0) + value = 0; + else if (strcmp(cp, "ask") == 0) + value = 2; + else + fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); + if (*activep && *intptr == -1) + *intptr = value; + break; + +#ifdef WITH_ZLIB + case oCompression: + intptr = &options->compression; + goto parse_flag; +#endif /* WITH_ZLIB */ + + case oKeepAlives: + intptr = &options->keepalives; + goto parse_flag; + + case oTISAuthentication: + cp = strtok(NULL, WHITESPACE); + if (cp != 0 && (strcmp(cp, "yes") == 0 || strcmp(cp, "true") == 0)) + fprintf(stderr, + "%.99s line %d: Warning, TIS is not supported.\n", + filename, + linenum); + break; + +#ifdef WITH_ZLIB + case oCompressionLevel: + intptr = &options->compression_level; + goto parse_int; +#endif /* WITH_ZLIB */ + + case oIdentityFile: + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (*activep) + { + if (options->num_identity_files >= SSH_MAX_IDENTITY_FILES) + fatal("%.200s line %d: Too many identity files specified (max %d).", + filename, linenum, SSH_MAX_IDENTITY_FILES); + options->identity_files[options->num_identity_files++] = xstrdup(cp); + } + break; + + case oUser: + charptr = &options->user; + parse_string: + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (*activep && *charptr == NULL) + *charptr = xstrdup(cp); + break; + + case oGlobalKnownHostsFile: + charptr = &options->system_hostfile; + goto parse_string; + + case oUserKnownHostsFile: + charptr = &options->user_hostfile; + goto parse_string; + + case oHostName: + charptr = &options->hostname; + goto parse_string; + + case oProxyCommand: + charptr = &options->proxy_command; + string = xstrdup(""); + while ((cp = strtok(NULL, WHITESPACE)) != NULL) + { + string = xrealloc(string, strlen(string) + strlen(cp) + 2); + strcat(string, " "); + strcat(string, cp); + } + if (*activep && *charptr == NULL) + *charptr = string; + else + xfree(string); + return; + + case oPort: + intptr = &options->port; + parse_int: + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (cp[0] < '0' || cp[0] > '9') + fatal("%.200s line %d: Bad number.", filename, linenum); +#if 0 + value = atoi(cp); +#else + { + char *ptr; + value = strtol(cp, &ptr, 0); /* Octal, decimal, or hex format? */ + if (cp == ptr) + fatal("%.200s line %d: Bad number.", filename, linenum); + } +#endif + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oConnectionAttempts: + intptr = &options->connection_attempts; + goto parse_int; + + case oCipher: + intptr = &options->cipher; + cp = strtok(NULL, WHITESPACE); + value = cipher_number(cp); + if (value == -1) + fatal("%.200s line %d: Bad cipher.", filename, linenum); + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oRemoteForward: + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (cp[0] < '0' || cp[0] > '9') + fatal("%.200s line %d: Badly formatted port number.", + filename, linenum); + fwd_port = atoi(cp); + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing second argument.", + filename, linenum); + if (sscanf(cp, "%255[^:]:%d", buf, &fwd_host_port) != 2) + fatal("%.200s line %d: Badly formatted host:port.", + filename, linenum); + if (*activep) + add_remote_forward(options, fwd_port, buf, fwd_host_port); + break; + + case oLocalForward: + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (cp[0] < '0' || cp[0] > '9') + fatal("%.200s line %d: Badly formatted port number.", + filename, linenum); + fwd_port = atoi(cp); + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing second argument.", + filename, linenum); + if (sscanf(cp, "%255[^:]:%d", buf, &fwd_host_port) != 2) + fatal("%.200s line %d: Badly formatted host:port.", + filename, linenum); + if (*activep) + add_local_forward(options, fwd_port, buf, fwd_host_port); + break; + + case oHost: + *activep = 0; + while ((cp = strtok(NULL, WHITESPACE)) != NULL) + if (match_pattern(host, cp)) + { + debug("Applying options for %.100s", cp); + *activep = 1; + break; + } + /* Avoid garbage check below, as strtok already returned NULL. */ + return; + + case oEscapeChar: + intptr = &options->escape_char; + cp = strtok(NULL, WHITESPACE); + if (!cp) + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (cp[0] == '^' && cp[2] == 0 && + (unsigned char)cp[1] >= 64 && (unsigned char)cp[1] < 128) + value = (unsigned char)cp[1] & 31; + else + if (strlen(cp) == 1) + value = (unsigned char)cp[0]; + else + if (strcmp(cp, "none") == 0) + value = -2; + else + { + fatal("%.200s line %d: Bad escape character.", + filename, linenum); + /*NOTREACHED*/ + value = 0; /* Avoid compiler warning. */ + } + if (*activep && *intptr == -1) + *intptr = value; + break; + + default: + fatal("parse_config_file: Unimplemented opcode %d", opcode); + } + + /* Check that there is no garbage at end of line. */ + if (strtok(NULL, WHITESPACE) != NULL) + fatal("%.200s line %d: garbage at end of line.", + filename, linenum); +} + + +/* Reads the config file and modifies the options accordingly. Options should + already be initialized before this call. This never returns if there + is an error. If the file does not exist, this returns immediately. */ + +void read_config_file(const char *filename, const char *host, Options *options) +{ + FILE *f; + char line[1024]; + int active, linenum; + + /* Open the file. */ + f = fopen(filename, "r"); + if (!f) + return; + + debug("Reading configuration data %.200s", filename); + + /* Mark that we are now processing the options. This flag is turned on/off + by Host specifications. */ + active = 1; + linenum = 0; + while (fgets(line, sizeof(line), f)) + { + /* Update line number counter. */ + linenum++; + + process_config_line(options, host, line, filename, linenum, &active); + } + fclose(f); +} + +/* Initializes options to special values that indicate that they have not + yet been set. Read_config_file will only set options with this value. + Options are processed in the following order: command line, user config + file, system config file. Last, fill_default_options is called. */ + +void initialize_options(Options *options) +{ + memset(options, 'X', sizeof(*options)); + options->forward_agent = -1; + options->forward_x11 = -1; + options->rhosts_authentication = -1; + options->rsa_authentication = -1; +#ifdef KRB4 + options->kerberos_authentication = -1; +#endif +#ifdef KERBEROS_TGT_PASSING + options->kerberos_tgt_passing = -1; +#endif +#ifdef AFS + options->afs_token_passing = -1; +#endif + options->password_authentication = -1; + options->rhosts_rsa_authentication = -1; + options->fallback_to_rsh = -1; + options->use_rsh = -1; + options->batch_mode = -1; + options->strict_host_key_checking = -1; +#ifdef WITH_ZLIB + options->compression = -1; +#endif /* WITH_ZLIB */ + options->keepalives = -1; +#ifdef WITH_ZLIB + options->compression_level = -1; +#endif /* WITH_ZLIB */ + options->port = -1; + options->connection_attempts = -1; + options->cipher = -1; + options->num_identity_files = 0; + options->hostname = NULL; + options->proxy_command = NULL; + options->user = NULL; + options->escape_char = -1; + options->system_hostfile = NULL; + options->user_hostfile = NULL; + options->num_local_forwards = 0; + options->num_remote_forwards = 0; +} + +/* Called after processing other sources of option data, this fills those + options for which no value has been specified with their default values. */ + +void fill_default_options(Options *options) +{ + if (options->forward_agent == -1) + options->forward_agent = 1; + if (options->forward_x11 == -1) + options->forward_x11 = 1; + if (options->rhosts_authentication == -1) + options->rhosts_authentication = 1; + if (options->rsa_authentication == -1) + options->rsa_authentication = 1; +#ifdef KRB4 + if (options->kerberos_authentication == -1) + options->kerberos_authentication = 1; +#endif +#ifdef KERBEROS_TGT_PASSING + if (options->kerberos_tgt_passing == -1) + options->kerberos_tgt_passing = 1; +#endif +#ifdef AFS + if (options->afs_token_passing == -1) + options->afs_token_passing = 1; +#endif + if (options->password_authentication == -1) + options->password_authentication = 1; + if (options->rhosts_rsa_authentication == -1) + options->rhosts_rsa_authentication = 1; + if (options->fallback_to_rsh == -1) + options->fallback_to_rsh = 1; + if (options->use_rsh == -1) + options->use_rsh = 0; + if (options->batch_mode == -1) + options->batch_mode = 0; + if (options->strict_host_key_checking == -1) + options->strict_host_key_checking = 2; /* 2 is default */ +#ifdef WITH_ZLIB + if (options->compression == -1) + options->compression = 0; +#endif /* WITH_ZLIB */ + if (options->keepalives == -1) + options->keepalives = 1; +#ifdef WITH_ZLIB + if (options->compression_level == -1) + options->compression_level = 6; +#endif /* WITH_ZLIB */ + if (options->port == -1) + options->port = 0; /* Filled in ssh_connect. */ + if (options->connection_attempts == -1) + options->connection_attempts = 4; + if (options->cipher == -1) + options->cipher = SSH_CIPHER_NOT_SET; /* Selected in ssh_login(). */ + if (options->num_identity_files == 0) + { + options->identity_files[0] = + xmalloc(2 + strlen(SSH_CLIENT_IDENTITY) + 1); + sprintf(options->identity_files[0], "~/%.100s", SSH_CLIENT_IDENTITY); + options->num_identity_files = 1; + } + if (options->escape_char == -1) + options->escape_char = '~'; + if (options->system_hostfile == NULL) + options->system_hostfile = SSH_SYSTEM_HOSTFILE; + if (options->user_hostfile == NULL) + options->user_hostfile = SSH_USER_HOSTFILE; + /* options->proxy_command should not be set by default */ + /* options->user will be set in the main program if appropriate */ + /* options->hostname will be set in the main program if appropriate */ +} + diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h new file mode 100644 index 00000000000..2ad83aec67b --- /dev/null +++ b/usr.bin/ssh/readconf.h @@ -0,0 +1,116 @@ +/* + +readconf.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Apr 22 00:25:29 1995 ylo + +Functions for reading the configuration file. + +*/ + +/* RCSID("$Id: readconf.h,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); */ + +#ifndef READCONF_H +#define READCONF_H + +/* Data structure for representing a forwarding request. */ + +typedef struct +{ + int port; /* Port to forward. */ + char *host; /* Host to connect. */ + int host_port; /* Port to connect on host. */ +} Forward; + +/* Data structure for representing option data. */ + +typedef struct +{ + int forward_agent; /* Forward authentication agent. */ + int forward_x11; /* Forward X11 display. */ + int rhosts_authentication; /* Try rhosts authentication. */ + int rhosts_rsa_authentication;/* Try rhosts with RSA authentication. */ + int rsa_authentication; /* Try RSA authentication. */ +#ifdef KRB4 + int kerberos_authentication; /* Try Kerberos authentication. */ +#endif +#ifdef KERBEROS_TGT_PASSING + int kerberos_tgt_passing; /* Try Kerberos tgt passing. */ +#endif +#ifdef AFS + int afs_token_passing; /* Try AFS token passing. */ +#endif + int password_authentication; /* Try password authentication. */ + int fallback_to_rsh; /* Use rsh if cannot connect with ssh. */ + int use_rsh; /* Always use rsh (don\'t try ssh). */ + int batch_mode; /* Batch mode: do not ask for passwords. */ + int strict_host_key_checking; /* Strict host key checking. */ +#ifdef WITH_ZLIB + int compression; /* Compress packets in both directions. */ + int compression_level; /* Compression level 1 (fast) to 9 (best). */ +#endif /* WITH_ZLIB */ + int keepalives; /* Set SO_KEEPALIVE. */ + + int port; /* Port to connect. */ + int connection_attempts; /* Max attempts (seconds) before giving up */ + int cipher; /* Cipher to use. */ + char *hostname; /* Real host to connect. */ + char *proxy_command; /* Proxy command for connecting the host. */ + char *user; /* User to log in as. */ + int escape_char; /* Escape character; -2 = none */ + + char *system_hostfile; /* Path for /etc/ssh_known_hosts. */ + char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */ + + int num_identity_files; /* Number of files for RSA identities. */ + char *identity_files[SSH_MAX_IDENTITY_FILES]; + + /* Local TCP/IP forward requests. */ + int num_local_forwards; + Forward local_forwards[SSH_MAX_FORWARDS_PER_DIRECTION]; + + /* Remote TCP/IP forward requests. */ + int num_remote_forwards; + Forward remote_forwards[SSH_MAX_FORWARDS_PER_DIRECTION]; +} Options; + + +/* Initializes options to special values that indicate that they have not + yet been set. Read_config_file will only set options with this value. + Options are processed in the following order: command line, user config + file, system config file. Last, fill_default_options is called. */ +void initialize_options(Options *options); + +/* Called after processing other sources of option data, this fills those + options for which no value has been specified with their default values. */ +void fill_default_options(Options *options); + +/* Processes a single option line as used in the configuration files. + This only sets those values that have not already been set. */ +void process_config_line(Options *options, const char *host, + char *line, const char *filename, int linenum, + int *activep); + +/* Reads the config file and modifies the options accordingly. Options should + already be initialized before this call. This never returns if there + is an error. If the file does not exist, this returns immediately. */ +void read_config_file(const char *filename, const char *host, + Options *options); + +/* Adds a local TCP/IP port forward to options. Never returns if there + is an error. */ +void add_local_forward(Options *options, int port, const char *host, + int host_port); + +/* Adds a remote TCP/IP port forward to options. Never returns if there + is an error. */ +void add_remote_forward(Options *options, int port, const char *host, + int host_port); + + +#endif /* READCONF_H */ diff --git a/usr.bin/ssh/readpass.c b/usr.bin/ssh/readpass.c new file mode 100644 index 00000000000..c9b37dd9b5f --- /dev/null +++ b/usr.bin/ssh/readpass.c @@ -0,0 +1,171 @@ +/* + +readpass.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Mon Jul 10 22:08:59 1995 ylo + +Functions for reading passphrases and passwords. + +*/ + +#include "includes.h" +RCSID("$Id: readpass.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); + +#include "xmalloc.h" +#include "ssh.h" + +/* Saved old terminal mode for read_passphrase. */ +#ifdef USING_TERMIOS +static struct termios saved_tio; +#endif +#ifdef USING_SGTTY +static struct sgttyb saved_tio; +#endif + +/* Old interrupt signal handler for read_passphrase. */ +static RETSIGTYPE (*old_handler)(int sig) = NULL; + +/* Interrupt signal handler for read_passphrase. */ + +RETSIGTYPE intr_handler(int sig) +{ + /* Restore terminal modes. */ +#ifdef USING_TERMIOS + tcsetattr(fileno(stdin), TCSANOW, &saved_tio); +#endif +#ifdef USING_SGTTY + ioctl(fileno(stdin), TIOCSETP, &saved_tio); +#endif + /* Restore the old signal handler. */ + signal(sig, old_handler); + /* Resend the signal, with the old handler. */ + kill(getpid(), sig); +} + +/* Reads a passphrase from /dev/tty with echo turned off. Returns the + passphrase (allocated with xmalloc). Exits if EOF is encountered. + The passphrase if read from stdin if from_stdin is true (as is the + case with ssh-keygen). */ + +char *read_passphrase(const char *prompt, int from_stdin) +{ + char buf[1024], *cp; +#ifdef USING_TERMIOS + struct termios tio; +#endif +#ifdef USING_SGTTY + struct sgttyb tio; +#endif + FILE *f; + + if (from_stdin) + f = stdin; + else + { + /* Read the passphrase from /dev/tty to make it possible to ask it even + when stdin has been redirected. */ + f = fopen("/dev/tty", "r"); + if (!f) + { + if (getenv("DISPLAY")) + { + char command[512]; + fprintf(stderr, + "Executing ssh-askpass to query the password...\n"); + fflush(stdout); + fflush(stderr); + sprintf(command, "ssh-askpass '%.400s'", prompt); + f = popen(command, "r"); + if (!fgets(buf, sizeof(buf), f)) + { + pclose(f); + fprintf(stderr, "No passphrase supplied. Exiting.\n"); + exit(1); + } + pclose(f); + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + return xstrdup(buf); + } + + /* No controlling terminal and no DISPLAY. Nowhere to read. */ + fprintf(stderr, "You have no controlling tty and no DISPLAY. Cannot read passphrase.\n"); + exit(1); + } + } + + /* Display the prompt (on stderr because stdout might be redirected). */ + fflush(stdout); + fprintf(stderr, "%s", prompt); + fflush(stderr); + + /* Get terminal modes. */ +#ifdef USING_TERMIOS + tcgetattr(fileno(f), &tio); +#endif +#ifdef USING_SGTTY + ioctl(fileno(f), TIOCGETP, &tio); +#endif + saved_tio = tio; + /* Save signal handler and set the new handler. */ + old_handler = signal(SIGINT, intr_handler); + + /* Set new terminal modes disabling all echo. */ +#ifdef USING_TERMIOS + tio.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); + tcsetattr(fileno(f), TCSANOW, &tio); +#endif +#ifdef USING_SGTTY + tio.sg_flags &= ~(ECHO); + ioctl(fileno(f), TIOCSETP, &tio); +#endif + + /* Read the passphrase from the terminal. */ + if (fgets(buf, sizeof(buf), f) == NULL) + { + /* Got EOF. Just exit. */ + /* Restore terminal modes. */ +#ifdef USING_TERMIOS + tcsetattr(fileno(f), TCSANOW, &saved_tio); +#endif +#ifdef USING_SGTTY + ioctl(fileno(f), TIOCSETP, &saved_tio); +#endif + /* Restore the signal handler. */ + signal(SIGINT, old_handler); + /* Print a newline (the prompt probably didn\'t have one). */ + fprintf(stderr, "\n"); + /* Close the file. */ + if (f != stdin) + fclose(f); + exit(1); + } + /* Restore terminal modes. */ +#ifdef USING_TERMIOS + tcsetattr(fileno(f), TCSANOW, &saved_tio); +#endif +#ifdef USING_SGTTY + ioctl(fileno(f), TIOCSETP, &saved_tio); +#endif + /* Restore the signal handler. */ + (void)signal(SIGINT, old_handler); + /* Remove newline from the passphrase. */ + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + /* Allocate a copy of the passphrase. */ + cp = xstrdup(buf); + /* Clear the buffer so we don\'t leave copies of the passphrase laying + around. */ + memset(buf, 0, sizeof(buf)); + /* Print a newline since the prompt probably didn\'t have one. */ + fprintf(stderr, "\n"); + /* Close the file. */ + if (f != stdin) + fclose(f); + return cp; +} diff --git a/usr.bin/ssh/remove.c b/usr.bin/ssh/remove.c new file mode 100644 index 00000000000..7366ed2366b --- /dev/null +++ b/usr.bin/ssh/remove.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int remove(const char *filename) +{ + return unlink(filename); +} diff --git a/usr.bin/ssh/rfc-pg.c b/usr.bin/ssh/rfc-pg.c new file mode 100644 index 00000000000..20d9b483908 --- /dev/null +++ b/usr.bin/ssh/rfc-pg.c @@ -0,0 +1,49 @@ +/* + +rfc-pg.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Fri Jul 7 02:14:16 1995 ylo + +*/ + +/* RCSID("$Id: rfc-pg.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); */ + +#include <stdio.h> + +int main() +{ + int add_formfeed = 0; + int skipping = 0; + int ch; + + while ((ch = getc(stdin)) != EOF) + { + if (ch == '\n') + { + if (add_formfeed) + { + putc('\n', stdout); + putc('\014', stdout); + putc('\n', stdout); + add_formfeed = 0; + skipping = 1; + continue; + } + if (skipping) + continue; + } + skipping = 0; + if (ch == '\014') + { + add_formfeed = 1; + continue; + } + putc(ch, stdout); + } + exit(0); +} diff --git a/usr.bin/ssh/scp.1 b/usr.bin/ssh/scp.1 new file mode 100644 index 00000000000..16be9b9439f --- /dev/null +++ b/usr.bin/ssh/scp.1 @@ -0,0 +1,127 @@ +.\" -*- nroff -*- +.\" +.\" scp.1 +.\" +.\" Author: Tatu Ylonen <ylo@cs.hut.fi> +.\" +.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +.\" All rights reserved +.\" +.\" Created: Sun May 7 00:14:37 1995 ylo +.\" +.\" $Id: scp.1,v 1.1 1999/09/26 20:53:37 deraadt Exp $ +.\" +.TH SCP 1 "November 8, 1995" SSH SSH + +.SH NAME +scp \- secure copy (remote file copy program) + +.SH SYNOPSIS +.LP +.B scp +[\c +.B \-prvC\c +] +[\c +.BI \-P "\ port\c +] +[\c +.BI \-c "\ cipher\c +] +[\c +.BI \-i "\ identity\c +] +.if n .ti +5 +[[\c +.B user@\c +]\c +.B host1:\c +]\c +.B filename1\c +\&.\|.\|. +[[\c +.B user@\c +]\c +.B host2:\c +]\c +.B filename2 + +.SH DESCRIPTION +.LP +.B Scp +copies files between hosts on a network. It uses +.B ssh +for data transfer, and uses the same authentication and provides the +same security as +.B ssh. +Unlike +.BR rcp ", +.B ssh +will ask for passwords or passphrases if they are needed for +authentication. +.LP +Any file name may contain a host and user specification to indicate +that the file is to be copied to/from that host. Copies between two +remote hosts are permitted. + +.SH OPTIONS + +.TP 0.6i +.BI \-c "\ cipher +Selects the cipher to use for encrypting the data transfer. This +option is directly passed to +.B ssh. +.TP +.BI \-i "\ identity_file +Selects the file from which the identity (private key) for RSA +authentication is read. This option is directly passed to +.B ssh. +.TP +.B \-p +Preserves modification times, access times, and modes from the +original file. +.TP +.B \-r +Recursively copy entire directories. +.TP +.B \-v +Verbose mode. Causes +.B scp +and +.B ssh +to print debugging messages about their progress. This is helpful in +debugging connection, authentication, and configuration problems. +.TP +.B \-B +Selects batch mode (prevents asking for passwords or passphrases). +.TP +.B \-C +Compression enable. Passes the -C flag to +.B ssh +to enable compression. +.TP +.BI \-P "\ port +Specifies the port to connect to on the remote host. Note that this +option is written with a capital P, because \-p is already reserved for +preserving the times and modes of the file in rcp. + +.SH AUTHORS +.LP +Timo Rinne <tri@iki.fi> and Tatu Ylonen <ylo@cs.hut.fi> + +.SH DERIVATION +.LP +.B Scp +is based on the +.B rcp +program in BSD source code from the Regents of the University of +California. + +.SH SEE ALSO +.LP +.BR ssh (1), +.BR sshd (8), +.BR ssh-keygen (1), +.BR ssh-agent (1), +.BR ssh-add (1), +.BR rcp (1) diff --git a/usr.bin/ssh/scp.c b/usr.bin/ssh/scp.c new file mode 100644 index 00000000000..8ab7174840f --- /dev/null +++ b/usr.bin/ssh/scp.c @@ -0,0 +1,1071 @@ +/* + +scp - secure remote copy. This is basically patched BSD rcp which uses ssh +to do the data transfer (instead of using rcmd). + +NOTE: This version should NOT be suid root. (This uses ssh to do the transfer +and ssh has the necessary privileges.) + +1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi> + +*/ + +/* + * Copyright (c) 1983, 1990, 1992, 1993, 1995 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * $Id: scp.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $ + */ + +#include "includes.h" +RCSID("$Id: scp.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); + +#include "ssh.h" +#include "xmalloc.h" +#ifdef HAVE_UTIME_H +#include <utime.h> +#ifdef _NEXT_SOURCE +struct utimbuf { + time_t actime; + time_t modtime; +}; +#endif /* _NEXT_SOURCE */ +#else +struct utimbuf +{ + long actime; + long modtime; +}; +#endif + +#define _PATH_CP "cp" + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + +#if defined(KERBEROS_TGT_PASSING) || defined(AFS) +/* This is set to non-zero to disable authentication forwarding. */ +int nofwd = 0; +#endif + +/* This is set to non-zero to enable verbose mode. */ +int verbose = 0; + +/* This is set to non-zero if compression is desired. */ +int compress = 0; + +/* This is set to non-zero if running in batch mode (that is, password + and passphrase queries are not allowed). */ +int batchmode = 0; + +/* This is set to the cipher type string if given on the command line. */ +char *cipher = NULL; + +/* This is set to the RSA authentication identity file name if given on + the command line. */ +char *identity = NULL; + +/* This is the port to use in contacting the remote site (is non-NULL). */ +char *port = NULL; + +/* This function executes the given command as the specified user on the given + host. This returns < 0 if execution fails, and >= 0 otherwise. + This assigns the input and output file descriptors on success. */ + +int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) +{ + int pin[2], pout[2], reserved[2]; + + if (verbose) + fprintf(stderr, "Executing: host %s, user %s, command %s\n", + host, remuser ? remuser : "(unspecified)", cmd); + + /* Reserve two descriptors so that the real pipes won't get descriptors + 0 and 1 because that will screw up dup2 below. */ + pipe(reserved); + + /* Create a socket pair for communicating with ssh. */ + if (pipe(pin) < 0) + fatal("pipe: %s", strerror(errno)); + if (pipe(pout) < 0) + fatal("pipe: %s", strerror(errno)); + + /* Free the reserved descriptors. */ + close(reserved[0]); + close(reserved[1]); + + /* For a child to execute the command on the remote host using ssh. */ + if (fork() == 0) + { + char *args[100]; + unsigned int i; + + /* Child. */ + close(pin[1]); + close(pout[0]); + dup2(pin[0], 0); + dup2(pout[1], 1); + close(pin[0]); + close(pout[1]); + + i = 0; + args[i++] = SSH_PROGRAM; + args[i++] = "-x"; + args[i++] = "-oFallBackToRsh no"; + if (verbose) + args[i++] = "-v"; + if (compress) + args[i++] = "-C"; + if (batchmode) + args[i++] = "-oBatchMode yes"; +#if defined(KERBEROS_TGT_PASSING) || defined(AFS) + if (nofwd) + args[i++] = "-k"; +#endif + if (cipher != NULL) + { + args[i++] = "-c"; + args[i++] = cipher; + } + if (identity != NULL) + { + args[i++] = "-i"; + args[i++] = identity; + } + if (port != NULL) + { + args[i++] = "-p"; + args[i++] = port; + } + if (remuser != NULL) + { + args[i++] = "-l"; + args[i++] = remuser; + } + args[i++] = host; + args[i++] = cmd; + args[i++] = NULL; + + execvp(SSH_PROGRAM, args); + perror(SSH_PROGRAM); + exit(1); + } + /* Parent. Close the other side, and return the local side. */ + close(pin[0]); + *fdout = pin[1]; + close(pout[1]); + *fdin = pout[0]; + return 0; +} + +void fatal(const char *fmt, ...) +{ + va_list ap; + char buf[1024]; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + fprintf(stderr, "%s\n", buf); + exit(255); +} + +/* This stuff used to be in BSD rcp extern.h. */ + +typedef struct { + int cnt; + char *buf; +} BUF; + +extern int iamremote; + +BUF *allocbuf(BUF *, int, int); +char *colon(char *); +void lostconn(int); +void nospace(void); +int okname(char *); +void run_err(const char *, ...); +void verifydir(char *); + +/* Stuff from BSD rcp.c continues. */ + +struct passwd *pwd; +uid_t userid; +int errs, remin, remout; +int pflag, iamremote, iamrecursive, targetshouldbedirectory; + +#define CMDNEEDS 64 +char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ + +int response(void); +void rsource(char *, struct stat *); +void sink(int, char *[]); +void source(int, char *[]); +void tolocal(int, char *[]); +void toremote(char *, int, char *[]); +void usage(void); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int ch, fflag, tflag; + char *targ; + extern char *optarg; + extern int optind; + + fflag = tflag = 0; +#if defined(KERBEROS_TGT_PASSING) || defined(AFS) + while ((ch = getopt(argc, argv, "kdfprtvBCc:i:P:")) != EOF) +#else + while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:")) != EOF) +#endif + switch(ch) { /* User-visible flags. */ + case 'p': + pflag = 1; + break; + case 'P': + port = optarg; + break; + case 'r': + iamrecursive = 1; + break; + /* Server options. */ +#if defined(KERBEROS_TGT_PASSING) || defined(AFS) + case 'k': + nofwd = 1; + break; +#endif + case 'd': + targetshouldbedirectory = 1; + break; + case 'f': /* "from" */ + iamremote = 1; + fflag = 1; + break; + case 't': /* "to" */ + iamremote = 1; + tflag = 1; + break; + case 'c': + cipher = optarg; + break; + case 'i': + identity = optarg; + break; + case 'v': + verbose = 1; + break; + case 'B': + batchmode = 1; + break; + case 'C': + compress = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if ((pwd = getpwuid(userid = getuid())) == NULL) + fatal("unknown user %d", (int)userid); + + remin = STDIN_FILENO; + remout = STDOUT_FILENO; + + if (fflag) { /* Follow "protocol", send data. */ + (void)response(); + source(argc, argv); + exit(errs != 0); + } + + if (tflag) { /* Receive data. */ + sink(argc, argv); + exit(errs != 0); + } + + if (argc < 2) + usage(); + if (argc > 2) + targetshouldbedirectory = 1; + + remin = remout = -1; + /* Command to be executed on remote system using "ssh". */ + (void)sprintf(cmd, "scp%s%s%s%s", verbose ? " -v" : "", + iamrecursive ? " -r" : "", pflag ? " -p" : "", + targetshouldbedirectory ? " -d" : ""); + + (void)signal(SIGPIPE, lostconn); + + if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ + toremote(targ, argc, argv); + else { + tolocal(argc, argv); /* Dest is local host. */ + if (targetshouldbedirectory) + verifydir(argv[argc - 1]); + } + exit(errs != 0); +} + +void +toremote(targ, argc, argv) + char *targ, *argv[]; + int argc; +{ + int i, len; + char *bp, *host, *src, *suser, *thost, *tuser; + + *targ++ = 0; + if (*targ == 0) + targ = "."; + + if ((thost = strchr(argv[argc - 1], '@'))) { + /* user@host */ + *thost++ = 0; + tuser = argv[argc - 1]; + if (*tuser == '\0') + tuser = NULL; + else if (!okname(tuser)) + exit(1); + } else { + thost = argv[argc - 1]; + tuser = NULL; + } + + for (i = 0; i < argc - 1; i++) { + src = colon(argv[i]); + if (src) { /* remote to remote */ + *src++ = 0; + if (*src == 0) + src = "."; + host = strchr(argv[i], '@'); + len = strlen(SSH_PROGRAM) + strlen(argv[i]) + + strlen(src) + (tuser ? strlen(tuser) : 0) + + strlen(thost) + strlen(targ) + CMDNEEDS + 32; + bp = xmalloc(len); + if (host) { + *host++ = 0; + suser = argv[i]; + if (*suser == '\0') + suser = pwd->pw_name; + else if (!okname(suser)) + continue; + (void)sprintf(bp, + "%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'", + SSH_PROGRAM, verbose ? " -v" : "", + suser, host, cmd, src, + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); + } else + (void)sprintf(bp, + "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'", + SSH_PROGRAM, verbose ? " -v" : "", + argv[i], cmd, src, + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); + if (verbose) + fprintf(stderr, "Executing: %s\n", bp); + (void)system(bp); + (void)xfree(bp); + } else { /* local to remote */ + if (remin == -1) { + len = strlen(targ) + CMDNEEDS + 20; + bp = xmalloc(len); + (void)sprintf(bp, "%s -t %s", cmd, targ); + host = thost; + if (do_cmd(host, tuser, + bp, &remin, &remout) < 0) + exit(1); + if (response() < 0) + exit(1); + (void)xfree(bp); + } + source(1, argv+i); + } + } +} + +void +tolocal(argc, argv) + int argc; + char *argv[]; +{ + int i, len; + char *bp, *host, *src, *suser; + + for (i = 0; i < argc - 1; i++) { + if (!(src = colon(argv[i]))) { /* Local to local. */ + len = strlen(_PATH_CP) + strlen(argv[i]) + + strlen(argv[argc - 1]) + 20; + bp = xmalloc(len); + (void)sprintf(bp, "exec %s%s%s %s %s", _PATH_CP, + iamrecursive ? " -r" : "", pflag ? " -p" : "", + argv[i], argv[argc - 1]); + if (verbose) + fprintf(stderr, "Executing: %s\n", bp); + if (system(bp)) + ++errs; + (void)xfree(bp); + continue; + } + *src++ = 0; + if (*src == 0) + src = "."; + if ((host = strchr(argv[i], '@')) == NULL) { + host = argv[i]; + suser = NULL; + } else { + *host++ = 0; + suser = argv[i]; + if (*suser == '\0') + suser = pwd->pw_name; + else if (!okname(suser)) + continue; + } + len = strlen(src) + CMDNEEDS + 20; + bp = xmalloc(len); + (void)sprintf(bp, "%s -f %s", cmd, src); + if (do_cmd(host, suser, bp, &remin, &remout) < 0) { + (void)xfree(bp); + ++errs; + continue; + } + xfree(bp); + sink(1, argv + argc - 1); + (void)close(remin); + remin = remout = -1; + } +} + +void +source(argc, argv) + int argc; + char *argv[]; +{ + struct stat stb; + static BUF buffer; + BUF *bp; + off_t i; + int amt, fd, haderr, indx, result; + char *last, *name, buf[2048]; + + for (indx = 0; indx < argc; ++indx) { + name = argv[indx]; + if ((fd = open(name, O_RDONLY, 0)) < 0) + goto syserr; + if (fstat(fd, &stb) < 0) { +syserr: run_err("%s: %s", name, strerror(errno)); + goto next; + } + switch (stb.st_mode & S_IFMT) { + case S_IFREG: + break; + case S_IFDIR: + if (iamrecursive) { + rsource(name, &stb); + goto next; + } + /* FALLTHROUGH */ + default: + run_err("%s: not a regular file", name); + goto next; + } + if ((last = strrchr(name, '/')) == NULL) + last = name; + else + ++last; + if (pflag) { + /* + * Make it compatible with possible future + * versions expecting microseconds. + */ + (void)sprintf(buf, "T%lu 0 %lu 0\n", + (unsigned long)stb.st_mtime, + (unsigned long)stb.st_atime); + (void)write(remout, buf, strlen(buf)); + if (response() < 0) + goto next; + } +#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) + (void)sprintf(buf, "C%04o %lu %s\n", + (unsigned int)(stb.st_mode & FILEMODEMASK), + (unsigned long)stb.st_size, + last); + if (verbose) + { + fprintf(stderr, "Sending file modes: %s", buf); + fflush(stderr); + } + (void)write(remout, buf, strlen(buf)); + if (response() < 0) + goto next; + if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { +next: (void)close(fd); + continue; + } + + /* Keep writing after an error so that we stay sync'd up. */ + for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { + amt = bp->cnt; + if (i + amt > stb.st_size) + amt = stb.st_size - i; + if (!haderr) { + result = read(fd, bp->buf, amt); + if (result != amt) + haderr = result >= 0 ? EIO : errno; + } + if (haderr) + (void)write(remout, bp->buf, amt); + else { + result = write(remout, bp->buf, amt); + if (result != amt) + haderr = result >= 0 ? EIO : errno; + } + } + if (close(fd) < 0 && !haderr) + haderr = errno; + if (!haderr) + (void)write(remout, "", 1); + else + run_err("%s: %s", name, strerror(haderr)); + (void)response(); + } +} + +void +rsource(name, statp) + char *name; + struct stat *statp; +{ + DIR *dirp; + struct dirent *dp; + char *last, *vect[1], path[1100]; + + if (!(dirp = opendir(name))) { + run_err("%s: %s", name, strerror(errno)); + return; + } + last = strrchr(name, '/'); + if (last == 0) + last = name; + else + last++; + if (pflag) { + (void)sprintf(path, "T%lu 0 %lu 0\n", + (unsigned long)statp->st_mtime, + (unsigned long)statp->st_atime); + (void)write(remout, path, strlen(path)); + if (response() < 0) { + closedir(dirp); + return; + } + } + (void)sprintf(path, + "D%04o %d %.1024s\n", (unsigned int)(statp->st_mode & FILEMODEMASK), + 0, last); + if (verbose) + fprintf(stderr, "Entering directory: %s", path); + (void)write(remout, path, strlen(path)); + if (response() < 0) { + closedir(dirp); + return; + } + while ((dp = readdir(dirp))) { + if (dp->d_ino == 0) + continue; + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) { + run_err("%s/%s: name too long", name, dp->d_name); + continue; + } + (void)sprintf(path, "%s/%s", name, dp->d_name); + vect[0] = path; + source(1, vect); + } + (void)closedir(dirp); + (void)write(remout, "E\n", 2); + (void)response(); +} + +void +sink(argc, argv) + int argc; + char *argv[]; +{ + static BUF buffer; + struct stat stb; + enum { YES, NO, DISPLAYED } wrerr; + BUF *bp; + off_t i, j; + int amt, count, exists, first, mask, mode, ofd, omode; + int setimes, size, targisdir, wrerrno = 0; + char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; + struct utimbuf ut; + int dummy_usec; + +#define SCREWUP(str) { why = str; goto screwup; } + + setimes = targisdir = 0; + mask = umask(0); + if (!pflag) + (void)umask(mask); + if (argc != 1) { + run_err("ambiguous target"); + exit(1); + } + targ = *argv; + if (targetshouldbedirectory) + verifydir(targ); + + (void)write(remout, "", 1); + if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) + targisdir = 1; + for (first = 1;; first = 0) { + cp = buf; + if (read(remin, cp, 1) <= 0) + return; + if (*cp++ == '\n') + SCREWUP("unexpected <newline>"); + do { + if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) + SCREWUP("lost connection"); + *cp++ = ch; + } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); + *cp = 0; + + if (buf[0] == '\01' || buf[0] == '\02') { + if (iamremote == 0) + (void)write(STDERR_FILENO, + buf + 1, strlen(buf + 1)); + if (buf[0] == '\02') + exit(1); + ++errs; + continue; + } + if (buf[0] == 'E') { + (void)write(remout, "", 1); + return; + } + + if (ch == '\n') + *--cp = 0; + +#define getnum(t) (t) = 0; \ + while (*cp >= '0' && *cp <= '9') (t) = (t) * 10 + (*cp++ - '0'); + cp = buf; + if (*cp == 'T') { + setimes++; + cp++; + getnum(ut.modtime); + if (*cp++ != ' ') + SCREWUP("mtime.sec not delimited"); + getnum(dummy_usec); + if (*cp++ != ' ') + SCREWUP("mtime.usec not delimited"); + getnum(ut.actime); + if (*cp++ != ' ') + SCREWUP("atime.sec not delimited"); + getnum(dummy_usec); + if (*cp++ != '\0') + SCREWUP("atime.usec not delimited"); + (void)write(remout, "", 1); + continue; + } + if (*cp != 'C' && *cp != 'D') { + /* + * Check for the case "rcp remote:foo\* local:bar". + * In this case, the line "No match." can be returned + * by the shell before the rcp command on the remote is + * executed so the ^Aerror_message convention isn't + * followed. + */ + if (first) { + run_err("%s", cp); + exit(1); + } + SCREWUP("expected control record"); + } + mode = 0; + for (++cp; cp < buf + 5; cp++) { + if (*cp < '0' || *cp > '7') + SCREWUP("bad mode"); + mode = (mode << 3) | (*cp - '0'); + } + if (*cp++ != ' ') + SCREWUP("mode not delimited"); + + for (size = 0; *cp >= '0' && *cp <= '9';) + size = size * 10 + (*cp++ - '0'); + if (*cp++ != ' ') + SCREWUP("size not delimited"); + if (targisdir) { + static char *namebuf; + static int cursize; + size_t need; + + need = strlen(targ) + strlen(cp) + 250; + if (need > cursize) + namebuf = xmalloc(need); + (void)sprintf(namebuf, "%s%s%s", targ, + *targ ? "/" : "", cp); + np = namebuf; + } else + np = targ; + exists = stat(np, &stb) == 0; + if (buf[0] == 'D') { + int mod_flag = pflag; + if (exists) { + if (!S_ISDIR(stb.st_mode)) { + errno = ENOTDIR; + goto bad; + } + if (pflag) + (void)chmod(np, mode); + } else { + /* Handle copying from a read-only directory */ + mod_flag = 1; + if (mkdir(np, mode | S_IRWXU) < 0) + goto bad; + } + vect[0] = np; + sink(1, vect); + if (setimes) { + setimes = 0; + if (utime(np, &ut) < 0) + run_err("%s: set times: %s", + np, strerror(errno)); + } + if (mod_flag) + (void)chmod(np, mode); + continue; + } + omode = mode; + mode |= S_IWRITE; + if ((ofd = open(np, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) { +bad: run_err("%s: %s", np, strerror(errno)); + continue; + } + (void)write(remout, "", 1); + if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { + (void)close(ofd); + continue; + } + cp = bp->buf; + wrerr = NO; + for (count = i = 0; i < size; i += 4096) { + amt = 4096; + if (i + amt > size) + amt = size - i; + count += amt; + do { + j = read(remin, cp, amt); + if (j <= 0) { + run_err("%s", j ? strerror(errno) : + "dropped connection"); + exit(1); + } + amt -= j; + cp += j; + } while (amt > 0); + if (count == bp->cnt) { + /* Keep reading so we stay sync'd up. */ + if (wrerr == NO) { + j = write(ofd, bp->buf, count); + if (j != count) { + wrerr = YES; + wrerrno = j >= 0 ? EIO : errno; + } + } + count = 0; + cp = bp->buf; + } + } + if (count != 0 && wrerr == NO && + (j = write(ofd, bp->buf, count)) != count) { + wrerr = YES; + wrerrno = j >= 0 ? EIO : errno; + } +#if 0 + if (ftruncate(ofd, size)) { + run_err("%s: truncate: %s", np, strerror(errno)); + wrerr = DISPLAYED; + } +#endif + if (pflag) { + if (exists || omode != mode) +#ifdef HAVE_FCHMOD + if (fchmod(ofd, omode)) +#else /* HAVE_FCHMOD */ + if (chmod(np, omode)) +#endif /* HAVE_FCHMOD */ + run_err("%s: set mode: %s", + np, strerror(errno)); + } else { + if (!exists && omode != mode) +#ifdef HAVE_FCHMOD + if (fchmod(ofd, omode & ~mask)) +#else /* HAVE_FCHMOD */ + if (chmod(np, omode & ~mask)) +#endif /* HAVE_FCHMOD */ + run_err("%s: set mode: %s", + np, strerror(errno)); + } + (void)close(ofd); + (void)response(); + if (setimes && wrerr == NO) { + setimes = 0; + if (utime(np, &ut) < 0) { + run_err("%s: set times: %s", + np, strerror(errno)); + wrerr = DISPLAYED; + } + } + switch(wrerr) { + case YES: + run_err("%s: %s", np, strerror(wrerrno)); + break; + case NO: + (void)write(remout, "", 1); + break; + case DISPLAYED: + break; + } + } +screwup: + run_err("protocol error: %s", why); + exit(1); +} + +int +response() +{ + char ch, *cp, resp, rbuf[2048]; + + if (read(remin, &resp, sizeof(resp)) != sizeof(resp)) + lostconn(0); + + cp = rbuf; + switch(resp) { + case 0: /* ok */ + return (0); + default: + *cp++ = resp; + /* FALLTHROUGH */ + case 1: /* error, followed by error msg */ + case 2: /* fatal error, "" */ + do { + if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) + lostconn(0); + *cp++ = ch; + } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); + + if (!iamremote) + (void)write(STDERR_FILENO, rbuf, cp - rbuf); + ++errs; + if (resp == 1) + return (-1); + exit(1); + } + /* NOTREACHED */ +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: scp [-p] f1 f2; or: scp [-pr] f1 ... fn directory\n"); + exit(1); +} + +void +run_err(const char *fmt, ...) +{ + static FILE *fp; + va_list ap; + va_start(ap, fmt); + + ++errs; + if (fp == NULL && !(fp = fdopen(remout, "w"))) + return; + (void)fprintf(fp, "%c", 0x01); + (void)fprintf(fp, "scp: "); + (void)vfprintf(fp, fmt, ap); + (void)fprintf(fp, "\n"); + (void)fflush(fp); + + if (!iamremote) + { + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } + + va_end(ap); +} + +/* Stuff below is from BSD rcp util.c. */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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. + * + * $Id: scp.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $ + */ + +char * +colon(cp) + char *cp; +{ + if (*cp == ':') /* Leading colon is part of file name. */ + return (0); + + for (; *cp; ++cp) { + if (*cp == ':') + return (cp); + if (*cp == '/') + return (0); + } + return (0); +} + +void +verifydir(cp) + char *cp; +{ + struct stat stb; + + if (!stat(cp, &stb)) { + if (S_ISDIR(stb.st_mode)) + return; + errno = ENOTDIR; + } + run_err("%s: %s", cp, strerror(errno)); + exit(1); +} + +int +okname(cp0) + char *cp0; +{ + int c; + char *cp; + + cp = cp0; + do { + c = *cp; + if (c & 0200) + goto bad; + if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') + goto bad; + } while (*++cp); + return (1); + +bad: fprintf(stderr, "%s: invalid user name", cp0); + return (0); +} + +BUF * +allocbuf(bp, fd, blksize) + BUF *bp; + int fd, blksize; +{ + size_t size; +#ifdef HAVE_ST_BLKSIZE + struct stat stb; + + if (fstat(fd, &stb) < 0) { + run_err("fstat: %s", strerror(errno)); + return (0); + } + if (stb.st_blksize == 0) + size = blksize; + else + size = blksize + (stb.st_blksize - blksize % stb.st_blksize) % + stb.st_blksize; +#else /* HAVE_ST_BLKSIZE */ + size = blksize; +#endif /* HAVE_ST_BLKSIZE */ + if (bp->cnt >= size) + return (bp); + if (bp->buf == NULL) + bp->buf = xmalloc(size); + else + bp->buf = xrealloc(bp->buf, size); + bp->cnt = size; + return (bp); +} + +void +lostconn(signo) + int signo; +{ + if (!iamremote) + fprintf(stderr, "lost connection\n"); + exit(1); +} diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c new file mode 100644 index 00000000000..4a70624d18a --- /dev/null +++ b/usr.bin/ssh/servconf.c @@ -0,0 +1,499 @@ +/* + +servconf.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Mon Aug 21 15:48:58 1995 ylo + +*/ + +#include "includes.h" +RCSID("$Id: servconf.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); + +#include "ssh.h" +#include "servconf.h" +#include "xmalloc.h" + +/* Initializes the server options to their default values. */ + +void initialize_server_options(ServerOptions *options) +{ + memset(options, 0, sizeof(*options)); + options->port = -1; + options->listen_addr.s_addr = INADDR_ANY; + options->host_key_file = NULL; + options->random_seed_file = NULL; + options->server_key_bits = -1; + options->login_grace_time = -1; + options->key_regeneration_time = -1; + options->permit_root_login = -1; + options->ignore_rhosts = -1; + options->quiet_mode = -1; + options->fascist_logging = -1; + options->print_motd = -1; + options->x11_forwarding = -1; + options->strict_modes = -1; + options->keepalives = -1; + options->log_facility = (SyslogFacility)-1; + options->rhosts_authentication = -1; + options->rhosts_rsa_authentication = -1; + options->rsa_authentication = -1; +#ifdef KRB4 + options->kerberos_authentication = -1; + options->kerberos_or_local_passwd = -1; +#endif +#if defined(KRB4) || defined(AFS) + options->kerberos_ticket_cleanup = -1; +#endif +#ifdef KERBEROS_TGT_PASSING + options->kerberos_tgt_passing = -1; +#endif +#ifdef AFS + options->afs_token_passing = -1; +#endif + options->password_authentication = -1; + options->permit_empty_passwd = -1; + options->num_allow_hosts = 0; + options->num_deny_hosts = 0; +} + +void fill_default_server_options(ServerOptions *options) +{ + if (options->port == -1) + { + struct servent *sp; + + sp = getservbyname(SSH_SERVICE_NAME, "tcp"); + if (sp) + options->port = ntohs(sp->s_port); + else + options->port = SSH_DEFAULT_PORT; + endservent(); + } + if (options->host_key_file == NULL) + options->host_key_file = HOST_KEY_FILE; + if (options->random_seed_file == NULL) + options->random_seed_file = SSH_DAEMON_SEED_FILE; + if (options->server_key_bits == -1) + options->server_key_bits = 768; + if (options->login_grace_time == -1) + options->login_grace_time = 600; + if (options->key_regeneration_time == -1) + options->key_regeneration_time = 3600; + if (options->permit_root_login == -1) + options->permit_root_login = 1; + if (options->ignore_rhosts == -1) + options->ignore_rhosts = 0; + if (options->quiet_mode == -1) + options->quiet_mode = 0; + if (options->fascist_logging == -1) + options->fascist_logging = 1; + if (options->print_motd == -1) + options->print_motd = 1; + if (options->x11_forwarding == -1) + options->x11_forwarding = 1; + if (options->strict_modes == -1) + options->strict_modes = 1; + if (options->keepalives == -1) + options->keepalives = 1; + if (options->log_facility == (SyslogFacility)(-1)) + options->log_facility = SYSLOG_FACILITY_DAEMON; + if (options->rhosts_authentication == -1) + options->rhosts_authentication = 0; + if (options->rhosts_rsa_authentication == -1) + options->rhosts_rsa_authentication = 1; + if (options->rsa_authentication == -1) + options->rsa_authentication = 1; +#ifdef KRB4 + if (options->kerberos_authentication == -1) + options->kerberos_authentication = 1; + if (options->kerberos_or_local_passwd == -1) + options->kerberos_or_local_passwd = 0; +#endif +#if defined(KRB4) || defined(AFS) + if (options->kerberos_ticket_cleanup == -1) + options->kerberos_ticket_cleanup = 1; +#endif +#ifdef KERBEROS_TGT_PASSING + if (options->kerberos_tgt_passing == -1) + options->kerberos_tgt_passing = 0; +#endif +#ifdef AFS + if (options->afs_token_passing == -1) + options->afs_token_passing = 1; +#endif + if (options->password_authentication == -1) + options->password_authentication = 1; + if (options->permit_empty_passwd == -1) + options->permit_empty_passwd = 1; +} + +#define WHITESPACE " \t\r\n" + +/* Keyword tokens. */ +typedef enum +{ + sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime, + sPermitRootLogin, sQuietMode, sFascistLogging, sLogFacility, + sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication, +#ifdef KRB4 + sKerberosAuthentication, sKerberosOrLocalPasswd, +#endif +#if defined(KRB4) || defined(AFS) + sKerberosTicketCleanup, +#endif +#ifdef KERBEROS_TGT_PASSING + sKerberosTgtPassing, +#endif +#ifdef AFS + sAFSTokenPassing, +#endif + sPasswordAuthentication, sAllowHosts, sDenyHosts, sListenAddress, + sPrintMotd, sIgnoreRhosts, sX11Forwarding, + sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives +} ServerOpCodes; + +/* Textual representation of the tokens. */ +static struct +{ + const char *name; + ServerOpCodes opcode; +} keywords[] = +{ + { "port", sPort }, + { "hostkey", sHostKeyFile }, + { "serverkeybits", sServerKeyBits }, + { "logingracetime", sLoginGraceTime }, + { "keyregenerationinterval", sKeyRegenerationTime }, + { "permitrootlogin", sPermitRootLogin }, + { "quietmode", sQuietMode }, + { "fascistlogging", sFascistLogging }, + { "syslogfacility", sLogFacility }, + { "rhostsauthentication", sRhostsAuthentication }, + { "rhostsrsaauthentication", sRhostsRSAAuthentication }, + { "rsaauthentication", sRSAAuthentication }, +#ifdef KRB4 + { "kerberosauthentication", sKerberosAuthentication }, + { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, +#endif +#if defined(KRB4) || defined(AFS) + { "kerberosticketcleanup", sKerberosTicketCleanup }, +#endif +#ifdef KERBEROS_TGT_PASSING + { "kerberostgtpassing", sKerberosTgtPassing }, +#endif +#ifdef AFS + { "afstokenpassing", sAFSTokenPassing }, +#endif + { "passwordauthentication", sPasswordAuthentication }, + { "allowhosts", sAllowHosts }, + { "denyhosts", sDenyHosts }, + { "listenaddress", sListenAddress }, + { "printmotd", sPrintMotd }, + { "ignorerhosts", sIgnoreRhosts }, + { "x11forwarding", sX11Forwarding }, + { "strictmodes", sStrictModes }, + { "permitemptypasswords", sEmptyPasswd }, + { "randomseed", sRandomSeedFile }, + { "keepalive", sKeepAlives }, + { NULL, 0 } +}; + +static struct +{ + const char *name; + SyslogFacility facility; +} log_facilities[] = +{ + { "DAEMON", SYSLOG_FACILITY_DAEMON }, + { "USER", SYSLOG_FACILITY_USER }, + { "AUTH", SYSLOG_FACILITY_AUTH }, + { "LOCAL0", SYSLOG_FACILITY_LOCAL0 }, + { "LOCAL1", SYSLOG_FACILITY_LOCAL1 }, + { "LOCAL2", SYSLOG_FACILITY_LOCAL2 }, + { "LOCAL3", SYSLOG_FACILITY_LOCAL3 }, + { "LOCAL4", SYSLOG_FACILITY_LOCAL4 }, + { "LOCAL5", SYSLOG_FACILITY_LOCAL5 }, + { "LOCAL6", SYSLOG_FACILITY_LOCAL6 }, + { "LOCAL7", SYSLOG_FACILITY_LOCAL7 }, + { NULL, 0 } +}; + +/* Returns the number of the token pointed to by cp of length len. + Never returns if the token is not known. */ + +static ServerOpCodes parse_token(const char *cp, const char *filename, + int linenum) +{ + unsigned int i; + + for (i = 0; keywords[i].name; i++) + if (strcmp(cp, keywords[i].name) == 0) + return keywords[i].opcode; + + fprintf(stderr, "%s line %d: Bad configuration option: %s\n", + filename, linenum, cp); + exit(1); +} + +/* Reads the server configuration file. */ + +void read_server_config(ServerOptions *options, const char *filename) +{ + FILE *f; + char line[1024]; + char *cp, **charptr; + int linenum, *intptr, i, value; + ServerOpCodes opcode; + + f = fopen(filename, "r"); + if (!f) + { + perror(filename); + return; + } + + linenum = 0; + while (fgets(line, sizeof(line), f)) + { + linenum++; + cp = line + strspn(line, WHITESPACE); + if (!*cp || *cp == '#') + continue; + cp = strtok(cp, WHITESPACE); + { + char *t = cp; + for (; *t != 0; t++) + if ('A' <= *t && *t <= 'Z') + *t = *t - 'A' + 'a'; /* tolower */ + + } + opcode = parse_token(cp, filename, linenum); + switch (opcode) + { + case sPort: + intptr = &options->port; + parse_int: + cp = strtok(NULL, WHITESPACE); + if (!cp) + { + fprintf(stderr, "%s line %d: missing integer value.\n", + filename, linenum); + exit(1); + } + value = atoi(cp); + if (*intptr == -1) + *intptr = value; + break; + + case sServerKeyBits: + intptr = &options->server_key_bits; + goto parse_int; + + case sLoginGraceTime: + intptr = &options->login_grace_time; + goto parse_int; + + case sKeyRegenerationTime: + intptr = &options->key_regeneration_time; + goto parse_int; + + case sListenAddress: + cp = strtok(NULL, WHITESPACE); + if (!cp) + { + fprintf(stderr, "%s line %d: missing inet addr.\n", + filename, linenum); + exit(1); + } +#ifdef BROKEN_INET_ADDR + options->listen_addr.s_addr = inet_network(cp); +#else /* BROKEN_INET_ADDR */ + options->listen_addr.s_addr = inet_addr(cp); +#endif /* BROKEN_INET_ADDR */ + break; + + case sHostKeyFile: + charptr = &options->host_key_file; + parse_pathname: + cp = strtok(NULL, WHITESPACE); + if (!cp) + { + fprintf(stderr, "%s line %d: missing file name.\n", + filename, linenum); + exit(1); + } + if (*charptr == NULL) + *charptr = tilde_expand_filename(cp, getuid()); + break; + + case sRandomSeedFile: + charptr = &options->random_seed_file; + goto parse_pathname; + + case sPermitRootLogin: + intptr = &options->permit_root_login; + parse_flag: + cp = strtok(NULL, WHITESPACE); + if (!cp) + { + fprintf(stderr, "%s line %d: missing yes/no argument.\n", + filename, linenum); + exit(1); + } + if (strcmp(cp, "yes") == 0) + value = 1; + else + if (strcmp(cp, "no") == 0) + value = 0; + else + { + fprintf(stderr, "%s line %d: Bad yes/no argument: %s\n", + filename, linenum, cp); + exit(1); + } + if (*intptr == -1) + *intptr = value; + break; + + case sIgnoreRhosts: + intptr = &options->ignore_rhosts; + goto parse_flag; + + case sQuietMode: + intptr = &options->quiet_mode; + goto parse_flag; + + case sFascistLogging: + intptr = &options->fascist_logging; + goto parse_flag; + + case sRhostsAuthentication: + intptr = &options->rhosts_authentication; + goto parse_flag; + + case sRhostsRSAAuthentication: + intptr = &options->rhosts_rsa_authentication; + goto parse_flag; + + case sRSAAuthentication: + intptr = &options->rsa_authentication; + goto parse_flag; + +#ifdef KRB4 + case sKerberosAuthentication: + intptr = &options->kerberos_authentication; + goto parse_flag; + + case sKerberosOrLocalPasswd: + intptr = &options->kerberos_or_local_passwd; + goto parse_flag; +#endif + +#if defined(KRB4) || defined(AFS) + case sKerberosTicketCleanup: + intptr = &options->kerberos_ticket_cleanup; + goto parse_flag; +#endif + +#ifdef KERBEROS_TGT_PASSING + case sKerberosTgtPassing: + intptr = &options->kerberos_tgt_passing; + goto parse_flag; +#endif + +#ifdef AFS + case sAFSTokenPassing: + intptr = &options->afs_token_passing; + goto parse_flag; +#endif + + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; + + case sPrintMotd: + intptr = &options->print_motd; + goto parse_flag; + + case sX11Forwarding: + intptr = &options->x11_forwarding; + goto parse_flag; + + case sStrictModes: + intptr = &options->strict_modes; + goto parse_flag; + + case sKeepAlives: + intptr = &options->keepalives; + goto parse_flag; + + case sEmptyPasswd: + intptr = &options->permit_empty_passwd; + goto parse_flag; + + case sLogFacility: + cp = strtok(NULL, WHITESPACE); + if (!cp) + { + fprintf(stderr, "%s line %d: missing facility name.\n", + filename, linenum); + exit(1); + } + for (i = 0; log_facilities[i].name; i++) + if (strcmp(log_facilities[i].name, cp) == 0) + break; + if (!log_facilities[i].name) + { + fprintf(stderr, "%s line %d: unsupported log facility %s\n", + filename, linenum, cp); + exit(1); + } + if (options->log_facility == (SyslogFacility)(-1)) + options->log_facility = log_facilities[i].facility; + break; + + case sAllowHosts: + while ((cp = strtok(NULL, WHITESPACE))) + { + if (options->num_allow_hosts >= MAX_ALLOW_HOSTS) + { + fprintf(stderr, "%s line %d: too many allow hosts.\n", + filename, linenum); + exit(1); + } + options->allow_hosts[options->num_allow_hosts++] = xstrdup(cp); + } + break; + + case sDenyHosts: + while ((cp = strtok(NULL, WHITESPACE))) + { + if (options->num_deny_hosts >= MAX_DENY_HOSTS) + { + fprintf(stderr, "%s line %d: too many deny hosts.\n", + filename, linenum); + exit(1); + } + options->deny_hosts[options->num_deny_hosts++] = xstrdup(cp); + } + break; + + default: + fprintf(stderr, "%s line %d: Missing handler for opcode %s (%d)\n", + filename, linenum, cp, opcode); + exit(1); + } + if (strtok(NULL, WHITESPACE) != NULL) + { + fprintf(stderr, "%s line %d: garbage at end of line.\n", + filename, linenum); + exit(1); + } + } + fclose(f); +} diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h new file mode 100644 index 00000000000..2807218c1ad --- /dev/null +++ b/usr.bin/ssh/servconf.h @@ -0,0 +1,77 @@ +/* + +servconf.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Mon Aug 21 15:35:03 1995 ylo + +Definitions for server configuration data and for the functions reading it. + +*/ + +/* RCSID("$Id: servconf.h,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); */ + +#ifndef SERVCONF_H +#define SERVCONF_H + +#define MAX_ALLOW_HOSTS 256 /* Max # hosts on allow list. */ +#define MAX_DENY_HOSTS 256 /* Max # hosts on deny list. */ + +typedef struct +{ + int port; /* Port number to listen on. */ + struct in_addr listen_addr; /* Address on which the server listens. */ + char *host_key_file; /* File containing host key. */ + char *random_seed_file; /* File containing random seed. */ + int server_key_bits; /* Size of the server key. */ + int login_grace_time; /* Disconnect if no auth in this time (sec). */ + int key_regeneration_time; /* Server key lifetime (seconds). */ + int permit_root_login; /* If true, permit root login. */ + int ignore_rhosts; /* Ignore .rhosts and .shosts. */ + int quiet_mode; /* If true, don't log anything but fatals. */ + int fascist_logging; /* Perform very verbose logging. */ + int print_motd; /* If true, print /etc/motd. */ + int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */ + int strict_modes; /* If true, require string home dir modes. */ + int keepalives; /* If true, set SO_KEEPALIVE. */ + SyslogFacility log_facility; /* Facility for system logging. */ + int rhosts_authentication; /* If true, permit rhosts authentication. */ + int rhosts_rsa_authentication;/* If true, permit rhosts RSA authentication.*/ + int rsa_authentication; /* If true, permit RSA authentication. */ +#ifdef KRB4 + int kerberos_authentication; /* If true, permit Kerberos authentication. */ + int kerberos_or_local_passwd; +#endif +#if defined(KRB4) || defined(AFS) + int kerberos_ticket_cleanup; /* If true, destroy ticket file on logout. */ +#endif +#ifdef KERBEROS_TGT_PASSING + int kerberos_tgt_passing; /* If true, permit Kerberos tgt passing. */ +#endif +#ifdef AFS + int afs_token_passing; /* If true, permit AFS token passing. */ +#endif + int password_authentication; /* If true, permit password authentication. */ + int permit_empty_passwd; /* If false, do not permit empty passwords. */ + unsigned int num_allow_hosts; + char *allow_hosts[MAX_ALLOW_HOSTS]; + unsigned int num_deny_hosts; + char *deny_hosts[MAX_DENY_HOSTS]; +} ServerOptions; + +/* Initializes the server options to special values that indicate that they + have not yet been set. */ +void initialize_server_options(ServerOptions *options); + +/* Reads the server configuration file. This only sets the values for those + options that have the special value indicating they have not been set. */ +void read_server_config(ServerOptions *options, const char *filename); + +/* Sets values for those values that have not yet been set. */ +void fill_default_server_options(ServerOptions *options); + +#endif /* SERVCONF_H */ diff --git a/usr.bin/ssh/server_config.sample b/usr.bin/ssh/server_config.sample new file mode 100644 index 00000000000..54deaa6251a --- /dev/null +++ b/usr.bin/ssh/server_config.sample @@ -0,0 +1,38 @@ +# This is ssh server systemwide configuration file. + +Port 22 +ListenAddress 0.0.0.0 +HostKey _ETCDIR_/ssh_host_key +RandomSeed _ETCDIR_/ssh_random_seed +ServerKeyBits 768 +LoginGraceTime 600 +KeyRegenerationInterval 3600 +PermitRootLogin yes +# +# Don't read ~/.rhosts and ~/.shosts files +IgnoreRhosts yes +StrictModes yes +QuietMode no +X11Forwarding yes +FascistLogging no +PrintMotd yes +KeepAlive yes +SyslogFacility DAEMON +RhostsAuthentication no +# +# For this to work you will also need host keys in _ETCDIR_/ssh_known_hosts +RhostsRSAAuthentication yes +# +# Changed RSAAuthentication to no/bg +RSAAuthentication no +# +# To enable tunneled clear text passwords, change to yes here! +PasswordAuthentication no +PermitEmptyPasswords no +#KerberosOrLocalPasswd yes + +# Kerberos TGT Passing does only work with the AFS kaserver +#KerberosTgtPassing yes + +# AllowHosts *.our.com friend.other.com +# DenyHosts lowsecurity.theirs.com *.evil.org evil.org diff --git a/usr.bin/ssh/serverloop.c b/usr.bin/ssh/serverloop.c new file mode 100644 index 00000000000..731914d73e1 --- /dev/null +++ b/usr.bin/ssh/serverloop.c @@ -0,0 +1,628 @@ +/* + +serverloop.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sun Sep 10 00:30:37 1995 ylo + +Server main loop for handling the interactive session. + +*/ + +#include "includes.h" +#include "xmalloc.h" +#include "ssh.h" +#include "packet.h" +#include "buffer.h" +#include "servconf.h" +#include "pty.h" + +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 int fdin; /* Descriptor for stdin (for writing) */ +static int fdout; /* Descriptor for stdout (for reading); + May be same number as fdin. */ +static int fderr; /* Descriptor for stderr. May be -1. */ +static long stdin_bytes = 0; /* Number of bytes written to stdin. */ +static long stdout_bytes = 0; /* Number of stdout bytes sent to client. */ +static long stderr_bytes = 0; /* Number of stderr bytes sent to client. */ +static long fdout_bytes = 0; /* Number of stdout bytes read from program. */ +static int stdin_eof = 0; /* EOF message received from client. */ +static int fdout_eof = 0; /* EOF encountered reading from fdout. */ +static int fderr_eof = 0; /* EOF encountered readung from fderr. */ +static int connection_in; /* Connection to client (input). */ +static int connection_out; /* Connection to client (output). */ +static unsigned int buffer_high;/* "Soft" max buffer size. */ +static int max_fd; /* Max file descriptor number for select(). */ + +/* This SIGCHLD kludge is used to detect when the child exits. The server + will exit after that, as soon as forwarded connections have terminated. */ + +static int child_pid; /* Pid of the child. */ +static volatile int child_terminated; /* The child has terminated. */ +static volatile int child_wait_status; /* Status from wait(). */ + +RETSIGTYPE sigchld_handler(int sig) +{ + int wait_pid; + debug("Received SIGCHLD."); + wait_pid = wait((int *)&child_wait_status); + if (wait_pid != -1) + { + if (wait_pid != child_pid) + error("Strange, got SIGCHLD and wait returned pid %d but child is %d", + wait_pid, child_pid); + if (WIFEXITED(child_wait_status) || + WIFSIGNALED(child_wait_status)) + child_terminated = 1; + } + signal(SIGCHLD, sigchld_handler); +} + +/* Process any buffered packets that have been received from the client. */ + +void process_buffered_input_packets() +{ + int type; + char *data; + unsigned int data_len; + int row, col, xpixel, ypixel; + int payload_len; + + /* Process buffered packets from the client. */ + while ((type = packet_read_poll(&payload_len)) != SSH_MSG_NONE) + { + switch (type) + { + case SSH_CMSG_STDIN_DATA: + /* Stdin data from the client. Append it to the buffer. */ + if (fdin == -1) + break; /* Ignore any data if the client has closed stdin. */ + data = packet_get_string(&data_len); + packet_integrity_check(payload_len, (4 + data_len), type); + buffer_append(&stdin_buffer, data, data_len); + memset(data, 0, data_len); + xfree(data); + break; + + case SSH_CMSG_EOF: + /* Eof from the client. The stdin descriptor to the program + will be closed when all buffered data has drained. */ + debug("EOF received for stdin."); + packet_integrity_check(payload_len, 0, type); + stdin_eof = 1; + break; + + case SSH_CMSG_WINDOW_SIZE: + debug("Window change received."); + packet_integrity_check(payload_len, 4*4, type); + row = packet_get_int(); + col = packet_get_int(); + xpixel = packet_get_int(); + ypixel = packet_get_int(); + if (fdin != -1) + pty_change_window_size(fdin, row, col, xpixel, ypixel); + break; + + case SSH_MSG_PORT_OPEN: + debug("Received port open request."); + channel_input_port_open(payload_len); + break; + + case SSH_MSG_CHANNEL_OPEN_CONFIRMATION: + debug("Received channel open confirmation."); + packet_integrity_check(payload_len, 4 + 4, type); + channel_input_open_confirmation(); + break; + + case SSH_MSG_CHANNEL_OPEN_FAILURE: + debug("Received 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: + debug("Received channel close."); + packet_integrity_check(payload_len, 4, type); + channel_input_close(); + break; + + case SSH_MSG_CHANNEL_CLOSE_CONFIRMATION: + debug("Received channel close confirmation."); + packet_integrity_check(payload_len, 4, type); + channel_input_close_confirmation(); + break; + + default: + /* In this phase, any unexpected messages cause a protocol + error. This is to ease debugging; also, since no + confirmations are sent messages, unprocessed unknown + messages could cause strange problems. Any compatible + protocol extensions must be negotiated before entering the + interactive session. */ + packet_disconnect("Protocol error during session: type %d", + type); + } + } +} + +/* Make packets from buffered stderr data, and buffer it for sending + to the client. */ + +void make_packets_from_stderr_data() +{ + int len; + + /* Send buffered stderr data to the client. */ + while (buffer_len(&stderr_buffer) > 0 && + packet_not_very_much_data_to_write()) + { + len = buffer_len(&stderr_buffer); + if (packet_is_interactive()) + { + if (len > 512) + len = 512; + } + else + { + if (len > 32768) + len = 32768; /* Keep the packets at reasonable size. */ + } + packet_start(SSH_SMSG_STDERR_DATA); + packet_put_string(buffer_ptr(&stderr_buffer), len); + packet_send(); + buffer_consume(&stderr_buffer, len); + stderr_bytes += len; + } +} + +/* Make packets from buffered stdout data, and buffer it for sending to the + client. */ + +void make_packets_from_stdout_data() +{ + int len; + + /* Send buffered stdout data to the client. */ + while (buffer_len(&stdout_buffer) > 0 && + packet_not_very_much_data_to_write()) + { + len = buffer_len(&stdout_buffer); + if (packet_is_interactive()) + { + if (len > 512) + len = 512; + } + else + { + if (len > 32768) + len = 32768; /* Keep the packets at reasonable size. */ + } + packet_start(SSH_SMSG_STDOUT_DATA); + packet_put_string(buffer_ptr(&stdout_buffer), len); + packet_send(); + buffer_consume(&stdout_buffer, len); + stdout_bytes += len; + } +} + +/* Sleep in select() until we can do something. This will initialize the + select masks. Upon return, the masks will indicate which descriptors + have data or can accept data. Optionally, a maximum time can be specified + for the duration of the wait (0 = infinite). */ + +void wait_until_can_do_something(fd_set *readset, fd_set *writeset, + unsigned int max_time_milliseconds) +{ + struct timeval tv, *tvp; + int ret; + + /* When select fails we restart from here. */ +retry_select: + + /* Initialize select() masks. */ + FD_ZERO(readset); + + /* Read packets from the client unless we have too much buffered stdin + or channel data. */ + if (buffer_len(&stdin_buffer) < 4096 && + channel_not_very_much_buffered_data()) + FD_SET(connection_in, readset); + + /* If there is not too much data already buffered going to the client, + try to get some more data from the program. */ + if (packet_not_very_much_data_to_write()) + { + if (!fdout_eof) + FD_SET(fdout, readset); + if (!fderr_eof) + FD_SET(fderr, readset); + } + + FD_ZERO(writeset); + + /* Set masks for channel descriptors. */ + channel_prepare_select(readset, writeset); + + /* If we have buffered packet data going to the client, mark that + descriptor. */ + if (packet_have_data_to_write()) + FD_SET(connection_out, writeset); + + /* If we have buffered data, try to write some of that data to the + program. */ + if (fdin != -1 && buffer_len(&stdin_buffer) > 0) + FD_SET(fdin, writeset); + + /* Update the maximum descriptor number if appropriate. */ + if (channel_max_fd() > max_fd) + max_fd = channel_max_fd(); + + /* If child has terminated, read as much as is available and then exit. */ + if (child_terminated) + if (max_time_milliseconds == 0) + max_time_milliseconds = 100; + + if (max_time_milliseconds == 0) + tvp = NULL; + else + { + tv.tv_sec = max_time_milliseconds / 1000; + tv.tv_usec = 1000 * (max_time_milliseconds % 1000); + tvp = &tv; + } + + /* Wait for something to happen, or the timeout to expire. */ + ret = select(max_fd + 1, readset, writeset, NULL, tvp); + + if (ret < 0) + { + if (errno != EINTR) + error("select: %.100s", strerror(errno)); + else + goto retry_select; + } +} + +/* Processes input from the client and the program. Input data is stored + in buffers and processed later. */ + +void process_input(fd_set *readset) +{ + int len; + char buf[16384]; + + /* Read and buffer any input data from the client. */ + if (FD_ISSET(connection_in, readset)) + { + len = read(connection_in, buf, sizeof(buf)); + if (len == 0) + fatal("Connection closed by remote host."); + + /* 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) + fatal("Read error from remote host: %.100s", strerror(errno)); + + /* Buffer any received data. */ + packet_process_incoming(buf, len); + } + + /* Read and buffer any available stdout data from the program. */ + if (!fdout_eof && FD_ISSET(fdout, readset)) + { + len = read(fdout, buf, sizeof(buf)); + if (len <= 0) + fdout_eof = 1; + else + { + buffer_append(&stdout_buffer, buf, len); + fdout_bytes += len; + } + } + + /* Read and buffer any available stderr data from the program. */ + if (!fderr_eof && FD_ISSET(fderr, readset)) + { + len = read(fderr, buf, sizeof(buf)); + if (len <= 0) + fderr_eof = 1; + else + buffer_append(&stderr_buffer, buf, len); + } +} + +/* Sends data from internal buffers to client program stdin. */ + +void process_output(fd_set *writeset) +{ + int len; + + /* Write buffered data to program stdin. */ + if (fdin != -1 && FD_ISSET(fdin, writeset)) + { + len = write(fdin, buffer_ptr(&stdin_buffer), + buffer_len(&stdin_buffer)); + if (len <= 0) + { + shutdown(fdin, 1); /* We will no longer send. */ + fdin = -1; + } + else + { + /* Successful write. Consume the data from the buffer. */ + buffer_consume(&stdin_buffer, len); + /* Update the count of bytes written to the program. */ + stdin_bytes += len; + } + } + + /* Send any buffered packet data to the client. */ + if (FD_ISSET(connection_out, writeset)) + packet_write_poll(); +} + +/* Wait until all buffered output has been sent to the client. + This is used when the program terminates. */ + +void drain_output() +{ + /* Send any buffered stdout data to the client. */ + if (buffer_len(&stdout_buffer) > 0) + { + packet_start(SSH_SMSG_STDOUT_DATA); + packet_put_string(buffer_ptr(&stdout_buffer), + buffer_len(&stdout_buffer)); + packet_send(); + /* Update the count of sent bytes. */ + stdout_bytes += buffer_len(&stdout_buffer); + } + + /* Send any buffered stderr data to the client. */ + if (buffer_len(&stderr_buffer) > 0) + { + packet_start(SSH_SMSG_STDERR_DATA); + packet_put_string(buffer_ptr(&stderr_buffer), + buffer_len(&stderr_buffer)); + packet_send(); + /* Update the count of sent bytes. */ + stderr_bytes += buffer_len(&stderr_buffer); + } + + /* Wait until all buffered data has been written to the client. */ + packet_write_wait(); +} + +/* Performs the interactive session. This handles data transmission between + the client and the program. Note that the notion of stdin, stdout, and + stderr in this function is sort of reversed: this function writes to + stdin (of the child program), and reads from stdout and stderr (of the + child program). */ + +void server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) +{ + int wait_status, wait_pid; /* Status and pid returned by wait(). */ + int waiting_termination = 0; /* Have displayed waiting close message. */ + unsigned int max_time_milliseconds; + unsigned int previous_stdout_buffer_bytes; + unsigned int stdout_buffer_bytes; + int type; + + debug("Entering interactive session."); + + /* Initialize the SIGCHLD kludge. */ + child_pid = pid; + child_terminated = 0; + signal(SIGCHLD, sigchld_handler); + + /* Initialize our global variables. */ + fdin = fdin_arg; + fdout = fdout_arg; + fderr = fderr_arg; + connection_in = packet_get_connection_in(); + connection_out = packet_get_connection_out(); + + previous_stdout_buffer_bytes = 0; + + /* Set approximate I/O buffer size. */ + if (packet_is_interactive()) + buffer_high = 4096; + else + buffer_high = 64 * 1024; + + /* Initialize max_fd to the maximum of the known file descriptors. */ + max_fd = fdin; + if (fdout > max_fd) + max_fd = fdout; + if (fderr != -1 && fderr > max_fd) + max_fd = fderr; + if (connection_in > max_fd) + max_fd = connection_in; + if (connection_out > max_fd) + max_fd = connection_out; + + /* Initialize Initialize buffers. */ + buffer_init(&stdin_buffer); + buffer_init(&stdout_buffer); + buffer_init(&stderr_buffer); + + /* If we have no separate fderr (which is the case when we have a pty - there + we cannot make difference between data sent to stdout and stderr), + indicate that we have seen an EOF from stderr. This way we don\'t + need to check the descriptor everywhere. */ + if (fderr == -1) + fderr_eof = 1; + + /* Main loop of the server for the interactive session mode. */ + for (;;) + { + fd_set readset, writeset; + + /* Process buffered packets from the client. */ + process_buffered_input_packets(); + + /* If we have received eof, and there is no more pending input data, + cause a real eof by closing fdin. */ + if (stdin_eof && fdin != -1 && buffer_len(&stdin_buffer) == 0) + { + shutdown(fdin, 1); /* We will no longer send. */ + fdin = -1; + } + + /* Make packets from buffered stderr data to send to the client. */ + make_packets_from_stderr_data(); + + /* Make packets from buffered stdout data to send to the client. + If there is very little to send, this arranges to not send them + now, but to wait a short while to see if we are getting more data. + This is necessary, as some systems wake up readers from a pty after + each separate character. */ + max_time_milliseconds = 0; + stdout_buffer_bytes = buffer_len(&stdout_buffer); + if (stdout_buffer_bytes != 0 && stdout_buffer_bytes < 256 && + stdout_buffer_bytes != previous_stdout_buffer_bytes) + max_time_milliseconds = 10; /* try again after a while */ + else + make_packets_from_stdout_data(); /* Send it now. */ + previous_stdout_buffer_bytes = buffer_len(&stdout_buffer); + + /* Send channel data to the client. */ + if (packet_not_very_much_data_to_write()) + channel_output_poll(); + + /* Bail out of the loop if the program has closed its output descriptors, + and we have no more data to send to the client, and there is no + pending buffered data. */ + if (fdout_eof && fderr_eof && !packet_have_data_to_write() && + buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) + { + if (!channel_still_open()) + goto quit; + if (!waiting_termination) + { + const char *s = + "Waiting for forwarded connections to terminate...\r\n"; + char *cp; + waiting_termination = 1; + buffer_append(&stderr_buffer, s, strlen(s)); + + /* Display list of open channels. */ + cp = channel_open_message(); + buffer_append(&stderr_buffer, cp, strlen(cp)); + xfree(cp); + } + } + + /* Sleep in select() until we can do something. */ + wait_until_can_do_something(&readset, &writeset, + max_time_milliseconds); + + /* Process any channel events. */ + channel_after_select(&readset, &writeset); + + /* Process input from the client and from program stdout/stderr. */ + process_input(&readset); + + /* Process output to the client and to program stdin. */ + process_output(&writeset); + } + + quit: + /* Cleanup and termination code. */ + + /* Wait until all output has been sent to the client. */ + drain_output(); + + debug("End of interactive session; stdin %ld, stdout (read %ld, sent %ld), stderr %ld bytes.", + stdin_bytes, fdout_bytes, stdout_bytes, stderr_bytes); + + /* Free and clear the buffers. */ + buffer_free(&stdin_buffer); + buffer_free(&stdout_buffer); + buffer_free(&stderr_buffer); + + /* Close the file descriptors. */ + if (fdout != -1) + shutdown(fdout, 0); + fdout = -1; + fdout_eof = 1; + if (fderr != -1) + shutdown(fderr, 0); + fderr = -1; + fderr_eof = 1; + if (fdin != -1) + shutdown(fdin, 1); + fdin = -1; + + /* Stop listening for channels; this removes unix domain sockets. */ + channel_stop_listening(); + + /* Wait for the child to exit. Get its exit status. */ + wait_pid = wait(&wait_status); + if (wait_pid < 0) + { + /* It is possible that the wait was handled by SIGCHLD handler. This + may result in either: this call returning with EINTR, or: this + call returning ECHILD. */ + if (child_terminated) + wait_status = child_wait_status; + else + packet_disconnect("wait: %.100s", strerror(errno)); + } + else + { + /* Check if it matches the process we forked. */ + if (wait_pid != pid) + error("Strange, wait returned pid %d, expected %d", wait_pid, pid); + } + + /* We no longer want our SIGCHLD handler to be called. */ + signal(SIGCHLD, SIG_DFL); + + /* Check if it exited normally. */ + if (WIFEXITED(wait_status)) + { + /* Yes, normal exit. Get exit status and send it to the client. */ + debug("Command exited with status %d.", WEXITSTATUS(wait_status)); + packet_start(SSH_SMSG_EXITSTATUS); + packet_put_int(WEXITSTATUS(wait_status)); + packet_send(); + packet_write_wait(); + + /* Wait for exit confirmation. Note that there might be other + packets coming before it; however, the program has already died + so we just ignore them. The client is supposed to respond with + the confirmation when it receives the exit status. */ + do + { + int plen; + type = packet_read(&plen); + } + while (type != SSH_CMSG_EXIT_CONFIRMATION); + + debug("Received exit confirmation."); + return; + } + + /* Check if the program terminated due to a signal. */ + if (WIFSIGNALED(wait_status)) + packet_disconnect("Command terminated on signal %d.", + WTERMSIG(wait_status)); + + /* Some weird exit cause. Just exit. */ + packet_disconnect("wait returned status %04x.", wait_status); + /*NOTREACHED*/ +} + diff --git a/usr.bin/ssh/ssh-add.1 b/usr.bin/ssh/ssh-add.1 new file mode 100644 index 00000000000..99a1312e2cd --- /dev/null +++ b/usr.bin/ssh/ssh-add.1 @@ -0,0 +1,98 @@ +.\" -*- nroff -*- +.\" +.\" ssh-add.1 +.\" +.\" Author: Tatu Ylonen <ylo@cs.hut.fi> +.\" +.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +.\" All rights reserved +.\" +.\" Created: Sat Apr 22 23:55:14 1995 ylo +.\" +.\" $Id: ssh-add.1,v 1.1 1999/09/26 20:53:37 deraadt Exp $ +.\" +.TH SSH-ADD 1 "November 8, 1995" "SSH" "SSH" + +.SH NAME +ssh-add \- adds identities for the authentication agent + +.SH SYNOPSIS +.B ssh-add +[\c +.B \-l\c +] +[\c +.B \-d\c +] +[\c +.B \-D\c +] +[\c +.B file\c +\&.\|.\|.\|] + +.SH DESCRIPTION +.LP +.B Ssh-add +adds identities to the authentication agent, +.B ssh-agent. +When run without arguments, it adds the file +.IR $HOME/\s+2.\s0ssh/identity ". +Alternative file names can be given on the +command line. If any file requires a passphrase, +.B ssh-add +asks for the passphrase from the user. If the user is using X11, the +passphrase is requested using a small X11 program; otherwise it is +read from the user's tty. (Note: it may be necessary to redirect +stdin from /dev/null to get the passphrase requested using X11.) +.LP +The authentication agent must be running and must be an ancestor of +the current process for +.B ssh-add +to work. + +.SH OPTIONS +.TP 0.5i +.B \-l +Lists all identities currently represented by the agent. +.TP +.B \-d +Instead of adding the identity, removes the identity from the agent. +.TP +.B \-D +Deletes all identities from the agent. + +.SH FILES +.TP +.I \&$HOME/\s+2.\s0ssh/identity +Contains the RSA authentication identity of the user. This file +should not be readable by anyone but the user. It is possible to +specify a passphrase when generating the key; that passphrase will be +used to encrypt the private part of this file. This is the +default file added by +.B ssh-add +when no other files have been specified. +.IP +If +.B ssh-add +needs a passphrase, it will read the passphrase from the current +terminal if it was run from a terminal. If +.B ssh-add +does not have a terminal associated with it but +.SM DISPLAY\s0 +is set, it +will open an X11 window to read the passphrase. This is particularly +useful when calling +.B ssh-add +from a .Xsession or related script. (Note that on some machines it +may be necessary to redirect the input from /dev/null to make this work.) + +.SH AUTHOR +.LP +Tatu Ylonen <ylo@cs.hut.fi> + +.SH SEE ALSO +.BR ssh-agent (1), +.BR ssh-keygen (1), +.BR ssh (1), +.BR sshd (8) diff --git a/usr.bin/ssh/ssh-add.c b/usr.bin/ssh/ssh-add.c new file mode 100644 index 00000000000..99a8ada1c9a --- /dev/null +++ b/usr.bin/ssh/ssh-add.c @@ -0,0 +1,247 @@ +/* + +ssh-add.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Thu Apr 6 00:52:24 1995 ylo + +Adds an identity to the authentication server, or removes an identity. + +*/ + +#include "includes.h" +RCSID("$Id: ssh-add.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); + +#include "randoms.h" +#include "rsa.h" +#include "ssh.h" +#include "xmalloc.h" +#include "authfd.h" + +void delete_file(const char *filename) +{ + RSAPublicKey key; + char *comment; + AuthenticationConnection *ac; + + if (!load_public_key(filename, &key, &comment)) + { + printf("Bad key file %s: %s\n", filename, strerror(errno)); + return; + } + + /* Send the request to the authentication agent. */ + ac = ssh_get_authentication_connection(); + if (!ac) + { + fprintf(stderr, + "Could not open a connection to your authentication agent.\n"); + rsa_clear_public_key(&key); + xfree(comment); + return; + } + if (ssh_remove_identity(ac, &key)) + fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); + else + fprintf(stderr, "Could not remove identity: %s\n", filename); + rsa_clear_public_key(&key); + xfree(comment); + ssh_close_authentication_connection(ac); +} + +void delete_all() +{ + AuthenticationConnection *ac; + + /* Get a connection to the agent. */ + ac = ssh_get_authentication_connection(); + if (!ac) + { + fprintf(stderr, + "Could not open a connection to your authentication agent.\n"); + return; + } + + /* Send a request to remove all identities. */ + if (ssh_remove_all_identities(ac)) + fprintf(stderr, "All identities removed.\n"); + else + fprintf(stderr, "Failed to remove all identitities.\n"); + + /* Close the connection to the agent. */ + ssh_close_authentication_connection(ac); +} + +void add_file(const char *filename) +{ + RSAPrivateKey key; + RSAPublicKey public_key; + AuthenticationConnection *ac; + char *saved_comment, *comment, *pass; + int first; + + if (!load_public_key(filename, &public_key, &saved_comment)) + { + printf("Bad key file %s: %s\n", filename, strerror(errno)); + return; + } + rsa_clear_public_key(&public_key); + + pass = xstrdup(""); + first = 1; + while (!load_private_key(filename, pass, &key, &comment)) + { + char buf[1024]; + FILE *f; + + /* Free the old passphrase. */ + memset(pass, 0, strlen(pass)); + xfree(pass); + + /* Ask for a passphrase. */ + if (getenv("DISPLAY") && !isatty(fileno(stdin))) + { + sprintf(buf, "ssh-askpass '%sEnter passphrase for %.100s'", + first ? "" : "You entered wrong passphrase. ", + saved_comment); + f = popen(buf, "r"); + if (!fgets(buf, sizeof(buf), f)) + { + pclose(f); + xfree(saved_comment); + return; + } + pclose(f); + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + pass = xstrdup(buf); + } + else + { + if (first) + printf("Need passphrase for %s (%s).\n", filename, saved_comment); + else + printf("Bad passphrase.\n"); + pass = read_passphrase("Enter passphrase: ", 1); + if (strcmp(pass, "") == 0) + { + xfree(saved_comment); + xfree(pass); + return; + } + } + first = 0; + } + memset(pass, 0, strlen(pass)); + xfree(pass); + + xfree(saved_comment); + + /* Send the key to the authentication agent. */ + ac = ssh_get_authentication_connection(); + if (!ac) + { + fprintf(stderr, + "Could not open a connection to your authentication agent.\n"); + rsa_clear_private_key(&key); + xfree(comment); + return; + } + if (ssh_add_identity(ac, &key, comment)) + fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); + else + fprintf(stderr, "Could not add identity: %s\n", filename); + rsa_clear_private_key(&key); + xfree(comment); + ssh_close_authentication_connection(ac); +} + +void list_identities() +{ + AuthenticationConnection *ac; + MP_INT e, n; + int bits, status; + char *comment; + int had_identities; + + ac = ssh_get_authentication_connection(); + if (!ac) + { + fprintf(stderr, "Could not connect to authentication server.\n"); + return; + } + mpz_init(&e); + mpz_init(&n); + had_identities = 0; + for (status = ssh_get_first_identity(ac, &bits, &e, &n, &comment); + status; + status = ssh_get_next_identity(ac, &bits, &e, &n, &comment)) + { + had_identities = 1; + printf("%d ", bits); + mpz_out_str(stdout, 10, &e); + printf(" "); + mpz_out_str(stdout, 10, &n); + printf(" %s\n", comment); + xfree(comment); + } + mpz_clear(&e); + mpz_clear(&n); + if (!had_identities) + printf("The agent has no identities.\n"); + ssh_close_authentication_connection(ac); +} + +int main(int ac, char **av) +{ + struct passwd *pw; + char buf[1024]; + int no_files = 1; + int i; + int deleting = 0; + + for (i = 1; i < ac; i++) + { + if (strcmp(av[i], "-l") == 0) + { + list_identities(); + no_files = 0; /* Don't default-add/delete if -l. */ + continue; + } + if (strcmp(av[i], "-d") == 0) + { + deleting = 1; + continue; + } + if (strcmp(av[i], "-D") == 0) + { + delete_all(); + no_files = 0; + continue; + } + no_files = 0; + if (deleting) + delete_file(av[i]); + else + add_file(av[i]); + } + if (no_files) + { + pw = getpwuid(getuid()); + if (!pw) + { + fprintf(stderr, "No user found with uid %d\n", (int)getuid()); + exit(1); + } + sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); + if (deleting) + delete_file(buf); + else + add_file(buf); + } + exit(0); +} diff --git a/usr.bin/ssh/ssh-agent.1 b/usr.bin/ssh/ssh-agent.1 new file mode 100644 index 00000000000..4b396431ae1 --- /dev/null +++ b/usr.bin/ssh/ssh-agent.1 @@ -0,0 +1,113 @@ +.\" -*- nroff -*- +.\" +.\" ssh-agent.1 +.\" +.\" Author: Tatu Ylonen <ylo@cs.hut.fi> +.\" +.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +.\" All rights reserved +.\" +.\" Created: Sat Apr 23 20:10:43 1995 ylo +.\" +.\" $Id: ssh-agent.1,v 1.1 1999/09/26 20:53:37 deraadt Exp $ +.\" +.TH SSH-AGENT 1 "November 8, 1995" "SSH" "SSH" + +.SH NAME +ssh-agent \- authentication agent + +.SH SYNOPSIS +.LP +.B ssh-agent +.I command + +.SH DESCRIPTION +.LP +.B Ssh-agent +is a program to hold authentication private keys. The +idea is that +.B ssh-agent +is started in the beginning of an X-session or a login session, and +all other windows or programs are started as children of the ssh-agent +program (the +.IR command +normally starts X or is the user shell). Programs started under +the agent inherit a connection to the agent, and the agent is +automatically used for RSA authentication when logging to other +machines using +.B ssh. +.LP +The agent initially does not have any private keys. Keys are added +using +.B ssh-add. +When executed without arguments, +.B ssh-add +adds the +.I \&$HOME/\s+2.\s0ssh/identity +file. If the identity has a passphrase, +.B ssh-add +asks for the passphrase (using a small X11 application if running +under X11, or from the terminal if running without X). It then sends +the identity to the agent. Several identities can be stored in the +agent; the agent can automatically use any of these identities. +.B "Ssh-add \-l +displays the identities currently held by the agent. +.LP +The idea is that the agent is run in the user's local PC, laptop, or +terminal. Authentication data need not be stored on any other +machine, and authentication passphrases never go over the network. +However, the connection to the agent is forwarded over +.B ssh +remote logins, and the user can thus use the privileges given by the +identities anywhere in the network in a secure way. +.LP +A connection to the agent is inherited by child programs. +There are two alternative +methods for inheriting the agent. The preferred method is to have an +open file descriptor which is inherited, and have an environment +variable (\fB\s-1SSH_AUTHENTICATION_FD\s0\fR) contain the number of this +descriptor. This restricts access to the authentication agent to only +those programs that are siblings of the agent, and it is fairly +difficult even for root to get unauthorized access to the agent. +.LP +On some machines, an alternative method is used. A unix-domain +socket is created (\fI/tmp/ssh_agent.*\fR), and the name of this +socket is stored in the +.B \s-1SSH_AUTHENTICATION_SOCKET\s0 +environment +variable. The socket is made accessible only to the current user. +This method is easily abused by root or another instance of the same +user. The socket is only used if ssh is unable to find a file +descriptor that would not be closed by shells. +.LP +The agent exits automatically when the command given on the command +line terminates. + +.SH FILES +.TP +.I \&$HOME/\s+2.\s0ssh/identity +Contains the RSA authentication identity of the user. This file +should not be readable by anyone but the user. It is possible to +specify a passphrase when generating the key; that passphrase will be +used to encrypt the private part of this file. This file +is not used by +.B ssh-agent, +but is normally added to the agent using +.B ssh-add +at login time. +.TP +.I \&/tmp/ssh_agent.<pid> +Unix-domain sockets used to contain the connection to the +authentication agent. These sockets should only be readable by the +owner. The sockets should get automatically removed when the agent +exits. + +.SH AUTHOR +.LP +Tatu Ylonen <ylo@cs.hut.fi> + +.SH SEE ALSO +.BR ssh-add (1), +.BR ssh-keygen (1), +.BR ssh (1), +.BR sshd (8) diff --git a/usr.bin/ssh/ssh-agent.c b/usr.bin/ssh/ssh-agent.c new file mode 100644 index 00000000000..f038178ed5f --- /dev/null +++ b/usr.bin/ssh/ssh-agent.c @@ -0,0 +1,629 @@ +/* + +ssh-agent.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Wed Mar 29 03:46:59 1995 ylo + +The authentication agent program. + +*/ + +#include "includes.h" +RCSID("$Id: ssh-agent.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); + +#include "ssh.h" +#include "rsa.h" +#include "randoms.h" +#include "authfd.h" +#include "buffer.h" +#include "bufaux.h" +#include "xmalloc.h" +#include "packet.h" +#include "ssh_md5.h" +#include "getput.h" +#include "mpaux.h" + +typedef struct +{ + int fd; + enum { AUTH_UNUSED, AUTH_FD, AUTH_SOCKET, AUTH_SOCKET_FD, + AUTH_CONNECTION } type; + Buffer input; + Buffer output; +} SocketEntry; + +unsigned int sockets_alloc = 0; +SocketEntry *sockets = NULL; + +typedef struct +{ + RSAPrivateKey key; + char *comment; +} Identity; + +unsigned int num_identities = 0; +Identity *identities = NULL; + +int max_fd = 0; + +void process_request_identity(SocketEntry *e) +{ + Buffer msg; + int i; + + buffer_init(&msg); + buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER); + buffer_put_int(&msg, num_identities); + for (i = 0; i < num_identities; i++) + { + buffer_put_int(&msg, identities[i].key.bits); + buffer_put_mp_int(&msg, &identities[i].key.e); + buffer_put_mp_int(&msg, &identities[i].key.n); + buffer_put_string(&msg, identities[i].comment, + strlen(identities[i].comment)); + } + buffer_put_int(&e->output, buffer_len(&msg)); + buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); + buffer_free(&msg); +} + +void process_authentication_challenge(SocketEntry *e) +{ + int i, pub_bits; + MP_INT pub_e, pub_n, challenge; + Buffer msg; + struct MD5Context md; + unsigned char buf[32], mdbuf[16], session_id[16]; + unsigned int response_type; + + buffer_init(&msg); + mpz_init(&pub_e); + mpz_init(&pub_n); + mpz_init(&challenge); + pub_bits = buffer_get_int(&e->input); + buffer_get_mp_int(&e->input, &pub_e); + buffer_get_mp_int(&e->input, &pub_n); + buffer_get_mp_int(&e->input, &challenge); + if (buffer_len(&e->input) == 0) + { + /* Compatibility code for old servers. */ + memset(session_id, 0, 16); + response_type = 0; + } + else + { + /* New code. */ + buffer_get(&e->input, (char *)session_id, 16); + response_type = buffer_get_int(&e->input); + } + for (i = 0; i < num_identities; i++) + if (pub_bits == identities[i].key.bits && + mpz_cmp(&pub_e, &identities[i].key.e) == 0 && + mpz_cmp(&pub_n, &identities[i].key.n) == 0) + { + /* Decrypt the challenge using the private key. */ + rsa_private_decrypt(&challenge, &challenge, &identities[i].key); + + /* Compute the desired response. */ + switch (response_type) + { + case 0: /* As of protocol 1.0 */ + /* This response type is no longer supported. */ + log("Compatibility with ssh protocol 1.0 no longer supported."); + buffer_put_char(&msg, SSH_AGENT_FAILURE); + goto send; + + case 1: /* As of protocol 1.1 */ + /* The response is MD5 of decrypted challenge plus session id. */ + mp_linearize_msb_first(buf, 32, &challenge); + MD5Init(&md); + MD5Update(&md, buf, 32); + MD5Update(&md, session_id, 16); + MD5Final(mdbuf, &md); + break; + + default: + fatal("process_authentication_challenge: bad response_type %d", + response_type); + break; + } + + /* Send the response. */ + buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE); + for (i = 0; i < 16; i++) + buffer_put_char(&msg, mdbuf[i]); + + goto send; + } + /* Unknown identity. Send failure. */ + buffer_put_char(&msg, SSH_AGENT_FAILURE); + send: + buffer_put_int(&e->output, buffer_len(&msg)); + buffer_append(&e->output, buffer_ptr(&msg), + buffer_len(&msg)); + buffer_free(&msg); + mpz_clear(&pub_e); + mpz_clear(&pub_n); + mpz_clear(&challenge); +} + +void process_remove_identity(SocketEntry *e) +{ + unsigned int bits; + MP_INT dummy, n; + unsigned int i; + + mpz_init(&dummy); + mpz_init(&n); + + /* Get the key from the packet. */ + bits = buffer_get_int(&e->input); + buffer_get_mp_int(&e->input, &dummy); + buffer_get_mp_int(&e->input, &n); + + /* Check if we have the key. */ + for (i = 0; i < num_identities; i++) + if (mpz_cmp(&identities[i].key.n, &n) == 0) + { + /* We have this key. Free the old key. Since we don\'t want to leave + empty slots in the middle of the array, we actually free the + key there and copy data from the last entry. */ + rsa_clear_private_key(&identities[i].key); + xfree(identities[i].comment); + if (i < num_identities - 1) + identities[i] = identities[num_identities - 1]; + num_identities--; + mpz_clear(&dummy); + mpz_clear(&n); + + /* Send success. */ + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_SUCCESS); + return; + } + /* We did not have the key. */ + mpz_clear(&dummy); + mpz_clear(&n); + + /* Send failure. */ + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_FAILURE); +} + +/* Removes all identities from the agent. */ + +void process_remove_all_identities(SocketEntry *e) +{ + unsigned int i; + + /* Loop over all identities and clear the keys. */ + for (i = 0; i < num_identities; i++) + { + rsa_clear_private_key(&identities[i].key); + xfree(identities[i].comment); + } + + /* Mark that there are no identities. */ + num_identities = 0; + + /* Send success. */ + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_SUCCESS); + return; +} + +/* Adds an identity to the agent. */ + +void process_add_identity(SocketEntry *e) +{ + RSAPrivateKey *k; + int i; + + if (num_identities == 0) + identities = xmalloc(sizeof(Identity)); + else + identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity)); + k = &identities[num_identities].key; + k->bits = buffer_get_int(&e->input); + mpz_init(&k->n); + buffer_get_mp_int(&e->input, &k->n); + mpz_init(&k->e); + buffer_get_mp_int(&e->input, &k->e); + mpz_init(&k->d); + buffer_get_mp_int(&e->input, &k->d); + mpz_init(&k->u); + buffer_get_mp_int(&e->input, &k->u); + mpz_init(&k->p); + buffer_get_mp_int(&e->input, &k->p); + mpz_init(&k->q); + buffer_get_mp_int(&e->input, &k->q); + identities[num_identities].comment = buffer_get_string(&e->input, NULL); + + /* Check if we already have the key. */ + for (i = 0; i < num_identities; i++) + if (mpz_cmp(&identities[i].key.n, &k->n) == 0) + { + /* We already have this key. Clear and free the new data and + return success. */ + rsa_clear_private_key(k); + xfree(identities[num_identities].comment); + + /* Send success. */ + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_SUCCESS); + return; + } + + /* Increment the number of identities. */ + num_identities++; + + /* Send a success message. */ + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_SUCCESS); +} + +void process_message(SocketEntry *e) +{ + unsigned int msg_len; + unsigned int type; + unsigned char *cp; + if (buffer_len(&e->input) < 5) + return; /* Incomplete message. */ + cp = (unsigned char *)buffer_ptr(&e->input); + msg_len = GET_32BIT(cp); + if (msg_len > 256 * 1024) + { + shutdown(e->fd, 2); + close(e->fd); + e->type = AUTH_UNUSED; + return; + } + if (buffer_len(&e->input) < msg_len + 4) + return; + buffer_consume(&e->input, 4); + type = buffer_get_char(&e->input); + switch (type) + { + case SSH_AGENTC_REQUEST_RSA_IDENTITIES: + process_request_identity(e); + break; + case SSH_AGENTC_RSA_CHALLENGE: + process_authentication_challenge(e); + break; + case SSH_AGENTC_ADD_RSA_IDENTITY: + process_add_identity(e); + break; + case SSH_AGENTC_REMOVE_RSA_IDENTITY: + process_remove_identity(e); + break; + case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES: + process_remove_all_identities(e); + break; + default: + /* Unknown message. Respond with failure. */ + error("Unknown message %d", type); + buffer_clear(&e->input); + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_FAILURE); + break; + } +} + +void new_socket(int type, int fd) +{ + unsigned int i, old_alloc; +#if defined(O_NONBLOCK) && !defined(O_NONBLOCK_BROKEN) + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + error("fcntl O_NONBLOCK: %s", strerror(errno)); +#else /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + if (fcntl(fd, F_SETFL, O_NDELAY) < 0) + error("fcntl O_NDELAY: %s", strerror(errno)); +#endif /* O_NONBLOCK && !O_NONBLOCK_BROKEN */ + + if (fd > max_fd) + max_fd = fd; + + for (i = 0; i < sockets_alloc; i++) + if (sockets[i].type == AUTH_UNUSED) + { + sockets[i].fd = fd; + sockets[i].type = type; + buffer_init(&sockets[i].input); + buffer_init(&sockets[i].output); + return; + } + old_alloc = sockets_alloc; + sockets_alloc += 10; + if (sockets) + sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0])); + else + sockets = xmalloc(sockets_alloc * sizeof(sockets[0])); + for (i = old_alloc; i < sockets_alloc; i++) + sockets[i].type = AUTH_UNUSED; + sockets[old_alloc].type = type; + sockets[old_alloc].fd = fd; + buffer_init(&sockets[old_alloc].input); + buffer_init(&sockets[old_alloc].output); +} + +void prepare_select(fd_set *readset, fd_set *writeset) +{ + unsigned int i; + for (i = 0; i < sockets_alloc; i++) + switch (sockets[i].type) + { + case AUTH_FD: + case AUTH_CONNECTION: + case AUTH_SOCKET: + case AUTH_SOCKET_FD: + FD_SET(sockets[i].fd, readset); + if (buffer_len(&sockets[i].output) > 0) + FD_SET(sockets[i].fd, writeset); + break; + case AUTH_UNUSED: + break; + default: + fatal("Unknown socket type %d", sockets[i].type); + break; + } +} + +void after_select(fd_set *readset, fd_set *writeset) +{ + unsigned int i; + int len, sock, port; + char buf[1024]; + struct sockaddr_in sin; + struct sockaddr_un sunaddr; + + for (i = 0; i < sockets_alloc; i++) + switch (sockets[i].type) + { + case AUTH_UNUSED: + break; + case AUTH_FD: + if (FD_ISSET(sockets[i].fd, readset)) + { + len = recv(sockets[i].fd, buf, sizeof(buf), 0); + if (len <= 0) + { /* All instances of the other side have been closed. */ + log("Authentication agent exiting."); + exit(0); + } + process_auth_fd_input: + if (len != 3 || (unsigned char)buf[0] != SSH_AUTHFD_CONNECT) + break; /* Incorrect message; ignore it. */ + /* It is a connection request message. */ + port = (unsigned char)buf[1] * 256 + (unsigned char)buf[2]; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(0x7f000001); /* localhost */ + sin.sin_port = htons(port); + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + { + perror("socket"); + break; + } + if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) + { + perror("connecting to port requested in authfd message"); + close(sock); + break; + } + new_socket(AUTH_CONNECTION, sock); + } + break; + case AUTH_SOCKET: + if (FD_ISSET(sockets[i].fd, readset)) + { + len = sizeof(sunaddr); + sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len); + if (sock < 0) + { + perror("accept from AUTH_SOCKET"); + break; + } + new_socket(AUTH_SOCKET_FD, sock); + } + break; + case AUTH_SOCKET_FD: + if (FD_ISSET(sockets[i].fd, readset)) + { + len = recv(sockets[i].fd, buf, sizeof(buf), 0); + if (len <= 0) + { /* The other side has closed the socket. */ + shutdown(sockets[i].fd, 2); + close(sockets[i].fd); + sockets[i].type = AUTH_UNUSED; + break; + } + goto process_auth_fd_input; + } + break; + case AUTH_CONNECTION: + if (buffer_len(&sockets[i].output) > 0 && + FD_ISSET(sockets[i].fd, writeset)) + { + len = write(sockets[i].fd, buffer_ptr(&sockets[i].output), + buffer_len(&sockets[i].output)); + if (len <= 0) + { + shutdown(sockets[i].fd, 2); + close(sockets[i].fd); + sockets[i].type = AUTH_UNUSED; + break; + } + buffer_consume(&sockets[i].output, len); + } + if (FD_ISSET(sockets[i].fd, readset)) + { + len = read(sockets[i].fd, buf, sizeof(buf)); + if (len <= 0) + { + shutdown(sockets[i].fd, 2); + close(sockets[i].fd); + sockets[i].type = AUTH_UNUSED; + break; + } + buffer_append(&sockets[i].input, buf, len); + process_message(&sockets[i]); + } + break; + default: + fatal("Unknown type %d", sockets[i].type); + } +} + +int parent_pid = -1; +char socket_name[1024]; + +RETSIGTYPE check_parent_exists(int sig) +{ + if (kill(parent_pid, 0) < 0) + { + remove(socket_name); + /* printf("Parent has died - Authentication agent exiting.\n"); */ + exit(1); + } + signal(SIGALRM, check_parent_exists); + alarm(10); +} + +int main(int ac, char **av) +{ + fd_set readset, writeset; + char buf[1024]; + int pfd; + int sock; + struct sockaddr_un sunaddr; + + int sockets[2], i; + int *dups; + + if (ac < 2) + { + fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION); + fprintf(stderr, "Usage: %s command\n", av[0]); + exit(1); + } + + pfd = get_permanent_fd(NULL); + if (pfd < 0) + { + /* The agent uses SSH_AUTHENTICATION_SOCKET. */ + + parent_pid = getpid(); + + sprintf(socket_name, SSH_AGENT_SOCKET, parent_pid); + + /* Fork, and have the parent execute the command. The child continues as + the authentication agent. */ + if (fork() != 0) + { /* Parent - execute the given command. */ + sprintf(buf, "SSH_AUTHENTICATION_SOCKET=%s", socket_name); + putenv(buf); + execvp(av[1], av + 1); + perror(av[1]); + exit(1); + } + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + perror("socket"); + exit(1); + } + memset(&sunaddr, 0, sizeof(sunaddr)); + sunaddr.sun_family = AF_UNIX; + strncpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path)); + if (bind(sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)) < 0) + { + perror("bind"); + exit(1); + } + if (chmod(socket_name, 0700) < 0) + { + perror("chmod"); + exit(1); + } + if (listen(sock, 5) < 0) + { + perror("listen"); + exit(1); + } + new_socket(AUTH_SOCKET, sock); + signal(SIGALRM, check_parent_exists); + alarm(10); + } + else + { + /* The agent uses SSH_AUTHENTICATION_FD. */ + int cnt, newfd; + + dups = xmalloc(sizeof (int) * (1 + pfd)); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) + { + perror("socketpair"); + exit(1); + } + + /* Dup some descriptors to get the authentication fd to pfd, + because some shells arbitrarily close descriptors below that. + Don't use dup2 because maybe some systems don't have it?? */ + for (cnt = 0;; cnt++) { + if ((dups[cnt] = dup(0)) < 0) + fatal("auth_input_request_forwarding: dup failed"); + if (dups[cnt] == pfd) + break; + } + close(dups[cnt]); + + /* Move the file descriptor we pass to children up high where + the shell won't close it. */ + newfd = dup(sockets[1]); + if (newfd != pfd) + fatal("auth_input_request_forwarding: dup didn't return %d.", pfd); + close(sockets[1]); + sockets[1] = newfd; + /* Close duped descriptors. */ + for (i = 0; i < cnt; i++) + close(dups[i]); + free(dups); + + if (fork() != 0) + { /* Parent - execute the given command. */ + close(sockets[0]); + sprintf(buf, "SSH_AUTHENTICATION_FD=%d", sockets[1]); + putenv(buf); + execvp(av[1], av + 1); + perror(av[1]); + exit(1); + } + close(sockets[1]); + new_socket(AUTH_FD, sockets[0]); + } + + signal(SIGINT, SIG_IGN); + while (1) + { + FD_ZERO(&readset); + FD_ZERO(&writeset); + prepare_select(&readset, &writeset); + if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) + { + if (errno == EINTR) + continue; + perror("select"); + exit(1); + } + after_select(&readset, &writeset); + } + /*NOTREACHED*/ +} diff --git a/usr.bin/ssh/ssh-askpass.wish b/usr.bin/ssh/ssh-askpass.wish new file mode 100644 index 00000000000..5e8d3d897d3 --- /dev/null +++ b/usr.bin/ssh/ssh-askpass.wish @@ -0,0 +1,48 @@ +# This file (ssh-askpass.wish) will be used to create ssh-askpass by-*- tcl -*- +# prepending the header line that executes wish. +# +# $Id: ssh-askpass.wish,v 1.1 1999/09/26 20:53:37 deraadt Exp $ +# + +global result + +wm title . "Authentication Password Entry" + +# Use the first argument as a prompt (if given). +if {$argv==""} { + label .header -text "Please enter your authentication password" +} { + label .header -text "[lindex $argv 0]" +} + +entry .pass -relief sunken -textvariable password +set bgcolor [lindex [.pass configure -bg] 3] +.pass configure -fg $bgcolor -selectforeground $bgcolor \ + -selectbackground $bgcolor + +bind .pass <Return> { set result ok } +frame .b +frame .b.ok_f -borderwidth 2 -relief sunken +button .b.ok -text OK -width 6 -command { set result ok } +button .b.cancel -text Cancel -width 6 -command { set result cancel } +pack .b.ok -in .b.ok_f -padx 2 -pady 2 +pack .b.ok_f -side left -padx 5m -pady 3m +pack .b.cancel -side right -padx 5m -pady 3m +pack .header .pass .b +wm protocol . WM_DELETE_WINDOW { set result cancel } + +set old_focus [focus] +grab set . +focus .pass + +set result "none" + +while {"$result" == "none"} { + tkwait variable result +} + +if {$old_focus!=""} { + focus $old_focus +} + +if {"$result" == "ok"} {puts "$password"; exit 0} {exit 1} diff --git a/usr.bin/ssh/ssh-keygen.1 b/usr.bin/ssh/ssh-keygen.1 new file mode 100644 index 00000000000..2bf44eec33c --- /dev/null +++ b/usr.bin/ssh/ssh-keygen.1 @@ -0,0 +1,143 @@ +.\" -*- nroff -*- +.\" +.\" ssh-keygen.1 +.\" +.\" Author: Tatu Ylonen <ylo@cs.hut.fi> +.\" +.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +.\" All rights reserved +.\" +.\" Created: Sat Apr 22 23:55:14 1995 ylo +.\" +.\" $Id: ssh-keygen.1,v 1.1 1999/09/26 20:53:37 deraadt Exp $ +.\" +.TH SSH-KEYGEN 1 "November 8, 1995" "SSH" "SSH" + +.SH NAME +ssh-keygen \- authentication key generation + +.SH SYNOPSIS +.LP +.B ssh-keygen +[\c +.BI \-b \ bits\c +] +[\c +.BI \-N \ new_passphrase\c +] +[\c +.BI \-C \ comment\c +] + +.B "ssh-keygen \-p +[\c +.BI \-P \ old_passphrase\c +] +[\c +.BI \-N \ new_passphrase\c +] + +.B "ssh-keygen \-c +[\c +.BI \-P \ passphrase\c +] +[\c +.BI \-C \ comment\c +] + +.SH DESCRIPTION +.LP +.B Ssh-keygen +generates and manages authentication keys for +.BR ssh (1). +Normally each user wishing to use +.B ssh +with RSA authentication runs this once to create the authentication +key in +.IR \&$HOME/\s+2.\s0ssh/identity ". +Additionally, the system administrator may use this to generate host keys. +.LP +Normally this program generates the key and asks for a file in which +to store the private key. The public key is stored in a file with the +same name but ".pub" appended. The program also asks for a +passphrase. The passphrase may be empty to indicate no passphrase +(host keys must have empty passphrase), or it may be a string of +arbitrary length. Good passphrases are 10-30 characters long and are +not simple sentences or otherwise easily guessable (English +prose has only 1-2 bits of entropy per word, and provides very bad +passphrases). The passphrase can be changed later by using the +.B \-p +option. +.LP +There is no way to recover a lost passphrase. If the passphrase is +lost or forgotten, you will have to generate a new key and copy the +corresponding public key to other machines. +.LP +There is also a comment field in the key file that is only for +convenience to the user to help identify the key. The comment can +tell what the key is for, or whatever is useful. The comment is +initialized to user@host when the key is created, but can be changed +using the +.B \-c +option. + +.SH OPTIONS +.TP 0.6i +.BI \-b \ bits +Specifies the number of bits in the key to create. Minimum is 512 +bits. Generally 1024 bits is considered sufficient, and key sizes +above that no longer improve security but make things slower. The +default is 1024 bits. +.TP +.B \-c +Requests changing the comment in the private and public key files. +The program will prompt for the file containing the private keys, for +passphrase if the key has one, and for the new comment. +.TP +.B \-p +Requests changing the passphrase of a private key file instead of +creating a new private key. The program will prompt for the file +containing the private key, for the old passphrase, and twice for the +new passphrase. +.TP +.B \-C +Provides the new comment. +.TP +.B \-N +Provides the new passphrase. +.TP +.B \-P +Provides the (old) passphrase. + +.SH FILES +.TP 0.6i +.I \&$HOME/\s+2.\s0ssh/random_seed +Used for seeding the random number generator. This file should not be +readable by anyone but the user. This file is created the first time +the program is run, and is updated every time. +.TP +.I \&$HOME/\s+2.\s0ssh/identity +Contains the RSA authentication identity of the user. This file +should not be readable by anyone but the user. It is possible to +specify a passphrase when generating the key; that passphrase will be +used to encrypt the private part of this file using IDEA. This file +is not automatically accessed by +.BR ssh-keygen ", +but it is offered as the default file for the private key. +.TP +.I \&$HOME/\s+2.\s0ssh/identity.pub +Contains the public key for authentication. The contents of this file +should be added to \f4$HOME/\s+2.\s0ssh/authorized_keys\f1 on all machines +where you wish to log in using RSA authentication. There is no +need to keep the contents of this file secret. + +.SH AUTHOR +.LP +Tatu Ylonen <ylo@cs.hut.fi> + +.SH SEE ALSO +.LP +.BR ssh (1), +.BR sshd (8), +.BR ssh-agent (1), +.BR ssh-add (1) diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c new file mode 100644 index 00000000000..0ff98cde1cc --- /dev/null +++ b/usr.bin/ssh/ssh-keygen.c @@ -0,0 +1,552 @@ +/* + +ssh-keygen.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Mon Mar 27 02:26:40 1995 ylo + +Identity and host key generation and maintenance. + +*/ + +#include "includes.h" +RCSID("$Id: ssh-keygen.c,v 1.1 1999/09/26 20:53:37 deraadt Exp $"); + +#ifndef HAVE_GETHOSTNAME +#include <sys/utsname.h> +#endif +#include "randoms.h" +#include "rsa.h" +#include "ssh.h" +#include "xmalloc.h" + +/* Generated private key. */ +RSAPrivateKey private_key; + +/* Generated public key. */ +RSAPublicKey public_key; + +/* Random number generator state. */ +RandomState state; + +/* Number of bits in the RSA key. This value can be changed on the command + line. */ +int bits = 1024; + +/* Flag indicating that we just want to change the passphrase. This can be + set on the command line. */ +int change_passphrase = 0; + +/* Flag indicating that we just want to change the comment. This can be set + on the command line. */ +int change_comment = 0; + +/* This is set to the identity file name if given on the command line. */ +char *identity_file = NULL; + +/* This is set to the passphrase if given on the command line. */ +char *identity_passphrase = NULL; + +/* This is set to the new passphrase if given on the command line. */ +char *identity_new_passphrase = NULL; + +/* This is set to the new comment if given on the command line. */ +char *identity_comment = NULL; + +/* Perform changing a passphrase. The argument is the passwd structure + for the current user. */ + +void do_change_passphrase(struct passwd *pw) +{ + char buf[1024], *comment; + RSAPrivateKey private_key; + char *old_passphrase, *passphrase1, *passphrase2; + struct stat st; + + /* Read key file name. */ + if (identity_file != NULL) + { + strncpy(buf, identity_file, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + } + else + { + printf("Enter file in which the key is ($HOME/%s): ", + SSH_CLIENT_IDENTITY); + fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) + exit(1); + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + if (strcmp(buf, "") == 0) + sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); + } + + /* Check if the file exists. */ + if (stat(buf, &st) < 0) + { + perror(buf); + exit(1); + } + + /* Try to load the public key from the file the verify that it is + readable and of the proper format. */ + if (!load_public_key(buf, &public_key, NULL)) + { + printf("%s is not a valid key file.\n", buf); + exit(1); + } + /* Clear the public key since we are just about to load the whole file. */ + rsa_clear_public_key(&public_key); + + /* Try to load the file with empty passphrase. */ + if (!load_private_key(buf, "", &private_key, &comment)) + { + /* Read passphrase from the user. */ + if (identity_passphrase) + old_passphrase = xstrdup(identity_passphrase); + else + old_passphrase = read_passphrase("Enter old passphrase: ", 1); + /* Try to load using the passphrase. */ + if (!load_private_key(buf, old_passphrase, &private_key, &comment)) + { + memset(old_passphrase, 0, strlen(old_passphrase)); + xfree(old_passphrase); + printf("Bad passphrase.\n"); + exit(1); + } + /* Destroy the passphrase. */ + memset(old_passphrase, 0, strlen(old_passphrase)); + xfree(old_passphrase); + } + printf("Key has comment '%s'\n", comment); + + /* Ask the new passphrase (twice). */ + if (identity_new_passphrase) + { + passphrase1 = xstrdup(identity_new_passphrase); + passphrase2 = NULL; + } + else + { + passphrase1 = + read_passphrase("Enter new passphrase (empty for no passphrase): ", 1); + passphrase2 = read_passphrase("Enter same passphrase again: ", 1); + + /* Verify that they are the same. */ + if (strcmp(passphrase1, passphrase2) != 0) + { + memset(passphrase1, 0, strlen(passphrase1)); + memset(passphrase2, 0, strlen(passphrase2)); + xfree(passphrase1); + xfree(passphrase2); + printf("Pass phrases do not match. Try again.\n"); + exit(1); + } + /* Destroy the other copy. */ + memset(passphrase2, 0, strlen(passphrase2)); + xfree(passphrase2); + } + + /* Save the file using the new passphrase. */ + if (!save_private_key(buf, passphrase1, &private_key, comment, &state)) + { + printf("Saving the key failed: %s: %s.\n", + buf, strerror(errno)); + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + rsa_clear_private_key(&private_key); + xfree(comment); + exit(1); + } + /* Destroy the passphrase and the copy of the key in memory. */ + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + rsa_clear_private_key(&private_key); + xfree(comment); + + printf("Your identification has been saved with the new passphrase.\n"); + exit(0); +} + +/* Change the comment of a private key file. */ + +void do_change_comment(struct passwd *pw) +{ + char buf[1024], new_comment[1024], *comment; + RSAPrivateKey private_key; + char *passphrase; + struct stat st; + FILE *f; + + /* Read key file name. */ + if (identity_file) + { + strncpy(buf, identity_file, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + } + else + { + printf("Enter file in which the key is ($HOME/%s): ", + SSH_CLIENT_IDENTITY); + fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) + exit(1); + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + if (strcmp(buf, "") == 0) + sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); + } + + /* Check if the file exists. */ + if (stat(buf, &st) < 0) + { + perror(buf); + exit(1); + } + + /* Try to load the public key from the file the verify that it is + readable and of the proper format. */ + if (!load_public_key(buf, &public_key, NULL)) + { + printf("%s is not a valid key file.\n", buf); + exit(1); + } + + /* Try to load the file with empty passphrase. */ + if (load_private_key(buf, "", &private_key, &comment)) + passphrase = xstrdup(""); + else + { + /* Read passphrase from the user. */ + if (identity_passphrase) + passphrase = xstrdup(identity_passphrase); + else + if (identity_new_passphrase) + passphrase = xstrdup(identity_new_passphrase); + else + passphrase = read_passphrase("Enter passphrase: ", 1); + /* Try to load using the passphrase. */ + if (!load_private_key(buf, passphrase, &private_key, &comment)) + { + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + printf("Bad passphrase.\n"); + exit(1); + } + } + printf("Key now has comment '%s'\n", comment); + + if (identity_comment) + { + strncpy(new_comment, identity_comment, sizeof(new_comment)); + new_comment[sizeof(new_comment) - 1] = '\0'; + } + else + { + printf("Enter new comment: "); + fflush(stdout); + if (!fgets(new_comment, sizeof(new_comment), stdin)) + { + memset(passphrase, 0, strlen(passphrase)); + rsa_clear_private_key(&private_key); + exit(1); + } + + /* Remove terminating newline from comment. */ + if (strchr(new_comment, '\n')) + *strchr(new_comment, '\n') = 0; + } + + /* Save the file using the new passphrase. */ + if (!save_private_key(buf, passphrase, &private_key, new_comment, + &state)) + { + printf("Saving the key failed: %s: %s.\n", + buf, strerror(errno)); + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + rsa_clear_private_key(&private_key); + xfree(comment); + exit(1); + } + + /* Destroy the passphrase and the private key in memory. */ + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + rsa_clear_private_key(&private_key); + + /* Save the public key in text format in a file with the same name but + .pub appended. */ + strcat(buf, ".pub"); + f = fopen(buf, "w"); + if (!f) + { + printf("Could not save your public key in %s\n", buf); + exit(1); + } + fprintf(f, "%d ", public_key.bits); + mpz_out_str(f, 10, &public_key.e); + fprintf(f, " "); + mpz_out_str(f, 10, &public_key.n); + fprintf(f, " %s\n", new_comment); + fclose(f); + + xfree(comment); + + printf("The comment in your key file has been changed.\n"); + exit(0); +} + +/* Main program for key management. */ + +int main(int ac, char **av) +{ + char buf[16384], buf2[1024], *passphrase1, *passphrase2; + struct passwd *pw; + int opt; + struct stat st; + FILE *f; +#ifdef HAVE_GETHOSTNAME + char hostname[257]; +#else + struct utsname uts; +#endif + extern int optind; + extern char *optarg; + + /* Get user\'s passwd structure. We need this for the home directory. */ + pw = getpwuid(getuid()); + if (!pw) + { + printf("You don't exist, go away!\n"); + exit(1); + } + + /* Create ~/.ssh directory if it doesn\'t already exist. */ + sprintf(buf, "%s/%s", pw->pw_dir, SSH_USER_DIR); + if (stat(buf, &st) < 0) + if (mkdir(buf, 0755) < 0) + error("Could not create directory '%s'.", buf); + + /* Parse command line arguments. */ + while ((opt = getopt(ac, av, "pcb:f:P:N:C:")) != EOF) + { + switch (opt) + { + case 'b': + bits = atoi(optarg); + if (bits < 512 || bits > 32768) + { + printf("Bits has bad value.\n"); + exit(1); + } + break; + + case 'p': + change_passphrase = 1; + break; + + case 'c': + change_comment = 1; + break; + + case 'f': + identity_file = optarg; + break; + + case 'P': + identity_passphrase = optarg; + break; + + case 'N': + identity_new_passphrase = optarg; + break; + + case 'C': + identity_comment = optarg; + break; + + case '?': + default: + printf("ssh-keygen version %s\n", SSH_VERSION); + printf("Usage: %s [-b bits] [-p] [-c] [-f file] [-P pass] [-N new-pass] [-C comment]\n", av[0]); + exit(1); + } + } + if (optind < ac) + { + printf("Too many arguments.\n"); + exit(1); + } + if (change_passphrase && change_comment) + { + printf("Can only have one of -p and -c.\n"); + exit(1); + } + + /* If the user requested to change the passphrase, do it now. This + function never returns. */ + if (change_passphrase) + do_change_passphrase(pw); + + /* If the user requested to change the comment, do it now. This function + never returns. */ + if (change_comment) + do_change_comment(pw); + + /* Initialize random number generator. This may take a while if the + user has no seed file, so display a message to the user. */ + printf("Initializing random number generator...\n"); + sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_SEEDFILE); + random_initialize(&state, buf); + + /* Save random seed so we don\'t need to do all that time-consuming + environmental noise collection the next time. */ + random_save(&state, buf); + + /* Generate the rsa key pair. */ + rsa_generate_key(&private_key, &public_key, &state, bits); + + /* Save the state again, just to remove any fear that the previous state + could be used to recreate the key. (That should not be possible anyway + since the pool is stirred after save and some noise is added.) */ + random_save(&state, buf); + + ask_file_again: + + /* Ask for a file to save the key in. */ + if (identity_file) + { + strncpy(buf, identity_file, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + } + else + { + printf("Enter file in which to save the key ($HOME/%s): ", + SSH_CLIENT_IDENTITY); + fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) + exit(1); + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + if (strcmp(buf, "") == 0) + sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); + } + + /* If the file aready exists, ask the user to confirm. */ + if (stat(buf, &st) >= 0) + { + printf("%s already exists.\n", buf); + printf("Overwrite (y/n)? "); + fflush(stdout); + if (fgets(buf2, sizeof(buf2), stdin) == NULL) + exit(1); + if (buf2[0] != 'y' && buf2[0] != 'Y') + exit(1); + } + + /* Ask for a passphrase (twice). */ + if (identity_passphrase) + passphrase1 = xstrdup(identity_passphrase); + else + if (identity_new_passphrase) + passphrase1 = xstrdup(identity_new_passphrase); + else + { + passphrase_again: + passphrase1 = + read_passphrase("Enter passphrase (empty for no passphrase): ", 1); + passphrase2 = read_passphrase("Enter same passphrase again: ", 1); + if (strcmp(passphrase1, passphrase2) != 0) + { + /* The passphrases do not match. Clear them and retry. */ + memset(passphrase1, 0, strlen(passphrase1)); + memset(passphrase2, 0, strlen(passphrase2)); + xfree(passphrase1); + xfree(passphrase2); + printf("Passphrases do not match. Try again.\n"); + goto passphrase_again; + } + /* Clear the other copy of the passphrase. */ + memset(passphrase2, 0, strlen(passphrase2)); + xfree(passphrase2); + } + + /* Create default commend field for the passphrase. The user can later + edit this field. */ + if (identity_comment) + { + strncpy(buf2, identity_comment, sizeof(buf2)); + buf2[sizeof(buf2) - 1] = '\0'; + } + else + { +#ifdef HAVE_GETHOSTNAME + if (gethostname(hostname, sizeof(hostname)) < 0) + { + perror("gethostname"); + exit(1); + } + sprintf(buf2, "%s@%s", pw->pw_name, hostname); +#else + if (uname(&uts) < 0) + { + perror("uname"); + exit(1); + } + sprintf(buf2, "%s@%s", pw->pw_name, uts.nodename); +#endif + } + + /* Save the key with the given passphrase and comment. */ + if (!save_private_key(buf, passphrase1, &private_key, buf2, &state)) + { + printf("Saving the key failed: %s: %s.\n", + buf, strerror(errno)); + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + goto ask_file_again; + } + /* Clear the passphrase. */ + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + + /* Clear the private key and the random number generator. */ + rsa_clear_private_key(&private_key); + random_clear(&state); + + printf("Your identification has been saved in %s.\n", buf); + + /* Display the public key on the screen. */ + printf("Your public key is:\n"); + printf("%d ", public_key.bits); + mpz_out_str(stdout, 10, &public_key.e); + printf(" "); + mpz_out_str(stdout, 10, &public_key.n); + printf(" %s\n", buf2); + + /* Save the public key in text format in a file with the same name but + .pub appended. */ + strcat(buf, ".pub"); + f = fopen(buf, "w"); + if (!f) + { + printf("Could not save your public key in %s\n", buf); + exit(1); + } + fprintf(f, "%d ", public_key.bits); + mpz_out_str(f, 10, &public_key.e); + fprintf(f, " "); + mpz_out_str(f, 10, &public_key.n); + fprintf(f, " %s\n", buf2); + fclose(f); + + printf("Your public key has been saved in %s\n", buf); + + exit(0); +} diff --git a/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1 new file mode 100644 index 00000000000..58c7c2272a5 --- /dev/null +++ b/usr.bin/ssh/ssh.1 @@ -0,0 +1,1003 @@ +.\" -*- nroff -*- +.\" +.\" ssh.1.in +.\" +.\" Author: Tatu Ylonen <ylo@cs.hut.fi> +.\" +.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +.\" All rights reserved +.\" +.\" Created: Sat Apr 22 21:55:14 1995 ylo +.\" +.\" $Id: ssh.1,v 1.1 1999/09/26 20:53:37 deraadt Exp $ +.\" +.TH SSH 1 "November 8, 1995" "SSH" "SSH" + +.SH NAME +ssh \- secure shell client (remote login program) + +.SH SYNOPSIS +.B ssh +[\c +.BI \-l \ login_name\fR\c +] +.B hostname +[\c +.IR command \c +] + +.B ssh +[\c +.BR \-k \c +] +[\c +.B \-c +\fIblowfish\fR\||\|\fIidea\fR\||\|\fIdes\fR\||\|\fI3des\fR\||\|\fInone\fR\c +] +[\c +.BI \-e \ escape_char\fR\c +] +[\c +.BI \-i \ identity_file\fR\c +] +[\c +.BI \-l \ login_name\fR\c +] +[\c +.BR \-n \c +] +[\c +.BI \-o \ option\fR\c +] +[\c +.BI \-p \ port\fR\c +] +[\c +.BR \-q \c +] +[\c +.BR \-t \c +] +[\c +.BR \-v \c +] +[\c +.BR \-x \c +] +[\c +.BR \-X \c +] +[\c +.BR \-C \c +] +[\c +.BI \-L \ port\fB:\fIhost\fB:\fIhostport\fR\c +] +[\c +.BI \-R \ port\fB:\fIhost\fB:\fIhostport\fR\c +] +.I hostname +[\c +.IR command \c +] + +.SH DESCRIPTION +.LP +.B Ssh +(Secure Shell) a program for logging into a remote machine and for +executing commands in a remote machine. It is intended to replace +rlogin and rsh, and provide secure encrypted communications between +two untrusted hosts over an insecure network. X11 connections and +arbitrary TCP/IP ports can also be forwarded over the secure channel. +.LP +.B Ssh +connects and logs into the specified +.IR hostname . +The user must prove +his/her identity to the remote machine using one of several methods. +.LP +First, if the machine the user logs in from is listed in +.I /etc/hosts.equiv +or +.I /etc/shosts.equiv +on the remote machine, and the user names are +the same on both sides, the user is immediately permitted to log in. +Second, if +.I \&\s+2.\s0rhosts +or +.I \&\s+2.\s0shosts +exists in the user's home directory on the +remote machine and contains a line containing the name of the client +machine and the name of the user on that machine, the user is +permitted to log in. This form of authentication alone is normally not +allowed by the server because it is not secure. +.LP +The second (and primary) authentication method is the +.B rhosts +or +.B hosts.equiv +method combined with RSA-based host authentication. It +means that if the login would be permitted by +.I \&\s+2.\s0rhosts\c +\|, +.I \&\s+2.\s0shosts\c +\|, +.IR /etc/hosts.equiv\c +\|, +or +.IR /etc/shosts.equiv ", +and additionally it can verify the client's +host key (see +.I \&$HOME/\s+2.\s0ssh/known_hosts +and +.I /etc/ssh_known_hosts +in the +.B \s-1FILES\s0 +section), only then login is +permitted. This authentication method closes security holes due to IP +spoofing, DNS spoofing and routing spoofing. [Note to the +administrator: +.IR /etc/hosts.equiv ", +.IR \&\s+2.\s0rhosts ", +and the rlogin/rsh protocol in general, are inherently insecure and should be +disabled if security is desired.] +.LP +As a third authentication method, +.B ssh +supports RSA based authentication. +The scheme is based on public-key cryptography: there are cryptosystems +where encryption and decryption are done using separate keys, and it +is not possible to derive the decryption key from the encryption key. +RSA is one such system. The idea is that each user creates a public/private +key pair for authentication purposes. The +server knows the public key, and only the user knows the private key. +The file +.I \&$HOME/\s+2.\s0ssh/authorized_keys +lists the public keys that are permitted for logging +in. When the user logs in, the +.B ssh +program tells the server which key pair it would like to use for +authentication. The server checks if this key is permitted, and if +so, sends the user (actually the +.B ssh +program running on behalf of the user) a challenge, a random number, +encrypted by the user's public key. The challenge can only be +decrypted using the proper private key. The user's client then decrypts the +challenge using the private key, proving that he/she knows the private +key but without disclosing it to the server. +.LP +.B Ssh +implements the RSA authentication protocol automatically. The user +creates his/her RSA key pair by running +.BR ssh-keygen (1). +This stores the private key in +.I \&\s+2.\s0ssh/identity +and the public key in +.I \&\s+2.\s0ssh/identity.pub +in the user's home directory. The user should then +copy the +.I identity.pub +to +.I \&\s+2.\s0ssh/authorized_keys +in his/her home directory on the remote machine (the +.I authorized_keys +file corresponds to the conventional +.I \&\s+2.\s0rhosts +file, and has one key +per line, though the lines can be very long). After this, the user +can log in without giving the password. RSA authentication is much +more secure than rhosts authentication. +.LP +The most convenient way to use RSA authentication may be with an +authentication agent. See +.BR ssh-agent (1) +for more information. +.LP +If other authentication methods fail, +.B ssh +prompts the user for a password. The password is sent to the remote +host for checking; however, since all communications are encrypted, +the password cannot be seen by someone listening on the network. +.LP +When the user's identity has been accepted by the server, the server +either executes the given command, or logs into the machine and gives +the user a normal shell on the remote machine. All communication with +the remote command or shell will be automatically encrypted. +.LP +If a pseudo-terminal has been allocated (normal login session), the +user can disconnect with "~.", and suspend +.B ssh +with "~^Z". All forwarded connections can be listed with "~#", and if +the session blocks waiting for forwarded X11 or TCP/IP +connections to terminate, it can be backgrounded with "~&" (this +should not be used while the user shell is active, as it can cause the +shell to hang). All available escapes can be listed with "~?". +.LP +A single tilde character can be sent as "~~" (or by +following the tilde by a character other than those described above). +The escape character must always follow a newline to be interpreted as +special. The escape character can be changed in configuration files +or on the command line. +.LP +If no pseudo tty has been allocated, the +session is transparent and can be used to reliably transfer binary +data. On most systems, setting the escape character to ``none'' will +also make the session transparent even if a tty is used. +.LP +The session terminates when the command or shell in on the remote +machine exists and all X11 and TCP/IP connections have been closed. +The exit status of the remote program is returned as the exit status +of +.B ssh. +.LP +If the user is using X11 (the +.B \s-1DISPLAY\s0 +environment variable is set), the connection to the X11 display is +automatically forwarded to the remote side in such a way that any X11 +programs started from the shell (or command) will go through the +encrypted channel, and the connection to the real X server will be made +from the local machine. The user should not manually set +.BR \s-1DISPLAY\s0 ". +Forwarding of X11 connections can be +configured on the command line or in configuration files. +.LP +The DISPLAY value set by +.B ssh +will point to the server machine, but with a display number greater +than zero. This is normal, and happens because +.B ssh +creates a "proxy" X server on the server machine for forwarding the +connections over the encrypted channel. +.LP +.B Ssh +will also automatically set up Xauthority data on the server machine. +For this purpose, it will generate a random authorization cookie, +store it in Xauthority on the server, and verify that any forwarded +connections carry this cookie and replace it by the real cookie when +the connection is opened. The real authentication cookie is never +sent to the server machine (and no cookies are sent in the plain). +.LP +If the user is using an authentication agent, the connection to the agent +is automatically forwarded to the remote side unless disabled on +command line or in a configuration file. +.LP +Forwarding of arbitrary TCP/IP connections over the secure channel can +be specified either on command line or in a configuration file. One +possible application of TCP/IP forwarding is a secure connection to an +electronic purse; another is going trough firewalls. +.LP +.B Ssh +automatically maintains and checks a database containing RSA-based +identifications for all hosts it has ever been used with. The +database is stored in +.I \&\s+2.\s0ssh/known_hosts +in the user's home directory. Additionally, the file +.I /etc/ssh_known_hosts +is automatically checked for known hosts. Any new hosts are +automatically added to the user's file. If a host's identification +ever changes, +.B ssh +warns about this and disables password authentication to prevent a +trojan horse from getting the user's password. Another purpose of +this mechanism is to prevent man-in-the-middle attacks which could +otherwise be used to circumvent the encryption. The +.B StrictHostKeyChecking +option (see below) can be used to prevent logins to machines whose +host key is not known or has changed. + + +.ne 5 +.SH OPTIONS +.TP +.BI \-c \ \fIblowfish\fR\||\|\fIidea\fR\||\|\fIdes\fR\||\|\fI3des\fR\||\|\fInone\fR +Selects the cipher to use for encrypting the session. +.B \s-13DES\s0 +is used by default. It is believed to be secure. +.B \s-1DES\s0 +is the data encryption standard, but is breakable by +governments, large corporations, and major criminal organizations. +.B \s-13DES\s0 +(triple-des) is encrypt-decrypt-encrypt triple with three different +keys. It is presumably more secure than +DES. +.B none +disables encryption entirely; it is only intended for debugging, and +it renders the connection insecure. +.ne 3 +.TP +.B \-e \fIch\fR\||\|\fI^ch\fR\||\|\fInone\fR +Sets the escape character for sessions with a pty (default: ~). The +escape character is only recognized at the beginning of a line. The +escape character followed by a dot (.) closes the connection, followed +by control-Z suspends the connection, and followed by itself sends the +escape character once. Setting the character to 'none' disables any +escapes and makes the session fully transparent. +.ne 3 +.TP +.B \-f +Requests ssh to go to background after authentication. This is useful +if ssh is going to ask for passwords or passphrases, but the user +wants it in the background. This implies +.B \-n. +The recommended way to start X11 programs at a remote site is with +something like "ssh -f host xterm". +.ne 3 +.TP +.BI \-i \ identity_file +Selects the file from which the identity (private key) for +.B \s-1RSA\s0 +authentication is read. Default is +.I \&\s+2.\s0ssh/identity +in the user's home directory. Identity files may also be specified on +a per-host basis in the configuration file. It is possible to have +multiple \-i options (and multiple identities specified in +configuration files). +.ne 3 +.TP +.B \-k +Disables forwarding of Kerberos tickets / AFS tokens. This may +also be specified on a per-host basis in the configuration file. +.ne 3 +.TP +.BI -l \ login_name +Specifies the user to log in as on the remote machine. This may also +be specified on a per-host basis in the configuration file. +.ne 3 +.TP +.B \-n +Redirects stdin from /dev/null (actually, prevents reading from stdin). +This must be used when +.B ssh +is run in the background. A common trick is to use this to run X11 +programs in a remote machine. For example, "ssh -n shadows.cs.hut.fi +emacs &" will start an emacs on shadows.cs.hut.fi, and the X11 +connection will be automatically forwarded over an encrypted channel. +The +.B ssh +program will be put in the background. +(This does not work if +.B ssh +needs to ask for a password or passphrase; see also the -f option.) +.ne 3 +.TP +.BI \-o "\ 'option' +Can be used to give options in the format used in the config file. +This is useful for specifying options for which there is no separate +command-line flag. The option has the same format as a line in the +configuration file. +.ne 3 +.TP +.BI \-p "\ port +Port to connect to on the remote host. This can be specified on a +per-host basis in the configuration file. +.ne 3 +.TP +.B \-q +Quiet mode. Causes all warning and diagnostic messages to be +suppressed. Only fatal errors are displayed. +.ne 3 +.TP +.B \-t +Force pseudo-tty allocation. This can be used to execute arbitary +screen-based programs on a remote machine, which can be very useful +e.g. when implementing menu services. +.ne 3 +.TP +.B \-v +Verbose mode. Causes +.B ssh +to print debugging messages about its progress. This is helpful in +debugging connection, authentication, and configuration problems. +.ne 3 +.TP +.B \-x +Disables X11 forwarding. This can also be specified on a per-host +basis in a configuration file. +.ne 3 +.TP +.B \-X +Enables X11 forwarding. +.ne 3 +.TP +.B \-C +Requests compression of all data (including stdin, stdout, stderr, and +data for forwarded X11 and TCP/IP connections). The compression +algorithm is the same used by gzip, and the "level" can be controlled +by the +.B CompressionLevel +option (see below). Compression is desirable on modem lines and other +slow connections, but will only slow down things on fast networks. +The default value can be set on a host-by-host basis in the +configuration files; see the +.B Compress +option below. +.ne 3 +.TP +.BI \-L "\ port:host:hostport +Specifies that the given port on the local (client) host is to be +forwarded to the given host and port on the remote side. This works +by allocating a socket to listen to +.B port +on the local side, and whenever a connection is made to this port, the +connection is forwarded over the secure channel, and a connection is +made to +.B host:hostport +from the remote machine. Port forwardings can also be specified in the +configuration file. Only root can forward privileged ports. +.ne 3 +.TP +.BI \-R "\ port:host:hostport +Specifies that the given port on the remote (server) host is to be +forwarded to the given host and port on the local side. This works +by allocating a socket to listen to +.B port +on the remote side, and whenever a connection is made to this port, the +connection is forwarded over the secure channel, and a connection is +made to +.B host:hostport +from the local machine. Port forwardings can also be specified in the +configuration file. Privileged ports can be forwarded only when +logging in as root on the remote machine. + +.SH CONFIGURATION FILES +.LP +.B Ssh +obtains configuration data from the following sources (in this order): +command line options, user's configuration file +(\fI\&$HOME/\s+2.\s0ssh/config\fR), and system-wide configuration file +(\fI/etc/ssh_config\fR). For each parameter, the first obtained value +will be used. The configuration files contain sections bracketed by +"Host" specifications, and that section is only applied for hosts that +match one of the patterns given in the specification. The matched +host name is the one given on the command line. +.LP +Since the first obtained value for each parameter is used, more +host-specific declarations should be given near the beginning of the +file, and general defaults at the end. +.LP +The configuration file has the following format: +.IP +Empty lines and lines starting with '#' are comments. +.IP +Otherwise a line is of the format "keyword arguments". The possible +keywords and their meanings are as follows (note that the +configuration files are case-sensitive): +.ne 3 +.TP +.de YN +"\fByes\fR" or "\fBno\fR". +.. + +.B Host +Restricts the following declarations (up to the next +.B Host +keyword) to be only for those hosts that match one of the patterns +given after the keyword. '*' and '?' can be as wildcards in the +patterns. A single '*' as a pattern can be used to provide global +defaults for all hosts. The host is the +.IR hostname +argument given on the command line (i.e., the name is not converted to +a canonicalized host name before matching). +.ne 3 +.TP +.B AFSTokenPassing +Specifies whether to pass AFS tokens to remote host. The argument to +this keyword must be +.YN +.ne 3 +.TP +.B BatchMode +If set to "yes", passphrase/password querying will be disabled. This +option is useful in scripts and other batch jobs where you have no +user to supply the password. The argument must be +.YN +.ne 3 +.TP +.B Cipher +Specifies the cipher to use for encrypting the session. Currently, +.IR blowfish ", +.IR idea ", +.IR des ", +.IR 3des ", +and +.I none +are supported. The default is "3des". Using "none" (no encryption) is intended +only for debugging, and will render the connection insecure. +.ne 3 +.TP +.B Compression +Specifies whether to use compression. The argument must be +.YN +.ne 3 +.TP +.B CompressionLevel +Specifies the compression level to use if compression is enable. The +argument must be an integer from 1 (fast) to 9 (slow, best). The +default level is 6, which is good for most applications. The meaning +of the values is the same as in GNU GZIP. +.ne 3 +.TP +.B ConnectionAttempts +Specifies the number of tries (one per second) to make before falling +back to rsh or exiting. The argument must be an integer. This may be +useful in scripts if the connection sometimes fails. +.ne 3 +.TP +.B EscapeChar +Sets the escape character (default: ~). The escape character can also +be set on the command line. The argument should be a single +character, '^' followed by a letter, or ``none'' to disable the escape +character entirely (making the connection transparent for binary +data). +.ne 3 +.TP +.B FallBackToRsh +Specifies that if connecting via +.B ssh +fails due to a connection refused error (there is no +.B sshd +listening on the remote host), +.B rsh +should automatically be used instead (after a suitable warning about +the session being unencrypted). The argument must be +.YN +.ne 3 +.TP +.B ForwardAgent +Specifies whether the connection to the authentication agent (if any) +will be forwarded to the remote machine. The argument must be +.YN +.ne 3 +.TP +.B ForwardX11 +Specifies whether X11 connections will be automatically redirected +over the secure channel and +.B \s-1DISPLAY\s0 +set. The argument must be +.YN +.ne 3 +.TP +.B GlobalKnownHostsFile +Specifies a file to use instead of +.IR /etc/ssh_known_hosts ". +.ne 3 +.TP +.B HostName +Specifies the real host name to log into. This can be used to specify +nicnames or abbreviations for hosts. Default is the name given on the +command line. Numeric IP addresses are also permitted (both on the +command line and in +.B HostName +specifications). +.ne 3 +.TP +.B IdentityFile +Specifies the file from which the user's RSA authentication identity +is read (default \fI\s+2.\s0ssh/identity\fR in the user's home directory). +Additionally, any identities represented by the authentication agent +will be used for authentication. The file name may use the tilde +syntax to refer to a user's home directory. It is possible to have +multiple identity files specified in configuration files; all these +identities will be tried in sequence. +.ne 3 +.TP +.B KeepAlive +Specifies whether the system should send keepalive messages to the +other side. If they are sent, death of the connection or crash of one +of the machines will be properly noticed. However, this means that +connections will die if the route is down temporarily, and some people +find it annoying. + +The default is "yes" (to send keepalives), and the client will notice +if the network goes down or the remote host dies. This is important +in scripts, and many users want it too. + +To disable keepalives, the value should be set to "no" in both the +server and the client configuration files. +.ne 3 +.TP +.B KerberosAuthentication +Specifies whether Kerberos authentication will be used. +.TP +.B KerberosTgtPassing +Specifies whether a Kerberos TGT will be forwarded to the server. +Note that TGT forwarding is normally not enabled in the server. +.TP +.B LocalForward +Specifies that a TCP/IP port on the local machine be forwarded over +the secure channel to given host:port from the remote machine. The +first argument must be a port number, and the second must be +host:port. Multiple forwardings may be specified, and additional +forwardings can be given on the command line. Only the root can +forward privileged ports. +.ne 3 +.TP +.B PasswordAuthentication +Specifies whether to use password authentication. The argument to +this keyword must be +.YN +.ne 3 +.TP +.B Port +Specifies the port number to connect on the remote host. Default is +22. +.ne 3 +.TP +.B ProxyCommand +Specifies the command to use to connect to the server. The command +string extends to the end of the line, and is executed with /bin/sh. +In the command string, %h will be substituted by the host name to +connect and %p by the port. The command can be basically anything, +and should read from its stdin and write to its stdout. It should +eventually connect an +.B sshd +server running on some machine, or execute +"sshd -i" somewhere. Host key management will be done using the +HostName of the host being connected (defaulting to the name typed by +the user). + +Note that +.B ssh +can also be configured to support the SOCKS system using the +--with-socks compile-time configuration option. +.ne 3 +.TP +.B RemoteForward +Specifies that a TCP/IP port on the remote machine be forwarded over +the secure channel to given host:port from the local machine. The +first argument must be a port number, and the second must be +host:port. Multiple forwardings may be specified, and additional +forwardings can be given on the command line. Only the root can +forward privileged ports. +.ne 3 +.TP +.B RhostsAuthentication +Specifies whether to try rhosts based authentication. Note that this +declaration only affects the client side and has no effect whatsoever +on security. Disabling rhosts authentication may reduce +authentication time on slow connections when rhosts authentication is +not used. Most servers do not permit RhostsAuthentication because it +is not secure (see RhostsRSAAuthentication). The argument to this +keyword must be +.YN +.ne 3 +.TP +.B RhostsRSAAuthentication +Specifies whether to try rhosts based authentication with RSA host +authentication. This is the primary authentication method for most +sites. The argument must be +.YN +.ne 3 +.TP +.B RSAAuthentication +Specifies whether to try RSA authentication. The argument to this +keyword must be +.YN +RSA authentication will only be +attempted if the identity file exists, or an authentication agent is +running. +.ne 3 +.TP +.B StrictHostKeyChecking +If this flag is set to "yes", +.B ssh +ssh will never automatically add host keys to the +.I $HOME/.ssh/known_hosts +file, and refuses to connect hosts whose host key has changed. This +provides maximum protection against trojan horse attacks. However, it +can be somewhat annoying if you don't have good +.I /etc/ssh_known_hosts +files installed and frequently +connect new hosts. Basically this option forces the user to manually +add any new hosts. Normally this option is disabled, and new hosts +will automatically be added to the known host files. The host keys of +known hosts will be verified automatically in either case. The +argument must be +.YN +.ne3 +.TP +.B User +Specifies the user to log in as. This can be useful if you have a +different user name in different machines. This saves the trouble of +having to remember to give the user name on the command line. +.ne 3 +.TP +.B UserKnownHostsFile +Specifies a file to use instead of \fI$HOME/\s+2.\s0ssh/known_hosts\fR. +.ne 3 +.TP +.B UseRsh +Specifies that rlogin/rsh should be used for this host. It is +possible that the host does not at all support the +.B ssh +protocol. This causes +.B ssh +to immediately exec +.B rsh. +All other options (except +.BR HostName ) +are ignored if this has been specified. The argument must be +.YN + +.SH ENVIRONMENT +.LP +.B Ssh +will normally set the following environment variables: +.TP +.B DISPLAY +The DISPLAY variable indicates the location of the X11 server. It is +automatically set by +.B ssh +to point to a value of the form "hostname:n" where hostname indicates +the host where the shell runs, and n is an integer >= 1. Ssh uses +this special value to forward X11 connections over the secure +channel. The user should normally not set DISPLAY explicitly, as that +will render the X11 connection insecure (and will require the user to +manually copy any required authorization cookies). +.ne 3 +.TP +.B HOME +Set to the path of the user's home directory. +.ne 3 +.TP +.B LOGNAME +Synonym for USER; set for compatibility with systems that use +this variable. +.ne 3 +.TP +.B MAIL +Set to point the user's mailbox. +.ne 3 +.TP +.B PATH +Set to the default PATH, as specified when compiling +.B ssh +or, on some systems, +.I /etc/environment +or +.IR /etc/default/login ". +.ne 3 +.TP +.B SSH_AUTHENTICATION_FD +This is set to an integer value if you are using the authentication +agent and a connection to it has been forwarded. The value indicates +a file descriptor number used for communicating with the agent. On +some systems, +.B SSH_AUTHENTICATION_SOCKET +may be used instead to +indicate the path of a unix-domain socket used to communicate with the +agent (this method is less secure, and is only used on systems that +don't support the first method). +.ne 3 +.TP +.B SSH_CLIENT +Identifies the client end of the connection. The variable contains +three space-separated values: client ip-address, client port number, +and server port number. +.ne 3 +.TP +.B SSH_TTY +This is set to the name of the tty (path to the device) associated +with the current shell or command. If the current session has no tty, +this variable is not set. +.ne 3 +.TP +.B TZ +The timezone variable is set to indicate the present timezone if it +was set when the daemon was started (e.i., the daemon passes the value +on to new connections). +.ne 3 +.TP +.B USER +Set to the name of the user logging in. +.LP +.RT +Additionally, +.B ssh +reads +.I /etc/environment +and +.IR $HOME/.ssh/environment ", +and adds lines of +the format +.I VARNAME=value +to the environment. Some systems may have +still additional mechanisms for setting up the environment, such as +.I /etc/default/login +on Solaris. + +.ne 3 +.SH FILES +.TP +.I \&$HOME/\s+2.\s0ssh/known_hosts +Records host keys for all hosts the user has logged into (that are not +in \fI/etc/ssh_known_hosts\fR). See +.B sshd +manual page. +.ne 3 +.TP +.I \&$HOME/\s+2.\s0ssh/random_seed +Used for seeding the random number generator. This file contains +sensitive data and should read/write for the user and not accessible +for others. This file is created the first time the program is run +and updated automatically. The user should never need to read or +modify this file. +.ne 5 +.TP +.I \&$HOME/\s+2.\s0ssh/identity +Contains the RSA authentication identity of the user. This file +contains sensitive data and should be readable by the user but not +accessible by others. It is possible to specify a passphrase when +generating the key; the passphrase will be used to encrypt the +sensitive part of this file using +.BR \s-1IDEA\s0 ". +.ne 3 +.TP +.I \&$HOME/\s+2.\s0ssh/identity.pub +Contains the public key for authentication (public part of the +identity file in human-readable form). The contents of this file +should be added to \fI$HOME/\s+2.\s0ssh/authorized_keys\fR on all machines +where you wish to log in using RSA authentication. This file is not +sensitive and can (but need not) be readable by anyone. This file is +never used automatically and is not necessary; it is only provided for +the convenience of the user. +.ne 3 +.TP +.I \&$HOME/\s+2.\s0ssh/config +This is the per-user configuration file. The format of this file is +described above. This file is used by the +.B ssh +client. This file does not usually contain any sensitive information, +but the recommended permissions are read/write for the user, and not +accessible by others. +.ne 3 +.TP +.I \&$HOME/\s+2.\s0ssh/authorized_keys +Lists the RSA keys that can be used for logging in as this user. The +format of this file is described in the +.B sshd +manual page. In the simplest form the format is the same as the .pub +identity files (that is, each line contains the number of bits in +modulus, public exponent, modulus, and comment fields, separated by +spaces). This file is not highly sensitive, but the recommended +permissions are read/write for the user, and not accessible by others. +.ne 3 +.TP +.I /etc/ssh_known_hosts +Systemwide list of known host keys. This file should be prepared by the +system administrator to contain the public host keys of all machines in the +organization. This file should be world-readable. This file contains +public keys, one per line, in the following format (fields separated +by spaces): system name, number of bits in modulus, public exponent, +modulus, and optional comment field. When different names are used +for the same machine, all such names should be listed, separated by +commas. The format is described on the +.B sshd +manual page. +.IP +The canonical system name (as returned by name servers) is used by +.B sshd +to verify the client host when logging in; other names are needed because +.B ssh +does not convert the user-supplied name to a canonical name before +checking the key, because someone with access to the name servers +would then be able to fool host authentication. +.ne 3 +.TP +.I /etc/ssh_config +Systemwide configuration file. This file provides defaults for those +values that are not specified in the user's configuration file, and +for those users who do not have a configuration file. This file must +be world-readable. +.ne 3 +.TP +.I $HOME/\s+2.\s0rhosts +This file is used in \s+2.\s0rhosts authentication to list the +host/user pairs that are permitted to log in. (Note that this file is +also used by rlogin and rsh, which makes using this file insecure.) +Each line of the file contains a host name (in the canonical form +returned by name servers), and then a user name on that host, +separated by a space. One some machines this file may need to be +world-readable if the user's home directory is on a NFS partition, +because +.B sshd +reads it as root. Additionally, this file must be owned by the user, +and must not have write permissions for anyone else. The recommended +permission for most machines is read/write for the user, and not +accessible by others. +.IP +Note that by default +.B sshd +will be installed so that it requires successful RSA host +authentication before permitting \s+2.\s0rhosts authentication. If your +server machine does not have the client's host key in +\fI/etc/ssh_known_hosts\fR, you can store it in +\fI$HOME/\s+2.\s0ssh/known_hosts\fR. The easiest way to do this is to +connect back to the client from the server machine using ssh; this +will automatically add the host key in \fI$HOME/\s+2.\s0ssh/known_hosts\fR. +.ne 3 +.TP +.I $HOME/\s+2.\s0shosts +This file is used exactly the same way as \s+2.\s0rhosts. The purpose for +having this file is to be able to use rhosts authentication with +.B ssh +without permitting login with rlogin or rsh. +.ne 3 +.TP +.I /etc/hosts.equiv +This file is used during \s+2.\s0rhosts authentication. It contains +canonical hosts names, one per line (the full format is described on +the +.B sshd +manual page). If the client host is found in this file, login is +automatically permitted provided client and server user names are the +same. Additionally, successful RSA host authentication is normally +required. This file should only be writable by root. +.TP +.I /etc/shosts.equiv +This file is processed exactly as +.IR /etc/hosts.equiv ". +This file may be useful to permit logins using +.B ssh +but not using rsh/rlogin. +.ne 3 +.TP +.I /etc/sshrc +Commands in this file are executed by +.B ssh +when the user logs in just before the user's shell (or command) is started. +See the +.B sshd +manual page for more information. +.ne 3 +.TP +.I $HOME/.ssh/rc +Commands in this file are executed by +.B ssh +when the user logs in just before the user's shell (or command) is +started. +See the +.B sshd +manual page for more information. + +.SH INSTALLATION +.LP +.B Ssh +is normally installed as suid root. It needs root privileges only for +rhosts authentication (rhosts authentication requires that the +connection must come from a privileged port, and allocating such a +port requires root privileges). It also needs to be able to read +\fI/etc/ssh_host_key\fR to perform +.B \s-1RSA\s0 +host authentication. It is possible to use +.B ssh +without root privileges, but rhosts authentication will then be +disabled. +.B Ssh +drops any extra privileges immediately after the connection to the +remote host has been made. +.LP +Considerable work has been put into making +.B sshd +secure. However, if you find a security problem, please report it +immediately to <ssh-bugs@cs.hut.fi>. + + +.SH AUTHOR +.LP +Tatu Ylonen <ylo@cs.hut.fi> +.LP +Information about new releases, mailing lists, and other related +issues can be found from the ssh WWW home page at +http://www.cs.hut.fi/ssh. + +.SH SEE ALSO +.BR sshd (8), +.BR ssh-keygen (1), +.BR ssh-agent (1), +.BR ssh-add (1), +.BR scp (1), +.BR make-ssh-known-hosts (1), +.BR rlogin (1), +.BR rsh (1), +.BR telnet (1) diff --git a/usr.bin/ssh/ssh.1.in b/usr.bin/ssh/ssh.1.in new file mode 100644 index 00000000000..74a1255eb7d --- /dev/null +++ b/usr.bin/ssh/ssh.1.in @@ -0,0 +1,1003 @@ +.\" -*- nroff -*- +.\" +.\" ssh.1.in +.\" +.\" Author: Tatu Ylonen <ylo@cs.hut.fi> +.\" +.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +.\" All rights reserved +.\" +.\" Created: Sat Apr 22 21:55:14 1995 ylo +.\" +.\" $Id: ssh.1.in,v 1.1 1999/09/26 20:53:37 deraadt Exp $ +.\" +.TH SSH 1 "November 8, 1995" "SSH" "SSH" + +.SH NAME +ssh \- secure shell client (remote login program) + +.SH SYNOPSIS +.B ssh +[\c +.BI \-l \ login_name\fR\c +] +.B hostname +[\c +.IR command \c +] + +.B ssh +[\c +.BR \-k \c +] +[\c +.B \-c +\fIblowfish\fR\||\|\fIidea\fR\||\|\fIdes\fR\||\|\fI3des\fR\||\|\fInone\fR\c +] +[\c +.BI \-e \ escape_char\fR\c +] +[\c +.BI \-i \ identity_file\fR\c +] +[\c +.BI \-l \ login_name\fR\c +] +[\c +.BR \-n \c +] +[\c +.BI \-o \ option\fR\c +] +[\c +.BI \-p \ port\fR\c +] +[\c +.BR \-q \c +] +[\c +.BR \-t \c +] +[\c +.BR \-v \c +] +[\c +.BR \-x \c +] +[\c +.BR \-X \c +] +[\c +.BR \-C \c +] +[\c +.BI \-L \ port\fB:\fIhost\fB:\fIhostport\fR\c +] +[\c +.BI \-R \ port\fB:\fIhost\fB:\fIhostport\fR\c +] +.I hostname +[\c +.IR command \c +] + +.SH DESCRIPTION +.LP +.B Ssh +(Secure Shell) a program for logging into a remote machine and for +executing commands in a remote machine. It is intended to replace +rlogin and rsh, and provide secure encrypted communications between +two untrusted hosts over an insecure network. X11 connections and +arbitrary TCP/IP ports can also be forwarded over the secure channel. +.LP +.B Ssh +connects and logs into the specified +.IR hostname . +The user must prove +his/her identity to the remote machine using one of several methods. +.LP +First, if the machine the user logs in from is listed in +.I /etc/hosts.equiv +or +.I @ETCDIR@/shosts.equiv +on the remote machine, and the user names are +the same on both sides, the user is immediately permitted to log in. +Second, if +.I \&\s+2.\s0rhosts +or +.I \&\s+2.\s0shosts +exists in the user's home directory on the +remote machine and contains a line containing the name of the client +machine and the name of the user on that machine, the user is +permitted to log in. This form of authentication alone is normally not +allowed by the server because it is not secure. +.LP +The second (and primary) authentication method is the +.B rhosts +or +.B hosts.equiv +method combined with RSA-based host authentication. It +means that if the login would be permitted by +.I \&\s+2.\s0rhosts\c +\|, +.I \&\s+2.\s0shosts\c +\|, +.IR /etc/hosts.equiv\c +\|, +or +.IR @ETCDIR@/shosts.equiv ", +and additionally it can verify the client's +host key (see +.I \&$HOME/\s+2.\s0ssh/known_hosts +and +.I @ETCDIR@/ssh_known_hosts +in the +.B \s-1FILES\s0 +section), only then login is +permitted. This authentication method closes security holes due to IP +spoofing, DNS spoofing and routing spoofing. [Note to the +administrator: +.IR /etc/hosts.equiv ", +.IR \&\s+2.\s0rhosts ", +and the rlogin/rsh protocol in general, are inherently insecure and should be +disabled if security is desired.] +.LP +As a third authentication method, +.B ssh +supports RSA based authentication. +The scheme is based on public-key cryptography: there are cryptosystems +where encryption and decryption are done using separate keys, and it +is not possible to derive the decryption key from the encryption key. +RSA is one such system. The idea is that each user creates a public/private +key pair for authentication purposes. The +server knows the public key, and only the user knows the private key. +The file +.I \&$HOME/\s+2.\s0ssh/authorized_keys +lists the public keys that are permitted for logging +in. When the user logs in, the +.B ssh +program tells the server which key pair it would like to use for +authentication. The server checks if this key is permitted, and if +so, sends the user (actually the +.B ssh +program running on behalf of the user) a challenge, a random number, +encrypted by the user's public key. The challenge can only be +decrypted using the proper private key. The user's client then decrypts the +challenge using the private key, proving that he/she knows the private +key but without disclosing it to the server. +.LP +.B Ssh +implements the RSA authentication protocol automatically. The user +creates his/her RSA key pair by running +.BR ssh-keygen (1). +This stores the private key in +.I \&\s+2.\s0ssh/identity +and the public key in +.I \&\s+2.\s0ssh/identity.pub +in the user's home directory. The user should then +copy the +.I identity.pub +to +.I \&\s+2.\s0ssh/authorized_keys +in his/her home directory on the remote machine (the +.I authorized_keys +file corresponds to the conventional +.I \&\s+2.\s0rhosts +file, and has one key +per line, though the lines can be very long). After this, the user +can log in without giving the password. RSA authentication is much +more secure than rhosts authentication. +.LP +The most convenient way to use RSA authentication may be with an +authentication agent. See +.BR ssh-agent (1) +for more information. +.LP +If other authentication methods fail, +.B ssh +prompts the user for a password. The password is sent to the remote +host for checking; however, since all communications are encrypted, +the password cannot be seen by someone listening on the network. +.LP +When the user's identity has been accepted by the server, the server +either executes the given command, or logs into the machine and gives +the user a normal shell on the remote machine. All communication with +the remote command or shell will be automatically encrypted. +.LP +If a pseudo-terminal has been allocated (normal login session), the +user can disconnect with "~.", and suspend +.B ssh +with "~^Z". All forwarded connections can be listed with "~#", and if +the session blocks waiting for forwarded X11 or TCP/IP +connections to terminate, it can be backgrounded with "~&" (this +should not be used while the user shell is active, as it can cause the +shell to hang). All available escapes can be listed with "~?". +.LP +A single tilde character can be sent as "~~" (or by +following the tilde by a character other than those described above). +The escape character must always follow a newline to be interpreted as +special. The escape character can be changed in configuration files +or on the command line. +.LP +If no pseudo tty has been allocated, the +session is transparent and can be used to reliably transfer binary +data. On most systems, setting the escape character to ``none'' will +also make the session transparent even if a tty is used. +.LP +The session terminates when the command or shell in on the remote +machine exists and all X11 and TCP/IP connections have been closed. +The exit status of the remote program is returned as the exit status +of +.B ssh. +.LP +If the user is using X11 (the +.B \s-1DISPLAY\s0 +environment variable is set), the connection to the X11 display is +automatically forwarded to the remote side in such a way that any X11 +programs started from the shell (or command) will go through the +encrypted channel, and the connection to the real X server will be made +from the local machine. The user should not manually set +.BR \s-1DISPLAY\s0 ". +Forwarding of X11 connections can be +configured on the command line or in configuration files. +.LP +The DISPLAY value set by +.B ssh +will point to the server machine, but with a display number greater +than zero. This is normal, and happens because +.B ssh +creates a "proxy" X server on the server machine for forwarding the +connections over the encrypted channel. +.LP +.B Ssh +will also automatically set up Xauthority data on the server machine. +For this purpose, it will generate a random authorization cookie, +store it in Xauthority on the server, and verify that any forwarded +connections carry this cookie and replace it by the real cookie when +the connection is opened. The real authentication cookie is never +sent to the server machine (and no cookies are sent in the plain). +.LP +If the user is using an authentication agent, the connection to the agent +is automatically forwarded to the remote side unless disabled on +command line or in a configuration file. +.LP +Forwarding of arbitrary TCP/IP connections over the secure channel can +be specified either on command line or in a configuration file. One +possible application of TCP/IP forwarding is a secure connection to an +electronic purse; another is going trough firewalls. +.LP +.B Ssh +automatically maintains and checks a database containing RSA-based +identifications for all hosts it has ever been used with. The +database is stored in +.I \&\s+2.\s0ssh/known_hosts +in the user's home directory. Additionally, the file +.I @ETCDIR@/ssh_known_hosts +is automatically checked for known hosts. Any new hosts are +automatically added to the user's file. If a host's identification +ever changes, +.B ssh +warns about this and disables password authentication to prevent a +trojan horse from getting the user's password. Another purpose of +this mechanism is to prevent man-in-the-middle attacks which could +otherwise be used to circumvent the encryption. The +.B StrictHostKeyChecking +option (see below) can be used to prevent logins to machines whose +host key is not known or has changed. + + +.ne 5 +.SH OPTIONS +.TP +.BI \-c \ \fIblowfish\fR\||\|\fIidea\fR\||\|\fIdes\fR\||\|\fI3des\fR\||\|\fInone\fR +Selects the cipher to use for encrypting the session. +.B \s-13DES\s0 +is used by default. It is believed to be secure. +.B \s-1DES\s0 +is the data encryption standard, but is breakable by +governments, large corporations, and major criminal organizations. +.B \s-13DES\s0 +(triple-des) is encrypt-decrypt-encrypt triple with three different +keys. It is presumably more secure than +DES. +.B none +disables encryption entirely; it is only intended for debugging, and +it renders the connection insecure. +.ne 3 +.TP +.B \-e \fIch\fR\||\|\fI^ch\fR\||\|\fInone\fR +Sets the escape character for sessions with a pty (default: ~). The +escape character is only recognized at the beginning of a line. The +escape character followed by a dot (.) closes the connection, followed +by control-Z suspends the connection, and followed by itself sends the +escape character once. Setting the character to 'none' disables any +escapes and makes the session fully transparent. +.ne 3 +.TP +.B \-f +Requests ssh to go to background after authentication. This is useful +if ssh is going to ask for passwords or passphrases, but the user +wants it in the background. This implies +.B \-n. +The recommended way to start X11 programs at a remote site is with +something like "ssh -f host xterm". +.ne 3 +.TP +.BI \-i \ identity_file +Selects the file from which the identity (private key) for +.B \s-1RSA\s0 +authentication is read. Default is +.I \&\s+2.\s0ssh/identity +in the user's home directory. Identity files may also be specified on +a per-host basis in the configuration file. It is possible to have +multiple \-i options (and multiple identities specified in +configuration files). +.ne 3 +.TP +.B \-k +Disables forwarding of Kerberos tickets / AFS tokens. This may +also be specified on a per-host basis in the configuration file. +.ne 3 +.TP +.BI -l \ login_name +Specifies the user to log in as on the remote machine. This may also +be specified on a per-host basis in the configuration file. +.ne 3 +.TP +.B \-n +Redirects stdin from /dev/null (actually, prevents reading from stdin). +This must be used when +.B ssh +is run in the background. A common trick is to use this to run X11 +programs in a remote machine. For example, "ssh -n shadows.cs.hut.fi +emacs &" will start an emacs on shadows.cs.hut.fi, and the X11 +connection will be automatically forwarded over an encrypted channel. +The +.B ssh +program will be put in the background. +(This does not work if +.B ssh +needs to ask for a password or passphrase; see also the -f option.) +.ne 3 +.TP +.BI \-o "\ 'option' +Can be used to give options in the format used in the config file. +This is useful for specifying options for which there is no separate +command-line flag. The option has the same format as a line in the +configuration file. +.ne 3 +.TP +.BI \-p "\ port +Port to connect to on the remote host. This can be specified on a +per-host basis in the configuration file. +.ne 3 +.TP +.B \-q +Quiet mode. Causes all warning and diagnostic messages to be +suppressed. Only fatal errors are displayed. +.ne 3 +.TP +.B \-t +Force pseudo-tty allocation. This can be used to execute arbitary +screen-based programs on a remote machine, which can be very useful +e.g. when implementing menu services. +.ne 3 +.TP +.B \-v +Verbose mode. Causes +.B ssh +to print debugging messages about its progress. This is helpful in +debugging connection, authentication, and configuration problems. +.ne 3 +.TP +.B \-x +Disables X11 forwarding. This can also be specified on a per-host +basis in a configuration file. +.ne 3 +.TP +.B \-X +Enables X11 forwarding. +.ne 3 +.TP +.B \-C +Requests compression of all data (including stdin, stdout, stderr, and +data for forwarded X11 and TCP/IP connections). The compression +algorithm is the same used by gzip, and the "level" can be controlled +by the +.B CompressionLevel +option (see below). Compression is desirable on modem lines and other +slow connections, but will only slow down things on fast networks. +The default value can be set on a host-by-host basis in the +configuration files; see the +.B Compress +option below. +.ne 3 +.TP +.BI \-L "\ port:host:hostport +Specifies that the given port on the local (client) host is to be +forwarded to the given host and port on the remote side. This works +by allocating a socket to listen to +.B port +on the local side, and whenever a connection is made to this port, the +connection is forwarded over the secure channel, and a connection is +made to +.B host:hostport +from the remote machine. Port forwardings can also be specified in the +configuration file. Only root can forward privileged ports. +.ne 3 +.TP +.BI \-R "\ port:host:hostport +Specifies that the given port on the remote (server) host is to be +forwarded to the given host and port on the local side. This works +by allocating a socket to listen to +.B port +on the remote side, and whenever a connection is made to this port, the +connection is forwarded over the secure channel, and a connection is +made to +.B host:hostport +from the local machine. Port forwardings can also be specified in the +configuration file. Privileged ports can be forwarded only when +logging in as root on the remote machine. + +.SH CONFIGURATION FILES +.LP +.B Ssh +obtains configuration data from the following sources (in this order): +command line options, user's configuration file +(\fI\&$HOME/\s+2.\s0ssh/config\fR), and system-wide configuration file +(\fI@ETCDIR@/ssh_config\fR). For each parameter, the first obtained value +will be used. The configuration files contain sections bracketed by +"Host" specifications, and that section is only applied for hosts that +match one of the patterns given in the specification. The matched +host name is the one given on the command line. +.LP +Since the first obtained value for each parameter is used, more +host-specific declarations should be given near the beginning of the +file, and general defaults at the end. +.LP +The configuration file has the following format: +.IP +Empty lines and lines starting with '#' are comments. +.IP +Otherwise a line is of the format "keyword arguments". The possible +keywords and their meanings are as follows (note that the +configuration files are case-sensitive): +.ne 3 +.TP +.de YN +"\fByes\fR" or "\fBno\fR". +.. + +.B Host +Restricts the following declarations (up to the next +.B Host +keyword) to be only for those hosts that match one of the patterns +given after the keyword. '*' and '?' can be as wildcards in the +patterns. A single '*' as a pattern can be used to provide global +defaults for all hosts. The host is the +.IR hostname +argument given on the command line (i.e., the name is not converted to +a canonicalized host name before matching). +.ne 3 +.TP +.B AFSTokenPassing +Specifies whether to pass AFS tokens to remote host. The argument to +this keyword must be +.YN +.ne 3 +.TP +.B BatchMode +If set to "yes", passphrase/password querying will be disabled. This +option is useful in scripts and other batch jobs where you have no +user to supply the password. The argument must be +.YN +.ne 3 +.TP +.B Cipher +Specifies the cipher to use for encrypting the session. Currently, +.IR blowfish ", +.IR idea ", +.IR des ", +.IR 3des ", +and +.I none +are supported. The default is "3des". Using "none" (no encryption) is intended +only for debugging, and will render the connection insecure. +.ne 3 +.TP +.B Compression +Specifies whether to use compression. The argument must be +.YN +.ne 3 +.TP +.B CompressionLevel +Specifies the compression level to use if compression is enable. The +argument must be an integer from 1 (fast) to 9 (slow, best). The +default level is 6, which is good for most applications. The meaning +of the values is the same as in GNU GZIP. +.ne 3 +.TP +.B ConnectionAttempts +Specifies the number of tries (one per second) to make before falling +back to rsh or exiting. The argument must be an integer. This may be +useful in scripts if the connection sometimes fails. +.ne 3 +.TP +.B EscapeChar +Sets the escape character (default: ~). The escape character can also +be set on the command line. The argument should be a single +character, '^' followed by a letter, or ``none'' to disable the escape +character entirely (making the connection transparent for binary +data). +.ne 3 +.TP +.B FallBackToRsh +Specifies that if connecting via +.B ssh +fails due to a connection refused error (there is no +.B sshd +listening on the remote host), +.B rsh +should automatically be used instead (after a suitable warning about +the session being unencrypted). The argument must be +.YN +.ne 3 +.TP +.B ForwardAgent +Specifies whether the connection to the authentication agent (if any) +will be forwarded to the remote machine. The argument must be +.YN +.ne 3 +.TP +.B ForwardX11 +Specifies whether X11 connections will be automatically redirected +over the secure channel and +.B \s-1DISPLAY\s0 +set. The argument must be +.YN +.ne 3 +.TP +.B GlobalKnownHostsFile +Specifies a file to use instead of +.IR @ETCDIR@/ssh_known_hosts ". +.ne 3 +.TP +.B HostName +Specifies the real host name to log into. This can be used to specify +nicnames or abbreviations for hosts. Default is the name given on the +command line. Numeric IP addresses are also permitted (both on the +command line and in +.B HostName +specifications). +.ne 3 +.TP +.B IdentityFile +Specifies the file from which the user's RSA authentication identity +is read (default \fI\s+2.\s0ssh/identity\fR in the user's home directory). +Additionally, any identities represented by the authentication agent +will be used for authentication. The file name may use the tilde +syntax to refer to a user's home directory. It is possible to have +multiple identity files specified in configuration files; all these +identities will be tried in sequence. +.ne 3 +.TP +.B KeepAlive +Specifies whether the system should send keepalive messages to the +other side. If they are sent, death of the connection or crash of one +of the machines will be properly noticed. However, this means that +connections will die if the route is down temporarily, and some people +find it annoying. + +The default is "yes" (to send keepalives), and the client will notice +if the network goes down or the remote host dies. This is important +in scripts, and many users want it too. + +To disable keepalives, the value should be set to "no" in both the +server and the client configuration files. +.ne 3 +.TP +.B KerberosAuthentication +Specifies whether Kerberos authentication will be used. +.TP +.B KerberosTgtPassing +Specifies whether a Kerberos TGT will be forwarded to the server. +Note that TGT forwarding is normally not enabled in the server. +.TP +.B LocalForward +Specifies that a TCP/IP port on the local machine be forwarded over +the secure channel to given host:port from the remote machine. The +first argument must be a port number, and the second must be +host:port. Multiple forwardings may be specified, and additional +forwardings can be given on the command line. Only the root can +forward privileged ports. +.ne 3 +.TP +.B PasswordAuthentication +Specifies whether to use password authentication. The argument to +this keyword must be +.YN +.ne 3 +.TP +.B Port +Specifies the port number to connect on the remote host. Default is +22. +.ne 3 +.TP +.B ProxyCommand +Specifies the command to use to connect to the server. The command +string extends to the end of the line, and is executed with /bin/sh. +In the command string, %h will be substituted by the host name to +connect and %p by the port. The command can be basically anything, +and should read from its stdin and write to its stdout. It should +eventually connect an +.B sshd +server running on some machine, or execute +"sshd -i" somewhere. Host key management will be done using the +HostName of the host being connected (defaulting to the name typed by +the user). + +Note that +.B ssh +can also be configured to support the SOCKS system using the +--with-socks compile-time configuration option. +.ne 3 +.TP +.B RemoteForward +Specifies that a TCP/IP port on the remote machine be forwarded over +the secure channel to given host:port from the local machine. The +first argument must be a port number, and the second must be +host:port. Multiple forwardings may be specified, and additional +forwardings can be given on the command line. Only the root can +forward privileged ports. +.ne 3 +.TP +.B RhostsAuthentication +Specifies whether to try rhosts based authentication. Note that this +declaration only affects the client side and has no effect whatsoever +on security. Disabling rhosts authentication may reduce +authentication time on slow connections when rhosts authentication is +not used. Most servers do not permit RhostsAuthentication because it +is not secure (see RhostsRSAAuthentication). The argument to this +keyword must be +.YN +.ne 3 +.TP +.B RhostsRSAAuthentication +Specifies whether to try rhosts based authentication with RSA host +authentication. This is the primary authentication method for most +sites. The argument must be +.YN +.ne 3 +.TP +.B RSAAuthentication +Specifies whether to try RSA authentication. The argument to this +keyword must be +.YN +RSA authentication will only be +attempted if the identity file exists, or an authentication agent is +running. +.ne 3 +.TP +.B StrictHostKeyChecking +If this flag is set to "yes", +.B ssh +ssh will never automatically add host keys to the +.I $HOME/.ssh/known_hosts +file, and refuses to connect hosts whose host key has changed. This +provides maximum protection against trojan horse attacks. However, it +can be somewhat annoying if you don't have good +.I /etc/ssh_known_hosts +files installed and frequently +connect new hosts. Basically this option forces the user to manually +add any new hosts. Normally this option is disabled, and new hosts +will automatically be added to the known host files. The host keys of +known hosts will be verified automatically in either case. The +argument must be +.YN +.ne3 +.TP +.B User +Specifies the user to log in as. This can be useful if you have a +different user name in different machines. This saves the trouble of +having to remember to give the user name on the command line. +.ne 3 +.TP +.B UserKnownHostsFile +Specifies a file to use instead of \fI$HOME/\s+2.\s0ssh/known_hosts\fR. +.ne 3 +.TP +.B UseRsh +Specifies that rlogin/rsh should be used for this host. It is +possible that the host does not at all support the +.B ssh +protocol. This causes +.B ssh +to immediately exec +.B rsh. +All other options (except +.BR HostName ) +are ignored if this has been specified. The argument must be +.YN + +.SH ENVIRONMENT +.LP +.B Ssh +will normally set the following environment variables: +.TP +.B DISPLAY +The DISPLAY variable indicates the location of the X11 server. It is +automatically set by +.B ssh +to point to a value of the form "hostname:n" where hostname indicates +the host where the shell runs, and n is an integer >= 1. Ssh uses +this special value to forward X11 connections over the secure +channel. The user should normally not set DISPLAY explicitly, as that +will render the X11 connection insecure (and will require the user to +manually copy any required authorization cookies). +.ne 3 +.TP +.B HOME +Set to the path of the user's home directory. +.ne 3 +.TP +.B LOGNAME +Synonym for USER; set for compatibility with systems that use +this variable. +.ne 3 +.TP +.B MAIL +Set to point the user's mailbox. +.ne 3 +.TP +.B PATH +Set to the default PATH, as specified when compiling +.B ssh +or, on some systems, +.I /etc/environment +or +.IR /etc/default/login ". +.ne 3 +.TP +.B SSH_AUTHENTICATION_FD +This is set to an integer value if you are using the authentication +agent and a connection to it has been forwarded. The value indicates +a file descriptor number used for communicating with the agent. On +some systems, +.B SSH_AUTHENTICATION_SOCKET +may be used instead to +indicate the path of a unix-domain socket used to communicate with the +agent (this method is less secure, and is only used on systems that +don't support the first method). +.ne 3 +.TP +.B SSH_CLIENT +Identifies the client end of the connection. The variable contains +three space-separated values: client ip-address, client port number, +and server port number. +.ne 3 +.TP +.B SSH_TTY +This is set to the name of the tty (path to the device) associated +with the current shell or command. If the current session has no tty, +this variable is not set. +.ne 3 +.TP +.B TZ +The timezone variable is set to indicate the present timezone if it +was set when the daemon was started (e.i., the daemon passes the value +on to new connections). +.ne 3 +.TP +.B USER +Set to the name of the user logging in. +.LP +.RT +Additionally, +.B ssh +reads +.I /etc/environment +and +.IR $HOME/.ssh/environment ", +and adds lines of +the format +.I VARNAME=value +to the environment. Some systems may have +still additional mechanisms for setting up the environment, such as +.I /etc/default/login +on Solaris. + +.ne 3 +.SH FILES +.TP +.I \&$HOME/\s+2.\s0ssh/known_hosts +Records host keys for all hosts the user has logged into (that are not +in \fI@ETCDIR@/ssh_known_hosts\fR). See +.B sshd +manual page. +.ne 3 +.TP +.I \&$HOME/\s+2.\s0ssh/random_seed +Used for seeding the random number generator. This file contains +sensitive data and should read/write for the user and not accessible +for others. This file is created the first time the program is run +and updated automatically. The user should never need to read or +modify this file. +.ne 5 +.TP +.I \&$HOME/\s+2.\s0ssh/identity +Contains the RSA authentication identity of the user. This file +contains sensitive data and should be readable by the user but not +accessible by others. It is possible to specify a passphrase when +generating the key; the passphrase will be used to encrypt the +sensitive part of this file using +.BR \s-1IDEA\s0 ". +.ne 3 +.TP +.I \&$HOME/\s+2.\s0ssh/identity.pub +Contains the public key for authentication (public part of the +identity file in human-readable form). The contents of this file +should be added to \fI$HOME/\s+2.\s0ssh/authorized_keys\fR on all machines +where you wish to log in using RSA authentication. This file is not +sensitive and can (but need not) be readable by anyone. This file is +never used automatically and is not necessary; it is only provided for +the convenience of the user. +.ne 3 +.TP +.I \&$HOME/\s+2.\s0ssh/config +This is the per-user configuration file. The format of this file is +described above. This file is used by the +.B ssh +client. This file does not usually contain any sensitive information, +but the recommended permissions are read/write for the user, and not +accessible by others. +.ne 3 +.TP +.I \&$HOME/\s+2.\s0ssh/authorized_keys +Lists the RSA keys that can be used for logging in as this user. The +format of this file is described in the +.B sshd +manual page. In the simplest form the format is the same as the .pub +identity files (that is, each line contains the number of bits in +modulus, public exponent, modulus, and comment fields, separated by +spaces). This file is not highly sensitive, but the recommended +permissions are read/write for the user, and not accessible by others. +.ne 3 +.TP +.I @ETCDIR@/ssh_known_hosts +Systemwide list of known host keys. This file should be prepared by the +system administrator to contain the public host keys of all machines in the +organization. This file should be world-readable. This file contains +public keys, one per line, in the following format (fields separated +by spaces): system name, number of bits in modulus, public exponent, +modulus, and optional comment field. When different names are used +for the same machine, all such names should be listed, separated by +commas. The format is described on the +.B sshd +manual page. +.IP +The canonical system name (as returned by name servers) is used by +.B sshd +to verify the client host when logging in; other names are needed because +.B ssh +does not convert the user-supplied name to a canonical name before +checking the key, because someone with access to the name servers +would then be able to fool host authentication. +.ne 3 +.TP +.I @ETCDIR@/ssh_config +Systemwide configuration file. This file provides defaults for those +values that are not specified in the user's configuration file, and +for those users who do not have a configuration file. This file must +be world-readable. +.ne 3 +.TP +.I $HOME/\s+2.\s0rhosts +This file is used in \s+2.\s0rhosts authentication to list the +host/user pairs that are permitted to log in. (Note that this file is +also used by rlogin and rsh, which makes using this file insecure.) +Each line of the file contains a host name (in the canonical form +returned by name servers), and then a user name on that host, +separated by a space. One some machines this file may need to be +world-readable if the user's home directory is on a NFS partition, +because +.B sshd +reads it as root. Additionally, this file must be owned by the user, +and must not have write permissions for anyone else. The recommended +permission for most machines is read/write for the user, and not +accessible by others. +.IP +Note that by default +.B sshd +will be installed so that it requires successful RSA host +authentication before permitting \s+2.\s0rhosts authentication. If your +server machine does not have the client's host key in +\fI@ETCDIR@/ssh_known_hosts\fR, you can store it in +\fI$HOME/\s+2.\s0ssh/known_hosts\fR. The easiest way to do this is to +connect back to the client from the server machine using ssh; this +will automatically add the host key in \fI$HOME/\s+2.\s0ssh/known_hosts\fR. +.ne 3 +.TP +.I $HOME/\s+2.\s0shosts +This file is used exactly the same way as \s+2.\s0rhosts. The purpose for +having this file is to be able to use rhosts authentication with +.B ssh +without permitting login with rlogin or rsh. +.ne 3 +.TP +.I /etc/hosts.equiv +This file is used during \s+2.\s0rhosts authentication. It contains +canonical hosts names, one per line (the full format is described on +the +.B sshd +manual page). If the client host is found in this file, login is +automatically permitted provided client and server user names are the +same. Additionally, successful RSA host authentication is normally +required. This file should only be writable by root. +.TP +.I @ETCDIR@/shosts.equiv +This file is processed exactly as +.IR /etc/hosts.equiv ". +This file may be useful to permit logins using +.B ssh +but not using rsh/rlogin. +.ne 3 +.TP +.I @ETCDIR@/sshrc +Commands in this file are executed by +.B ssh +when the user logs in just before the user's shell (or command) is started. +See the +.B sshd +manual page for more information. +.ne 3 +.TP +.I $HOME/.ssh/rc +Commands in this file are executed by +.B ssh +when the user logs in just before the user's shell (or command) is +started. +See the +.B sshd +manual page for more information. + +.SH INSTALLATION +.LP +.B Ssh +is normally installed as suid root. It needs root privileges only for +rhosts authentication (rhosts authentication requires that the +connection must come from a privileged port, and allocating such a +port requires root privileges). It also needs to be able to read +\fI@ETCDIR@/ssh_host_key\fR to perform +.B \s-1RSA\s0 +host authentication. It is possible to use +.B ssh +without root privileges, but rhosts authentication will then be +disabled. +.B Ssh +drops any extra privileges immediately after the connection to the +remote host has been made. +.LP +Considerable work has been put into making +.B sshd +secure. However, if you find a security problem, please report it +immediately to <ssh-bugs@cs.hut.fi>. + + +.SH AUTHOR +.LP +Tatu Ylonen <ylo@cs.hut.fi> +.LP +Information about new releases, mailing lists, and other related +issues can be found from the ssh WWW home page at +http://www.cs.hut.fi/ssh. + +.SH SEE ALSO +.BR sshd (8), +.BR ssh-keygen (1), +.BR ssh-agent (1), +.BR ssh-add (1), +.BR scp (1), +.BR make-ssh-known-hosts (1), +.BR rlogin (1), +.BR rsh (1), +.BR telnet (1) diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c new file mode 100644 index 00000000000..f67a4f74197 --- /dev/null +++ b/usr.bin/ssh/ssh.c @@ -0,0 +1,813 @@ +/* + +ssh.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Mar 18 16:36:11 1995 ylo + +Ssh client program. This program can be used to log into a remote machine. +The software supports strong authentication, encryption, and forwarding +of X11, TCP/IP, and authentication connections. + +*/ + +#include "includes.h" +RCSID("$Id: ssh.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); + +#include "xmalloc.h" +#include "randoms.h" +#include "ssh.h" +#include "packet.h" +#include "buffer.h" +#include "authfd.h" +#include "readconf.h" +#include "uidswap.h" + +/* Random number generator state. This is initialized in ssh_login, and + left initialized. This is used both by the packet module and by various + other functions. */ +RandomState random_state; + +/* Flag indicating whether debug mode is on. This can be set on the + command line. */ +int debug_flag = 0; + +/* Flag indicating whether quiet mode is on. */ +int quiet_flag = 0; + +/* Flag indicating whether to allocate a pseudo tty. This can be set on the + command line, and is automatically set if no command is given on the command + line. */ +int tty_flag = 0; + +/* Flag indicating that nothing should be read from stdin. This can be set + on the command line. */ +int stdin_null_flag = 0; + +/* Flag indicating that ssh should fork after authentication. This is useful + so that the pasphrase can be entered manually, and then ssh goes to the + background. */ +int fork_after_authentication_flag = 0; + +/* General data structure for command line options and options configurable + in configuration files. See readconf.h. */ +Options options; + +/* 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. */ +char *host; + +#ifdef SIGWINCH +/* 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. */ +volatile int received_window_change_signal = 0; +#endif /* SIGWINCH */ + +/* Value of argv[0] (set in the main program). */ +char *av0; + +/* Flag indicating whether we have a valid host private key loaded. */ +int host_private_key_loaded = 0; + +/* Host private key. */ +RSAPrivateKey host_private_key; + + +/* Prints a help message to the user. This function never returns. */ + +void usage() +{ + int i; + + fprintf(stderr, "Usage: %s [options] host [command]\n", av0); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -l user Log in using this user name.\n"); + fprintf(stderr, " -n Redirect input from /dev/null.\n"); + fprintf(stderr, " -k Disable authentication agent forwarding.\n"); +#if defined(KERBEROS_TGT_PASSING) || defined(AFS) + fprintf(stderr, " This also disables passing of AFS tokens/Kerberos tickets.\n"); +#endif /* KERBEROS_TGT_PASSING || AFS */ + fprintf(stderr, " -x Disable X11 connection forwarding.\n"); + fprintf(stderr, " -i file Identity for RSA authentication (default: ~/.ssh/identity).\n"); + fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n"); + fprintf(stderr, " -v Verbose; display verbose debugging messages.\n"); + fprintf(stderr, " -q Quiet; don't display any warning messages.\n"); + fprintf(stderr, " -f Fork into background after authentication.\n"); + fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n"); + + fprintf(stderr, " -c cipher Select encryption algorithm: "); + for (i = 1; i <= 6; i++) + { + const char *t = cipher_name(i); + if (t[0] == 'n' && t[1] == 'o' && t[2] == ' ') + continue; + fprintf(stderr, "%s, ", t); + } + fprintf(stderr, "or none.\n"); + + fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n"); + fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n"); + fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n"); + fprintf(stderr, " These cause %s to listen for connections on a port, and\n", av0); + fprintf(stderr, " forward them to the other side by connecting to host:port.\n"); +#ifdef WITH_ZLIB + fprintf(stderr, " -C Enable compression.\n"); +#endif /* WITH_ZLIB */ + fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n"); + exit(1); +} + +/* Connects to the given host using rsh (or prints an error message and exits + if rsh is not available). This function never returns. */ + +void rsh_connect(char *host, char *user, Buffer *command) +{ +#ifdef RSH_PATH + char *args[10]; + int i; + + log("Using rsh. WARNING: Connection will not be encrypted."); + /* Build argument list for rsh. */ + i = 0; + args[i++] = RSH_PATH; + args[i++] = host; /* may have to come after user on some systems */ + if (user) + { + args[i++] = "-l"; + args[i++] = user; + } + if (buffer_len(command) > 0) + { + buffer_append(command, "\0", 1); + args[i++] = buffer_ptr(command); + } + args[i++] = NULL; + if (debug_flag) + { + for (i = 0; args[i]; i++) + { + if (i != 0) + fprintf(stderr, " "); + fprintf(stderr, "%s", args[i]); + } + fprintf(stderr, "\n"); + } + execv(RSH_PATH, args); + perror(RSH_PATH); + exit(1); +#else /* RSH_PATH */ + fatal("Rsh not available."); +#endif /* RSH_PATH */ +} + +/* Main program for the ssh client. */ + +int main(int ac, char **av) +{ + int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port, authfd; + char *optarg, *cp, buf[256]; + Buffer command; + struct winsize ws; + struct stat st; + struct passwd *pw, pwcopy; + int interactive = 0, dummy; + uid_t original_real_uid; + uid_t original_effective_uid; + int plen; + + /* Save the original real uid. It will be needed later (uid-swapping may + clobber the real uid). */ + original_real_uid = getuid(); + original_effective_uid = geteuid(); + + /* If we are installed setuid root be careful to not drop core. */ + if (original_real_uid != original_effective_uid) + { +#ifdef HAVE_SETRLIMIT + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 0; + if (setrlimit(RLIMIT_CORE, &rlim) < 0) + fatal("setrlimit failed: %.100s", strerror(errno)); +#else + fatal("ssh is installed setuid root.\n"); +#endif + } + + /* Use uid-swapping to give up root privileges for the duration of option + processing. We will re-instantiate the rights when we are ready to + create the privileged port, and will permanently drop them when the + port has been created (actually, when the connection has been made, as + we may need to create the port several times). */ + temporarily_use_uid(original_real_uid); + +#ifdef HAVE_UMASK + /* Set our umask to something reasonable, as some files are created with + the default umask. This will make them world-readable but writable + only by the owner, which is ok for all files for which we don't set + the modes explicitly. */ + umask(022); +#endif /* HAVE_UMASK */ + + /* Save our own name. */ + av0 = av[0]; + +#ifdef SOCKS + /* Initialize SOCKS (the firewall traversal library). */ + SOCKSinit(av0); +#endif /* SOCKS */ + + /* Set RSA (actually gmp) memory allocation functions. */ + rsa_set_mp_memory_allocation(); + + /* Initialize option structure to indicate that no values have been set. */ + initialize_options(&options); + + /* Parse command-line arguments. */ + host = NULL; + + /* If program name is not one of the standard names, use it as host name. */ + if (strchr(av0, '/')) + cp = strrchr(av0, '/') + 1; + else + cp = av0; + if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 && + strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0) + host = cp; + + for (optind = 1; optind < ac; optind++) + { + if (av[optind][0] != '-') + { + if (host) + break; + host = av[optind]; + continue; + } + opt = av[optind][1]; + if (!opt) + usage(); + if (strchr("eilcpLRo", opt)) /* options with arguments */ + { + optarg = av[optind] + 2; + if (strcmp(optarg, "") == 0) + { + if (optind >= ac - 1) + usage(); + optarg = av[++optind]; + } + } + else + { + if (av[optind][2]) + usage(); + optarg = NULL; + } + switch (opt) + { + case 'n': + stdin_null_flag = 1; + break; + + case 'f': + fork_after_authentication_flag = 1; + stdin_null_flag = 1; + break; + + case 'x': + options.forward_x11 = 0; + break; + + case 'X': + options.forward_x11 = 1; + break; + + case 'a': + options.forward_agent = 0; +#ifdef KERBEROS_TGT_PASSING + options.kerberos_tgt_passing = 0; +#endif +#ifdef AFS + options.afs_token_passing = 0; +#endif + break; + + case 'i': + if (stat(optarg, &st) < 0) + { + fprintf(stderr, "Warning: Identity file %s does not exist.\n", + optarg); + break; + } + if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES) + fatal("Too many identity files specified (max %d)", + SSH_MAX_IDENTITY_FILES); + options.identity_files[options.num_identity_files++] = + xstrdup(optarg); + break; + + case 't': + tty_flag = 1; + break; + + case 'v': + debug_flag = 1; + fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n", + SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR); +#ifdef RSAREF + fprintf(stderr, "Compiled with RSAREF.\n"); +#elif defined(DO_SSL) + fprintf(stderr, "Compiled with SSL.\n"); +#else /* RSAREF */ + fprintf(stderr, "Standard version. Does not use RSAREF.\n"); +#endif /* RSAREF */ + break; + + case 'q': + quiet_flag = 1; + break; + + case 'e': + if (optarg[0] == '^' && optarg[2] == 0 && + (unsigned char)optarg[1] >= 64 && (unsigned char)optarg[1] < 128) + options.escape_char = (unsigned char)optarg[1] & 31; + else + if (strlen(optarg) == 1) + options.escape_char = (unsigned char)optarg[0]; + else + if (strcmp(optarg, "none") == 0) + options.escape_char = -2; + else + { + fprintf(stderr, "Bad escape character '%s'.\n", optarg); + exit(1); + } + break; + + case 'c': + options.cipher = cipher_number(optarg); + if (options.cipher == -1) + { + fprintf(stderr, "Unknown cipher type '%s'\n", optarg); + exit(1); + } + break; + + case 'p': + options.port = atoi(optarg); + if (options.port < 1 || options.port > 65535) + { + fprintf(stderr, "Bad port %s.\n", optarg); + exit(1); + } + break; + + case 'l': + options.user = optarg; + break; + + case 'R': + if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf, + &fwd_host_port) != 3) + { + fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg); + usage(); + /*NOTREACHED*/ + } + add_remote_forward(&options, fwd_port, buf, fwd_host_port); + break; + + case 'L': + if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf, + &fwd_host_port) != 3) + { + fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg); + usage(); + /*NOTREACHED*/ + } + if (fwd_port < 1024 && original_real_uid != 0) + { + fprintf(stderr, + "Privileged ports can only be forwarded by root.\n"); + exit(1); + } + add_local_forward(&options, fwd_port, buf, fwd_host_port); + break; + +#ifdef WITH_ZLIB + case 'C': + options.compression = 1; + break; +#endif /* WITH_ZLIB */ + + case 'o': + dummy = 1; + process_config_line(&options, host ? host : "", optarg, + "command-line", 0, &dummy); + break; + + default: + usage(); + } + } + + /* Check that we got a host name. */ + if (!host) + usage(); + + /* Initialize the command to execute on remote host. */ + buffer_init(&command); + + /* Save the command to execute on the remote host in a buffer. There is + no limit on the length of the command, except by the maximum packet + size. Also sets the tty flag if there is no command. */ + if (optind == ac) + { + /* No command specified - execute shell on a tty. */ + tty_flag = 1; + } + else + { + /* A command has been specified. Store it into the buffer. */ + for (i = optind; i < ac; i++) + { + if (i > optind) + buffer_append(&command, " ", 1); + buffer_append(&command, av[i], strlen(av[i])); + } + } + + /* Cannot fork to background if no command. */ + if (fork_after_authentication_flag && buffer_len(&command) == 0) + fatal("Cannot fork into background without a command to execute."); + + /* Allocate a tty by default if no command specified. */ + if (buffer_len(&command) == 0) + tty_flag = 1; + + /* Do not allocate a tty if stdin is not a tty. */ + if (!isatty(fileno(stdin))) + { + if (tty_flag) + fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n"); + tty_flag = 0; + } + + /* Get user data. */ + pw = getpwuid(original_real_uid); + if (!pw) + { + fprintf(stderr, "You don't exist, go away!\n"); + exit(1); + } + + /* Take a copy of the returned structure. */ + memset(&pwcopy, 0, sizeof(pwcopy)); + pwcopy.pw_name = xstrdup(pw->pw_name); + pwcopy.pw_passwd = xstrdup(pw->pw_passwd); + pwcopy.pw_uid = pw->pw_uid; + pwcopy.pw_gid = pw->pw_gid; + pwcopy.pw_dir = xstrdup(pw->pw_dir); + pwcopy.pw_shell = xstrdup(pw->pw_shell); + pw = &pwcopy; + + /* Initialize "log" output. Since we are the client all output actually + goes to the terminal. */ + log_init(av[0], 1, debug_flag, quiet_flag, SYSLOG_FACILITY_USER); + + /* Read per-user configuration file. */ + sprintf(buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE); + read_config_file(buf, host, &options); + + /* Read systemwide configuration file. */ + read_config_file(HOST_CONFIG_FILE, host, &options); + + /* Fill configuration defaults. */ + fill_default_options(&options); + if (options.user == NULL) + options.user = xstrdup(pw->pw_name); + + if (options.hostname != NULL) + host = options.hostname; + + /* Find canonic host name. */ + if (strchr(host, '.') == 0) + { + struct hostent *hp = gethostbyname(host); + if (hp != 0) + { + if (strchr(hp->h_name, '.') != 0) + host = xstrdup(hp->h_name); + else if (hp->h_aliases != 0 + && hp->h_aliases[0] != 0 + && strchr(hp->h_aliases[0], '.') != 0) + host = xstrdup(hp->h_aliases[0]); + } + } + + /* Disable rhosts authentication if not running as root. */ + if (original_effective_uid != 0) + { + options.rhosts_authentication = 0; + options.rhosts_rsa_authentication = 0; + } + + /* If using rsh has been selected, exec it now (without trying anything + else). Note that we must release privileges first. */ + if (options.use_rsh) + { + /* Restore our superuser privileges. This must be done before + permanently setting the uid. */ + restore_uid(); + + /* Switch to the original uid permanently. */ + permanently_set_uid(original_real_uid); + + /* Execute rsh. */ + rsh_connect(host, options.user, &command); + fatal("rsh_connect returned"); + } + + /* Restore our superuser privileges. */ + restore_uid(); + + /* Open a connection to the remote host. This needs root privileges if + rhosts_authentication is true. Note that the random_state is not + yet used by this call, although a pointer to it is stored, and thus it + need not be initialized. */ + ok = ssh_connect(host, options.port, options.connection_attempts, + !options.rhosts_authentication && + !options.rhosts_rsa_authentication, + original_real_uid, options.proxy_command, &random_state); + + /* If we successfully made the connection, load the host private key in + case we will need it later for combined rsa-rhosts authentication. + This must be done before releasing extra privileges, because the file + is only readable by root. */ + if (ok) + { + if (load_private_key(HOST_KEY_FILE, "", &host_private_key, NULL)) + host_private_key_loaded = 1; + } + + /* Get rid of any extra privileges that we may have. We will no longer need + them. Also, extra privileges could make it very hard to read identity + files and other non-world-readable files from the user's home directory + if it happens to be on a NFS volume where root is mapped to nobody. */ + permanently_set_uid(original_real_uid); + + /* Now that we are back to our own permissions, create ~/.ssh directory + if it doesn\'t already exist. */ + sprintf(buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR); + if (stat(buf, &st) < 0) + if (mkdir(buf, 0755) < 0) + error("Could not create directory '%.200s'.", buf); + + /* Check if the connection failed, and try "rsh" if appropriate. */ + if (!ok) + { + if (options.port != 0) + log("Secure connection to %.100s on port %d refused%.100s.", + host, options.port, + options.fallback_to_rsh ? "; reverting to insecure method" : ""); + else + log("Secure connection to %.100s refused%.100s.", host, + options.fallback_to_rsh ? "; reverting to insecure method" : ""); + + if (options.fallback_to_rsh) + { + rsh_connect(host, options.user, &command); + fatal("rsh_connect returned"); + } + exit(1); + } + + /* Expand ~ in options.identity_files. */ + for (i = 0; i < options.num_identity_files; i++) + options.identity_files[i] = + tilde_expand_filename(options.identity_files[i], original_real_uid); + + /* Expand ~ in known host file names. */ + options.system_hostfile = tilde_expand_filename(options.system_hostfile, + original_real_uid); + options.user_hostfile = tilde_expand_filename(options.user_hostfile, + original_real_uid); + + /* Log into the remote system. This never returns if the login fails. + Note: this initializes the random state, and leaves it initialized. */ + ssh_login(&random_state, host_private_key_loaded, &host_private_key, + host, &options, original_real_uid); + + /* We no longer need the host private key. Clear it now. */ + if (host_private_key_loaded) + rsa_clear_private_key(&host_private_key); + + /* Close connection cleanly after attack. */ + cipher_attack_detected = packet_disconnect; + + /* If requested, fork and let ssh continue in the background. */ + if (fork_after_authentication_flag) + { + int ret = fork(); + if (ret == -1) + fatal("fork failed: %.100s", strerror(errno)); + if (ret != 0) + exit(0); +#ifdef HAVE_SETSID + setsid(); +#endif /* HAVE_SETSID */ + } + +#ifdef WITH_ZLIB + /* Enable compression if requested. */ + if (options.compression) + { + debug("Requesting compression at level %d.", options.compression_level); + + if (options.compression_level < 1 || options.compression_level > 9) + fatal("Compression level must be from 1 (fast) to 9 (slow, best)."); + + /* Send the request. */ + packet_start(SSH_CMSG_REQUEST_COMPRESSION); + packet_put_int(options.compression_level); + packet_send(); + packet_write_wait(); + type = packet_read(&plen); + if (type == SSH_SMSG_SUCCESS) + packet_start_compression(options.compression_level); + else if (type == SSH_SMSG_FAILURE) + log("Warning: Remote host refused compression."); + else + packet_disconnect("Protocol error waiting for compression response."); + } +#endif /* WITH_ZLIB */ + + /* Allocate a pseudo tty if appropriate. */ + if (tty_flag) + { + debug("Requesting pty."); + + /* Start the packet. */ + packet_start(SSH_CMSG_REQUEST_PTY); + + /* Store TERM in the packet. There is no limit on the length of the + string. */ + cp = getenv("TERM"); + if (!cp) + cp = ""; + packet_put_string(cp, strlen(cp)); + + /* Store window size in the packet. */ + if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) + memset(&ws, 0, sizeof(ws)); + packet_put_int(ws.ws_row); + packet_put_int(ws.ws_col); + packet_put_int(ws.ws_xpixel); + packet_put_int(ws.ws_ypixel); + + /* Store tty modes in the packet. */ + tty_make_modes(fileno(stdin)); + + /* Send the packet, and wait for it to leave. */ + packet_send(); + packet_write_wait(); + + /* Read response from the server. */ + type = packet_read(&plen); + if (type == SSH_SMSG_SUCCESS) + interactive = 1; + else if (type == SSH_SMSG_FAILURE) + log("Warning: Remote host failed or refused to allocate a pseudo tty."); + else + packet_disconnect("Protocol error waiting for pty request response."); + } + + /* Request X11 forwarding if enabled and DISPLAY is set. */ + if (options.forward_x11 && getenv("DISPLAY") != NULL) + { + char line[512], proto[512], data[512]; + FILE *f; + int forwarded = 0, got_data = 0, i; + +#ifdef XAUTH_PATH + /* Try to get Xauthority information for the display. */ + sprintf(line, "%.100s list %.200s 2>/dev/null", + XAUTH_PATH, getenv("DISPLAY")); + f = popen(line, "r"); + if (f && fgets(line, sizeof(line), f) && + sscanf(line, "%*s %s %s", proto, data) == 2) + got_data = 1; + if (f) + pclose(f); +#endif /* XAUTH_PATH */ + /* If we didn't get authentication data, just make up some data. The + forwarding code will check the validity of the response anyway, and + substitute this data. The X11 server, however, will ignore this + fake data and use whatever authentication mechanisms it was using + otherwise for the local connection. */ + if (!got_data) + { + strcpy(proto, "MIT-MAGIC-COOKIE-1"); + for (i = 0; i < 16; i++) + sprintf(data + 2 * i, "%02x", random_get_byte(&random_state)); + } + + /* Got local authentication reasonable information. Request forwarding + with authentication spoofing. */ + debug("Requesting X11 forwarding with authentication spoofing."); + x11_request_forwarding_with_spoofing(&random_state, proto, data); + + /* Read response from the server. */ + type = packet_read(&plen); + if (type == SSH_SMSG_SUCCESS) + { + forwarded = 1; + interactive = 1; + } + else if (type == SSH_SMSG_FAILURE) + log("Warning: Remote host denied X11 forwarding."); + else + packet_disconnect("Protocol error waiting for X11 forwarding"); + } + + /* Tell the packet module whether this is an interactive session. */ + packet_set_interactive(interactive, options.keepalives); + + /* Clear agent forwarding if we don\'t have an agent. */ + authfd = ssh_get_authentication_fd(); + if (authfd < 0) + options.forward_agent = 0; + else + ssh_close_authentication_socket(authfd); + + /* Request authentication agent forwarding if appropriate. */ + if (options.forward_agent) + { + debug("Requesting authentication agent forwarding."); + auth_request_forwarding(); + + /* Read response from the server. */ + type = packet_read(&plen); + packet_integrity_check(plen, 0, type); + if (type != SSH_SMSG_SUCCESS) + log("Warning: Remote host denied authentication agent forwarding."); + } + + /* Initiate local TCP/IP port forwardings. */ + for (i = 0; i < options.num_local_forwards; i++) + { + debug("Connections to local port %d forwarded to remote address %.200s:%d", + options.local_forwards[i].port, options.local_forwards[i].host, + options.local_forwards[i].host_port); + channel_request_local_forwarding(options.local_forwards[i].port, + options.local_forwards[i].host, + options.local_forwards[i].host_port); + } + + /* Initiate remote TCP/IP port forwardings. */ + for (i = 0; i < options.num_remote_forwards; i++) + { + debug("Connections to remote port %d forwarded to local address %.200s:%d", + options.remote_forwards[i].port, options.remote_forwards[i].host, + options.remote_forwards[i].host_port); + channel_request_remote_forwarding(options.remote_forwards[i].port, + options.remote_forwards[i].host, + options.remote_forwards[i].host_port); + } + + /* If a command was specified on the command line, execute the command now. + Otherwise request the server to start a shell. */ + if (buffer_len(&command) > 0) + { + int len = buffer_len(&command); + if (len > 900) + len = 900; + debug("Sending command: %.*s", len, buffer_ptr(&command)); + packet_start(SSH_CMSG_EXEC_CMD); + packet_put_string(buffer_ptr(&command), buffer_len(&command)); + packet_send(); + packet_write_wait(); + } + else + { + debug("Requesting shell."); + packet_start(SSH_CMSG_EXEC_SHELL); + packet_send(); + packet_write_wait(); + } + + /* Enter the interactive session. */ + exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1); + + /* Close the connection to the remote host. */ + packet_close(); + + /* Exit with the status returned by the program on the remote side. */ + exit(exit_status); +} diff --git a/usr.bin/ssh/ssh.h b/usr.bin/ssh/ssh.h new file mode 100644 index 00000000000..3aa6d8804f4 --- /dev/null +++ b/usr.bin/ssh/ssh.h @@ -0,0 +1,596 @@ +/* + +ssh.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Fri Mar 17 17:09:37 1995 ylo + +Generic header file for ssh. + +*/ + +/* RCSID("$Id: ssh.h,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); */ + +#ifndef SSH_H +#define SSH_H + +#include <gmp.h> +#include "rsa.h" +#include "randoms.h" +#include "cipher.h" + +/* The default cipher used if IDEA is not supported by the remote host. + It is recommended that this be one of the mandatory ciphers (DES, 3DES), + though that is not required. */ +#define SSH_FALLBACK_CIPHER SSH_CIPHER_3DES + +/* Cipher used for encrypting authentication files. */ +#define SSH_AUTHFILE_CIPHER SSH_CIPHER_3DES + +/* Default port number. */ +#define SSH_DEFAULT_PORT 22 + +/* Maximum number of TCP/IP ports forwarded per direction. */ +#define SSH_MAX_FORWARDS_PER_DIRECTION 100 + +/* Maximum number of RSA authentication identity files that can be specified + in configuration files or on the command line. */ +#define SSH_MAX_IDENTITY_FILES 100 + +/* Major protocol version. Different version indicates major incompatiblity + that prevents communication. */ +#define PROTOCOL_MAJOR 1 + +/* Minor protocol version. Different version indicates minor incompatibility + that does not prevent interoperation. */ +#define PROTOCOL_MINOR 3 + +/* Name for the service. The port named by this service overrides the default + port if present. */ +#define SSH_SERVICE_NAME "ssh" + +/* System-wide file containing host keys of known hosts. This file should be + world-readable. */ +#define SSH_SYSTEM_HOSTFILE ETCDIR "/ssh_known_hosts" + +/* HOST_KEY_FILE /etc/ssh_host_key, + SERVER_CONFIG_FILE /etc/sshd_config, +and HOST_CONFIG_FILE /etc/ssh_config +are all defined in Makefile.in. Of these, ssh_host_key should be readable +only by root, whereas ssh_config should be world-readable. */ + +/* Random seed file for the daemon. This file should be readable only by + root. */ +#define SSH_DAEMON_SEED_FILE ETCDIR "/ssh_random_seed" + +/* The process id of the daemon listening for connections is saved + here to make it easier to kill the correct daemon when necessary. */ +#define SSH_DAEMON_PID_FILE PIDDIR "/sshd.pid" + +/* The directory in user\'s home directory in which the files reside. + The directory should be world-readable (though not all files are). */ +#define SSH_USER_DIR ".ssh" + +/* Per-user file containing host keys of known hosts. This file need + not be readable by anyone except the user him/herself, though this does + not contain anything particularly secret. */ +#define SSH_USER_HOSTFILE "~/.ssh/known_hosts" + +/* Name of the file containing client-side random seed. This file should + only be readable by the user him/herself. */ +#define SSH_CLIENT_SEEDFILE ".ssh/random_seed" + +/* Name of the default file containing client-side authentication key. + This file should only be readable by the user him/herself. */ +#define SSH_CLIENT_IDENTITY ".ssh/identity" + +/* Configuration file in user\'s home directory. This file need not be + readable by anyone but the user him/herself, but does not contain + anything particularly secret. If the user\'s home directory resides + on an NFS volume where root is mapped to nobody, this may need to be + world-readable. */ +#define SSH_USER_CONFFILE ".ssh/config" + +/* File containing a list of those rsa keys that permit logging in as + this user. This file need not be + readable by anyone but the user him/herself, but does not contain + anything particularly secret. If the user\'s home directory resides + on an NFS volume where root is mapped to nobody, this may need to be + world-readable. (This file is read by the daemon which is running as + root.) */ +#define SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys" + +/* Per-user and system-wide ssh "rc" files. These files are executed with + /bin/sh before starting the shell or command if they exist. They + will be passed "proto cookie" as arguments if X11 forwarding with + spoofing is in use. xauth will be run if neither of these exists. */ +#define SSH_USER_RC ".ssh/rc" +#define SSH_SYSTEM_RC ETCDIR "/sshrc" + +/* Ssh-only version of /etc/hosts.equiv. */ +#define SSH_HOSTS_EQUIV ETCDIR "/shosts.equiv" + +/* Additionally, the daemon may use ~/.rhosts and /etc/hosts.equiv if + rhosts authentication is enabled. */ + +/* Socket for connecting the authentication agent. Normally the connection + to the authentication agent is passed in a file descriptor; however, + on some systems, commonly used shells close all open file descriptors. + To make the agent usable on those systems, configure checks whether + the shells close all descriptors, and if so, defines AGENT_USES_SOCKET. + That socket is an unix-domain socket and will be stored with this name + in the user\'s home directory. The socket must not be accessible by + anyone but the user him/herself. The number at the end of the name + is the pid of the agent or the forwarding daemon. Note that this + socket is stored in /tmp, which is supposedly on the local machine. If + this were in the user\'s home directory, the daemon (running as root) + might not be able to create and chown the file to the user\'s uid. */ +#define SSH_AGENT_SOCKET "/tmp/ssh_agent.%d" + +/* Name of the environment variable containing the authentication fd. */ +#define SSH_AUTHFD_ENV_NAME "SSH_AUTHENTICATION_FD" + +/* Name of the environment variable containing the pathname of the + authentication socket. */ +#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTHENTICATION_SOCKET" + +/* Force host key length and server key length to differ by at least this + many bits. This is to make double encryption with rsaref work. */ +#define SSH_KEY_BITS_RESERVED 128 + +/* Length of the session key in bytes. (Specified as 256 bits in the + protocol.) */ +#define SSH_SESSION_KEY_LENGTH 32 + +/* Name of Kerberos service for SSH to use. */ +#define KRB4_SERVICE_NAME "rcmd" + +/* Authentication methods. New types can be added, but old types should not + be removed for compatibility. The maximum allowed value is 31. */ +#define SSH_AUTH_RHOSTS 1 +#define SSH_AUTH_RSA 2 +#define SSH_AUTH_PASSWORD 3 +#define SSH_AUTH_RHOSTS_RSA 4 + /* 5 is TIS */ +#define SSH_AUTH_KERBEROS 6 +#define SSH_PASS_KERBEROS_TGT 7 +#define SSH_PASS_AFS_TOKEN 21 + +/* Protocol flags. These are bit masks. */ +#define SSH_PROTOFLAG_SCREEN_NUMBER 1 /* X11 forwarding includes screen */ +#define SSH_PROTOFLAG_HOST_IN_FWD_OPEN 2 /* forwarding opens contain host */ + +/* Definition of message types. New values can be added, but old values + should not be removed or without careful consideration of the consequences + for compatibility. The maximum value is 254; value 255 is reserved + for future extension. */ +/* Message name */ /* msg code */ /* arguments */ +#define SSH_MSG_NONE 0 /* no message */ +#define SSH_MSG_DISCONNECT 1 /* cause (string) */ +#define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */ +#define SSH_CMSG_SESSION_KEY 3 /* key (MP_INT) */ +#define SSH_CMSG_USER 4 /* user (string) */ +#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */ +#define SSH_CMSG_AUTH_RSA 6 /* modulus (MP_INT) */ +#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (MP_INT) */ +#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (MP_INT) */ +#define SSH_CMSG_AUTH_PASSWORD 9 /* pass (string) */ +#define SSH_CMSG_REQUEST_PTY 10 /* TERM, tty modes */ +#define SSH_CMSG_WINDOW_SIZE 11 /* row,col,xpix,ypix */ +#define SSH_CMSG_EXEC_SHELL 12 /* */ +#define SSH_CMSG_EXEC_CMD 13 /* cmd (string) */ +#define SSH_SMSG_SUCCESS 14 /* */ +#define SSH_SMSG_FAILURE 15 /* */ +#define SSH_CMSG_STDIN_DATA 16 /* data (string) */ +#define SSH_SMSG_STDOUT_DATA 17 /* data (string) */ +#define SSH_SMSG_STDERR_DATA 18 /* data (string) */ +#define SSH_CMSG_EOF 19 /* */ +#define SSH_SMSG_EXITSTATUS 20 /* status (int) */ +#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 21 /* channel (int) */ +#define SSH_MSG_CHANNEL_OPEN_FAILURE 22 /* channel (int) */ +#define SSH_MSG_CHANNEL_DATA 23 /* ch,data (int,str) */ +#define SSH_MSG_CHANNEL_CLOSE 24 /* channel (int) */ +#define SSH_MSG_CHANNEL_CLOSE_CONFIRMATION 25 /* channel (int) */ +/* SSH_CMSG_X11_REQUEST_FORWARDING 26 OBSOLETE */ +#define SSH_SMSG_X11_OPEN 27 /* channel (int) */ +#define SSH_CMSG_PORT_FORWARD_REQUEST 28 /* p,host,hp (i,s,i) */ +#define SSH_MSG_PORT_OPEN 29 /* ch,h,p (i,s,i) */ +#define SSH_CMSG_AGENT_REQUEST_FORWARDING 30 /* */ +#define SSH_SMSG_AGENT_OPEN 31 /* port (int) */ +#define SSH_MSG_IGNORE 32 /* string */ +#define SSH_CMSG_EXIT_CONFIRMATION 33 /* */ +#define SSH_CMSG_X11_REQUEST_FORWARDING 34 /* proto,data (s,s) */ +#define SSH_CMSG_AUTH_RHOSTS_RSA 35 /* user,mod (s,mpi) */ +#define SSH_MSG_DEBUG 36 /* string */ +#define SSH_CMSG_REQUEST_COMPRESSION 37 /* level 1-9 (int) */ + +#define SSH_CMSG_AUTH_KERBEROS 42 /* (KTEXT) */ +#define SSH_SMSG_AUTH_KERBEROS_RESPONSE 43 /* (KTEXT) */ +#define SSH_CMSG_HAVE_KERBEROS_TGT 44 /* credentials (s) */ +#define SSH_CMSG_HAVE_AFS_TOKEN 65 /* token (s) */ + + +/* Includes that need definitions above. */ + +#include "readconf.h" + +/*------------ definitions for login.c -------------*/ + +/* Returns the time when the user last logged in. Returns 0 if the + information is not available. This must be called before record_login. + The host from which the user logged in is stored in buf. */ +unsigned long get_last_login_time(uid_t uid, const char *logname, + char *buf, unsigned int bufsize); + +/* Records that the user has logged in. This does many things normally + done by login(1). */ +void record_login(int pid, const char *ttyname, const char *user, uid_t uid, + const char *host, struct sockaddr_in *addr); + +/* Records that the user has logged out. This does many thigs normally + done by login(1) or init. */ +void record_logout(int pid, const char *ttyname); + +/*------------ definitions for sshconnect.c ----------*/ + +/* Opens a TCP/IP connection to the remote server on the given host. If + port is 0, the default port will be used. If anonymous is zero, + a privileged port will be allocated to make the connection. + This requires super-user privileges if anonymous is false. + Connection_attempts specifies the maximum number of tries, one per + second. This returns true on success, and zero on failure. If the + connection is successful, this calls packet_set_connection for the + connection. */ +int ssh_connect(const char *host, int port, int connection_attempts, + int anonymous, uid_t original_real_uid, + const char *proxy_command, RandomState *random_state); + +/* Starts a dialog with the server, and authenticates the current user on the + server. This does not need any extra privileges. The basic connection + to the server must already have been established before this is called. + If login fails, this function prints an error and never returns. + This initializes the random state, and leaves it initialized (it will also + have references from the packet module). */ +void ssh_login(RandomState *state, int host_key_valid, RSAPrivateKey *host_key, + const char *host, Options *options, uid_t original_real_uid); + +/*------------ Definitions for various authentication methods. -------*/ + +/* Tries to authenticate the user using the .rhosts file. Returns true if + authentication succeeds. If ignore_rhosts is non-zero, this will not + consider .rhosts and .shosts (/etc/hosts.equiv will still be used). + If strict_modes is true, checks ownership and modes of .rhosts/.shosts. */ +int auth_rhosts(struct passwd *pw, const char *client_user, + 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(RandomState *state, + struct passwd *pw, const char *client_user, + unsigned int bits, MP_INT *client_host_key_e, + MP_INT *client_host_key_n, int ignore_rhosts, + int strict_modes); + +/* Tries to authenticate the user using password. Returns true if + authentication succeeds. */ +int auth_password(const char *server_user, const char *password); + +/* 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, MP_INT *client_n, RandomState *state); + +/* Parses an RSA key (number of bits, e, n) from a string. Moves the pointer + over the key. Skips any whitespace at the beginning and at end. */ +int auth_rsa_read_key(char **cpp, unsigned int *bitsp, MP_INT *e, MP_INT *n); + +/* Returns the name of the machine at the other end of the socket. The + returned string should be freed by the caller. */ +char *get_remote_hostname(int socket); + +/* Return the canonical name of the host in the other side of the current + connection (as returned by packet_get_connection). The host name is + cached, so it is efficient to call this several times. */ +const char *get_canonical_hostname(void); + +/* Returns the remote IP address as an ascii string. The value need not be + freed by the caller. */ +const char *get_remote_ipaddr(void); + +/* Returns the port number of the peer of the socket. */ +int get_peer_port(int sock); + +/* Returns the port number of the remote host. */ +int get_remote_port(void); + +/* Tries to match the host name (which must be in all lowercase) against the + comma-separated sequence of subpatterns (each possibly preceded by ! to + indicate negation). Returns true if there is a positive match; zero + otherwise. */ +int match_hostname(const char *host, const char *pattern, unsigned int len); + +/* Checks whether the given host is already in the list of our known hosts. + Returns HOST_OK if the host is known and has the specified key, + HOST_NEW if the host is not known, and HOST_CHANGED if the host is known + but used to have a different host key. The host must be in all lowercase. */ +typedef enum { HOST_OK, HOST_NEW, HOST_CHANGED } HostStatus; +HostStatus check_host_in_hostfile(const char *filename, + const char *host, unsigned int bits, + MP_INT *e, MP_INT *n); + +/* Appends an entry to the host file. Returns false if the entry + could not be appended. */ +int add_host_to_hostfile(const char *filename, const char *host, + unsigned int bits, MP_INT *e, MP_INT *n); + +/* 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(RandomState *state, unsigned int bits, + MP_INT *e, MP_INT *n); + +/* Reads a passphrase from /dev/tty with echo turned off. Returns the + passphrase (allocated with xmalloc). Exits if EOF is encountered. + If from_stdin is true, the passphrase will be read from stdin instead. */ +char *read_passphrase(const char *prompt, int from_stdin); + +/* 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, + RSAPrivateKey *private_key, const char *comment, + RandomState *state); + +/* Loads the public part of the key file (public key and comment). + Returns 0 if an error occurred; zero if the public key was successfully + read. The comment of the key is returned in comment_return if it is + non-NULL; the caller must free the value with xfree. */ +int load_public_key(const char *filename, RSAPublicKey *pub, + char **comment_return); + +/* 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. The comment of the key is returned + in comment_return if it is non-NULL; the caller must free the value + with xfree. */ +int load_private_key(const char *filename, const char *passphrase, + RSAPrivateKey *private_key, char **comment_return); + +/*------------ Definitions for logging. -----------------------*/ + +/* Supported syslog facilities. */ +typedef enum +{ + SYSLOG_FACILITY_DAEMON, + SYSLOG_FACILITY_USER, + SYSLOG_FACILITY_AUTH, + SYSLOG_FACILITY_LOCAL0, + SYSLOG_FACILITY_LOCAL1, + SYSLOG_FACILITY_LOCAL2, + SYSLOG_FACILITY_LOCAL3, + SYSLOG_FACILITY_LOCAL4, + SYSLOG_FACILITY_LOCAL5, + SYSLOG_FACILITY_LOCAL6, + SYSLOG_FACILITY_LOCAL7 +} SyslogFacility; + +/* Initializes logging. If debug is non-zero, debug() will output something. + If quiet is non-zero, none of these will log send anything to syslog + (but maybe to stderr). */ +void log_init(char *av0, int on_stderr, int debug, int quiet, + SyslogFacility facility); + +/* Outputs a message to syslog or stderr, depending on the implementation. + The format must guarantee that the final message does not exceed 1024 + characters. The message should not contain newline. */ +void log(const char *fmt, ...); + +/* Outputs a message to syslog or stderr, depending on the implementation. + The format must guarantee that the final message does not exceed 1024 + characters. The message should not contain newline. */ +void debug(const char *fmt, ...); + +/* Outputs a message to syslog or stderr, depending on the implementation. + The format must guarantee that the final message does not exceed 1024 + characters. The message should not contain newline. */ +void error(const char *fmt, ...); + +/* Outputs a message to syslog or stderr, depending on the implementation. + The format must guarantee that the final message does not exceed 1024 + characters. The message should not contain newline. + This call never returns. */ +void fatal(const char *fmt, ...); + +/* Registers a cleanup function to be called by fatal() before exiting. + It is permissible to call fatal_remove_cleanup for the function itself + from the function. */ +void fatal_add_cleanup(void (*proc)(void *context), void *context); + +/* Removes a cleanup frunction to be called at fatal(). */ +void fatal_remove_cleanup(void (*proc)(void *context), void *context); + +/*---------------- definitions for x11.c ------------------*/ + + +/* Sets specific protocol options. */ +void channel_set_options(int hostname_in_open); + +/* Allocate a new channel object and set its type and socket. Remote_name + must have been allocated with xmalloc; this will free it when the channel + is freed. */ +int channel_allocate(int type, int sock, char *remote_name); + +/* Free the channel and close its socket. */ +void channel_free(int channel); + +/* Add any bits relevant to channels in select bitmasks. */ +void channel_prepare_select(fd_set *readset, fd_set *writeset); + +/* After select, perform any appropriate operations for channels which + have events pending. */ +void channel_after_select(fd_set *readset, fd_set *writeset); + +/* If there is data to send to the connection, send some of it now. */ +void channel_output_poll(void); + +/* 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); + +/* Returns true if no channel has too much buffered data. */ +int channel_not_very_much_buffered_data(void); + +/* This is called after receiving CHANNEL_CLOSE. */ +void channel_input_close(void); + +/* This is called after receiving CHANNEL_CLOSE_CONFIRMATION. */ +void channel_input_close_confirmation(void); + +/* This is called after receiving CHANNEL_OPEN_CONFIRMATION. */ +void channel_input_open_confirmation(void); + +/* This is called after receiving CHANNEL_OPEN_FAILURE from the other side. */ +void channel_input_open_failure(void); + +/* This closes any sockets that are listening for connections; this removes + any unix domain sockets. */ +void channel_stop_listening(void); + +/* Closes the sockets of all channels. This is used to close extra file + descriptors after a fork. */ +void channel_close_all(void); + +/* Returns the maximum file descriptor number used by the channels. */ +int channel_max_fd(void); + +/* Returns true if there is still an open channel over the connection. */ +int channel_still_open(void); + +/* Returns a string containing a list of all open channels. The list is + suitable for displaying to the user. It uses crlf instead of newlines. + The caller should free the string with xfree. */ +char *channel_open_message(void); + +/* Initiate forwarding of connections to local port "port" through the secure + channel to host:port from remote side. This never returns if there + was an error. */ +void channel_request_local_forwarding(int port, const char *host, + int remote_port); + +/* Initiate forwarding of connections to port "port" on remote host through + the secure channel to host:port from local side. This never returns + if there was an error. This registers that open requests for that + port are permitted. */ +void channel_request_remote_forwarding(int port, const char *host, + int remote_port); + +/* 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(void); + +/* 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); + +/* 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); + +/* Creates a port for X11 connections, and starts listening for it. + Returns the display name, or NULL if an error was encountered. */ +char *x11_create_display(int screen); + +/* 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); + +/* 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); + +/* Requests forwarding of X11 connections. This should be called on the + client only. */ +void x11_request_forwarding(void); + +/* Requests forwarding for X11 connections, with authentication spoofing. + This should be called in the client only. */ +void x11_request_forwarding_with_spoofing(RandomState *state, + const char *proto, const char *data); + +/* Local Xauthority file (server only). */ +extern char *xauthfile; + +/* Sends a message to the server to request authentication fd forwarding. */ +void auth_request_forwarding(void); + +/* Returns the number of the file descriptor to pass to child programs as + the authentication fd. */ +int auth_get_fd(void); + +/* 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(void); + +/* 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); + +/* This is called to process an SSH_SMSG_AGENT_OPEN message. */ +void auth_input_open_request(void); + +/* Returns true if the given string matches the pattern (which may contain + ? and * as wildcards), and zero if it does not match. */ +int match_pattern(const char *s, const char *pattern); + +/* Expands tildes in the file name. Returns data allocated by xmalloc. + Warning: this calls getpw*. */ +char *tilde_expand_filename(const char *filename, uid_t my_uid); + +/* Gets a file descriptor that won't get closed by shell pathname. + If pathname is NULL, the path is inferred from the SHELL environment + variable or the user id. */ +int get_permanent_fd(const char *pathname); + +/* Performs the interactive session. This handles data transmission between + the client and the program. Note that the notion of stdin, stdout, and + stderr in this function is sort of reversed: this function writes to + stdin (of the child program), and reads from stdout and stderr (of the + child program). */ +void server_loop(int pid, int fdin, int fdout, int fderr); + +/* Client side main loop for the interactive session. */ +int client_loop(int have_pty, int escape_char); + +/* Linked list of custom environment strings (see auth-rsa.c). */ +struct envstring { + struct envstring *next; + char *s; +}; + +#ifdef KRB4 +#include <krb.h> + +int ssh_tf_init(uid_t uid); +int auth_krb4(const char *server_user, KTEXT auth, char **client); +int auth_kerberos_tgt(struct passwd *pw, const char *string); +int auth_afs_token(char *server_user, uid_t uid, const char *string); + +int creds_to_radix(CREDENTIALS *creds, unsigned char *buf); +int radix_to_creds(const char *buf, CREDENTIALS *creds); + +#endif /* KRB4 */ + +#endif /* SSH_H */ diff --git a/usr.bin/ssh/ssh_md5.c b/usr.bin/ssh/ssh_md5.c new file mode 100644 index 00000000000..e0b370e26d3 --- /dev/null +++ b/usr.bin/ssh/ssh_md5.c @@ -0,0 +1,237 @@ +/* This code has been heavily hacked by Tatu Ylonen <ylo@cs.hut.fi> to + make it compile on machines like Cray that don't have a 32 bit integer + type. */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include "includes.h" +#include "ssh_md5.h" +#include "getput.h" + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = (t + ((uint32)len << 3)) & 0xffffffff) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + MD5Transform(ctx->buf, ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + + /* Append length in bits and transform */ + PUT_32BIT_LSB_FIRST(ctx->in + 56, ctx->bits[0]); + PUT_32BIT_LSB_FIRST(ctx->in + 60, ctx->bits[1]); + + MD5Transform(ctx->buf, ctx->in); + PUT_32BIT_LSB_FIRST(digest, ctx->buf[0]); + PUT_32BIT_LSB_FIRST(digest + 4, ctx->buf[1]); + PUT_32BIT_LSB_FIRST(digest + 8, ctx->buf[2]); + PUT_32BIT_LSB_FIRST(digest + 12, ctx->buf[3]); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32 buf[4], const unsigned char inext[64]) +{ + register word32 a, b, c, d, i; + word32 in[16]; + + for (i = 0; i < 16; i++) + in[i] = GET_32BIT_LSB_FIRST(inext + 4 * i); + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff --git a/usr.bin/ssh/ssh_md5.h b/usr.bin/ssh/ssh_md5.h new file mode 100644 index 00000000000..999fea945a2 --- /dev/null +++ b/usr.bin/ssh/ssh_md5.h @@ -0,0 +1,27 @@ +#ifndef MD5_H +#define MD5_H + +typedef word32 uint32; + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; + +#define MD5Init ssh_MD5Init +void MD5Init(struct MD5Context *context); +#define MD5Update ssh_MD5Update +void MD5Update(struct MD5Context *context, unsigned char const *buf, + unsigned len); +#define MD5Final ssh_MD5Final +void MD5Final(unsigned char digest[16], struct MD5Context *context); +#define MD5Transform ssh_MD5Transform +void MD5Transform(uint32 buf[4], const unsigned char in[64]); + +/* + * This is needed to make RSAREF happy on some MS-DOS compilers. + */ +typedef struct MD5Context MD5_CTX; + +#endif /* !MD5_H */ diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c new file mode 100644 index 00000000000..1ce4b01047f --- /dev/null +++ b/usr.bin/ssh/sshconnect.c @@ -0,0 +1,1434 @@ +/* + +sshconnect.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Mar 18 22:15:47 1995 ylo + +Code to connect to a remote host, and to perform the client side of the +login (authentication) dialog. + +*/ + +#include "includes.h" +RCSID("$Id: sshconnect.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); + +#include <gmp.h> +#include "xmalloc.h" +#include "randoms.h" +#include "rsa.h" +#include "ssh.h" +#include "packet.h" +#include "authfd.h" +#include "cipher.h" +#include "ssh_md5.h" +#include "mpaux.h" +#include "uidswap.h" + +#ifdef KRB4 +#include <krb.h> +#ifdef AFS +#if defined(HAVE_SYS_IOCTL_H) && SunOS != 4 +#include <sys/ioctl.h> +#endif +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> +#endif +#include <kafs.h> +#endif /* AFS */ +#endif /* KRB4 */ + +/* Session id for the current session. */ +unsigned char session_id[16]; + +/* Connect to the given ssh server using a proxy command. */ + +int ssh_proxy_connect(const char *host, int port, uid_t original_real_uid, + const char *proxy_command, RandomState *random_state) +{ + Buffer command; + const char *cp; + char *command_string; + int pin[2], pout[2]; + int pid; + char portstring[100]; + + /* Convert the port number into a string. */ + sprintf(portstring, "%d", port); + + /* Build the final command string in the buffer by making the appropriate + substitutions to the given proxy command. */ + buffer_init(&command); + for (cp = proxy_command; *cp; cp++) + { + if (cp[0] == '%' && cp[1] == '%') + { + buffer_append(&command, "%", 1); + cp++; + continue; + } + if (cp[0] == '%' && cp[1] == 'h') + { + buffer_append(&command, host, strlen(host)); + cp++; + continue; + } + if (cp[0] == '%' && cp[1] == 'p') + { + buffer_append(&command, portstring, strlen(portstring)); + cp++; + continue; + } + buffer_append(&command, cp, 1); + } + buffer_append(&command, "\0", 1); + + /* Get the final command string. */ + command_string = buffer_ptr(&command); + + /* Create pipes for communicating with the proxy. */ + if (pipe(pin) < 0 || pipe(pout) < 0) + fatal("Could not create pipes to communicate with the proxy: %.100s", + strerror(errno)); + + debug("Executing proxy command: %.500s", command_string); + + /* Fork and execute the proxy command. */ + if ((pid = fork()) == 0) + { + char *argv[10]; + + /* Child. Permanently give up superuser privileges. */ + permanently_set_uid(original_real_uid); + + /* Redirect stdin and stdout. */ + close(pin[1]); + if (pin[0] != 0) + { + if (dup2(pin[0], 0) < 0) + perror("dup2 stdin"); + close(pin[0]); + } + close(pout[0]); + if (dup2(pout[1], 1) < 0) + perror("dup2 stdout"); + close(pout[1]); /* Cannot be 1 because pin allocated two descriptors. */ + + /* Stderr is left as it is so that error messages get printed on + the user's terminal. */ + argv[0] = "/bin/sh"; + argv[1] = "-c"; + argv[2] = command_string; + argv[3] = NULL; + + /* Execute the proxy command. Note that we gave up any extra + privileges above. */ + execv("/bin/sh", argv); + perror("/bin/sh"); + exit(1); + } + /* Parent. */ + if (pid < 0) + fatal("fork failed: %.100s", strerror(errno)); + + /* Close child side of the descriptors. */ + close(pin[0]); + close(pout[1]); + + /* Free the command name. */ + buffer_free(&command); + + /* Set the connection file descriptors. */ + packet_set_connection(pout[0], pin[1], random_state); + + return 1; +} + +/* Creates a (possibly privileged) socket for use as the ssh connection. */ + +int ssh_create_socket(uid_t original_real_uid, int privileged) +{ + int sock; + + /* If we are running as root and want to connect to a privileged port, + bind our own socket to a privileged port. */ + if (privileged) + { + struct sockaddr_in sin; + int p; + for (p = 1023; p > 512; p--) + { + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + fatal("socket: %.100s", strerror(errno)); + + /* Initialize the desired sockaddr_in structure. */ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons(p); + + /* Try to bind the socket to the privileged port. */ + if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + break; /* Success. */ + if (errno == EADDRINUSE) + { + close(sock); + continue; + } + fatal("bind: %.100s", strerror(errno)); + } + debug("Allocated local port %d.", p); + } + else + { + /* Just create an ordinary socket on arbitrary port. We use the + user's uid to create the socket. */ + temporarily_use_uid(original_real_uid); + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + fatal("socket: %.100s", strerror(errno)); + restore_uid(); + } + return sock; +} + +/* Opens a TCP/IP connection to the remote server on the given host. If + port is 0, the default port will be used. If anonymous is zero, + a privileged port will be allocated to make the connection. + This requires super-user privileges if anonymous is false. + Connection_attempts specifies the maximum number of tries (one per + second). If proxy_command is non-NULL, it specifies the command (with %h + and %p substituted for host and port, respectively) to use to contact + the daemon. */ + +int ssh_connect(const char *host, int port, int connection_attempts, + int anonymous, uid_t original_real_uid, + const char *proxy_command, RandomState *random_state) +{ + int sock = -1, attempt, i; + int on = 1; + struct servent *sp; + struct hostent *hp; + struct sockaddr_in hostaddr; +#ifdef SO_LINGER + struct linger linger; +#endif /* SO_LINGER */ + + debug("ssh_connect: getuid %d geteuid %d anon %d", + (int)getuid(), (int)geteuid(), anonymous); + + /* Get default port if port has not been set. */ + if (port == 0) + { + sp = getservbyname(SSH_SERVICE_NAME, "tcp"); + if (sp) + port = ntohs(sp->s_port); + else + port = SSH_DEFAULT_PORT; + } + + /* If a proxy command is given, connect using it. */ + if (proxy_command != NULL) + return ssh_proxy_connect(host, port, original_real_uid, proxy_command, + random_state); + + /* No proxy command. */ + + /* No host lookup made yet. */ + hp = NULL; + + /* Try to connect several times. On some machines, the first time will + sometimes fail. In general socket code appears to behave quite + magically on many machines. */ + for (attempt = 0; attempt < connection_attempts; attempt++) + { + if (attempt > 0) + debug("Trying again..."); + + /* Try to parse the host name as a numeric inet address. */ + memset(&hostaddr, 0, sizeof(hostaddr)); + hostaddr.sin_family = AF_INET; + hostaddr.sin_port = htons(port); +#ifdef BROKEN_INET_ADDR + hostaddr.sin_addr.s_addr = inet_network(host); +#else /* BROKEN_INET_ADDR */ + hostaddr.sin_addr.s_addr = inet_addr(host); +#endif /* BROKEN_INET_ADDR */ + if ((hostaddr.sin_addr.s_addr & 0xffffffff) != 0xffffffff) + { + /* Valid numeric IP address */ + debug("Connecting to %.100s port %d.", + inet_ntoa(hostaddr.sin_addr), port); + + /* Create a socket. */ + sock = ssh_create_socket(original_real_uid, + !anonymous && geteuid() == 0 && + port < 1024); + + /* Connect to the host. We use the user's uid in the hope that + it will help with the problems of tcp_wrappers showing the + remote uid as root. */ + temporarily_use_uid(original_real_uid); + if (connect(sock, (struct sockaddr *)&hostaddr, sizeof(hostaddr)) + >= 0) + { + /* Successful connect. */ + restore_uid(); + break; + } + debug("connect: %.100s", strerror(errno)); + restore_uid(); + + /* Destroy the failed socket. */ + shutdown(sock, 2); + close(sock); + } + else + { + /* Not a valid numeric inet address. */ + /* Map host name to an address. */ + if (!hp) + hp = gethostbyname(host); + if (!hp) + fatal("Bad host name: %.100s", host); + if (!hp->h_addr_list[0]) + fatal("Host does not have an IP address: %.100s", host); + + /* Loop through addresses for this host, and try each one in + sequence until the connection succeeds. */ + for (i = 0; hp->h_addr_list[i]; i++) + { + /* Set the address to connect to. */ + hostaddr.sin_family = hp->h_addrtype; + memcpy(&hostaddr.sin_addr, hp->h_addr_list[i], + sizeof(hostaddr.sin_addr)); + + debug("Connecting to %.200s [%.100s] port %d.", + host, inet_ntoa(hostaddr.sin_addr), port); + + /* Create a socket for connecting. */ + sock = ssh_create_socket(original_real_uid, + !anonymous && geteuid() == 0 && + port < 1024); + + /* Connect to the host. We use the user's uid in the hope that + it will help with tcp_wrappers showing the remote uid as + root. */ + temporarily_use_uid(original_real_uid); + if (connect(sock, (struct sockaddr *)&hostaddr, + sizeof(hostaddr)) >= 0) + { + /* Successful connection. */ + restore_uid(); + break; + } + debug("connect: %.100s", strerror(errno)); + restore_uid(); + + /* Close the failed socket; there appear to be some problems + when reusing a socket for which connect() has already + returned an error. */ + shutdown(sock, 2); + close(sock); + } + if (hp->h_addr_list[i]) + break; /* Successful connection. */ + } + + /* Sleep a moment before retrying. */ + sleep(1); + } + /* Return failure if we didn't get a successful connection. */ + if (attempt >= connection_attempts) + return 0; + + debug("Connection established."); + + /* 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)); */ +#ifdef TCP_NODELAY + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on)); +#endif /* TCP_NODELAY */ +#ifdef SO_LINGER + linger.l_onoff = 1; + linger.l_linger = 5; + setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); +#endif /* SO_LINGER */ + + /* Set the connection. */ + packet_set_connection(sock, sock, random_state); + + return 1; +} + +/* Checks if the user has an authentication agent, and if so, tries to + authenticate using the agent. */ + +int try_agent_authentication() +{ + int status, type, bits; + MP_INT e, n, challenge; + char *comment; + AuthenticationConnection *auth; + unsigned char response[16]; + unsigned int i; + + /* Get connection to the agent. */ + auth = ssh_get_authentication_connection(); + if (!auth) + return 0; + + mpz_init(&e); + mpz_init(&n); + mpz_init(&challenge); + + /* Loop through identities served by the agent. */ + for (status = ssh_get_first_identity(auth, &bits, &e, &n, &comment); + status; + status = ssh_get_next_identity(auth, &bits, &e, &n, &comment)) + { + int plen, clen; + + /* Try this identity. */ + debug("Trying RSA authentication via agent with '%.100s'", comment); + xfree(comment); + + /* Tell the server that we are willing to authenticate using this key. */ + packet_start(SSH_CMSG_AUTH_RSA); + packet_put_mp_int(&n); + packet_send(); + packet_write_wait(); + + /* Wait for server's response. */ + type = packet_read(&plen); + + /* The server sends failure if it doesn\'t like our key or does not + support RSA authentication. */ + if (type == SSH_SMSG_FAILURE) + { + debug("Server refused our key."); + continue; + } + + /* Otherwise it should have sent a challenge. */ + if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) + packet_disconnect("Protocol error during RSA authentication: %d", + type); + + packet_get_mp_int(&challenge, &clen); + + packet_integrity_check(plen, clen, type); + + debug("Received RSA challenge from server."); + + /* Ask the agent to decrypt the challenge. */ + if (!ssh_decrypt_challenge(auth, bits, &e, &n, &challenge, + session_id, 1, response)) + { + /* The agent failed to authenticate this identifier although it + advertised it supports this. Just return a wrong value. */ + log("Authentication agent failed to decrypt challenge."); + memset(response, 0, sizeof(response)); + } + + debug("Sending response to RSA challenge."); + + /* Send the decrypted challenge back to the server. */ + packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); + for (i = 0; i < 16; i++) + packet_put_char(response[i]); + packet_send(); + packet_write_wait(); + + /* Wait for response from the server. */ + type = packet_read(&plen); + + /* The server returns success if it accepted the authentication. */ + if (type == SSH_SMSG_SUCCESS) + { + debug("RSA authentication accepted by server."); + mpz_clear(&e); + mpz_clear(&n); + mpz_clear(&challenge); + return 1; + } + + /* Otherwise it should return failure. */ + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error waiting RSA auth response: %d", + type); + } + + mpz_clear(&e); + mpz_clear(&n); + mpz_clear(&challenge); + + debug("RSA authentication using agent refused."); + return 0; +} + +/* Computes the proper response to a RSA challenge, and sends the response to + the server. */ + +void respond_to_rsa_challenge(MP_INT *challenge, RSAPrivateKey *prv) +{ + unsigned char buf[32], response[16]; + struct MD5Context md; + int i; + + /* Decrypt the challenge using the private key. */ + rsa_private_decrypt(challenge, challenge, prv); + + /* Compute the response. */ + /* The response is MD5 of decrypted challenge plus session id. */ + mp_linearize_msb_first(buf, 32, challenge); + MD5Init(&md); + MD5Update(&md, buf, 32); + MD5Update(&md, session_id, 16); + MD5Final(response, &md); + + debug("Sending response to host key RSA challenge."); + + /* Send the response back to the server. */ + packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); + for (i = 0; i < 16; i++) + packet_put_char(response[i]); + packet_send(); + packet_write_wait(); + + memset(buf, 0, sizeof(buf)); + memset(response, 0, sizeof(response)); + memset(&md, 0, sizeof(md)); +} + +/* Checks if the user has authentication file, and if so, tries to authenticate + the user using it. */ + +int try_rsa_authentication(struct passwd *pw, const char *authfile, + int may_ask_passphrase) +{ + MP_INT challenge; + RSAPrivateKey private_key; + RSAPublicKey public_key; + char *passphrase, *comment; + int type, i; + int plen, clen; + + /* Try to load identification for the authentication key. */ + if (!load_public_key(authfile, &public_key, &comment)) + return 0; /* Could not load it. Fail. */ + + debug("Trying RSA authentication with key '%.100s'", comment); + + /* Tell the server that we are willing to authenticate using this key. */ + packet_start(SSH_CMSG_AUTH_RSA); + packet_put_mp_int(&public_key.n); + packet_send(); + packet_write_wait(); + + /* We no longer need the public key. */ + rsa_clear_public_key(&public_key); + + /* Wait for server's response. */ + type = packet_read(&plen); + + /* The server responds with failure if it doesn\'t like our key or doesn\'t + support RSA authentication. */ + if (type == SSH_SMSG_FAILURE) + { + debug("Server refused our key."); + xfree(comment); + return 0; /* Server refuses to authenticate with this key. */ + } + + /* Otherwise, the server should respond with a challenge. */ + if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) + packet_disconnect("Protocol error during RSA authentication: %d", type); + + /* Get the challenge from the packet. */ + mpz_init(&challenge); + packet_get_mp_int(&challenge, &clen); + + packet_integrity_check(plen, clen, type); + + debug("Received RSA challenge from server."); + + /* Load the private key. Try first with empty passphrase; if it fails, + ask for a passphrase. */ + if (!load_private_key(authfile, "", &private_key, NULL)) + { + char buf[300]; + /* Request passphrase from the user. We read from /dev/tty to make + this work even if stdin has been redirected. If running in + batch mode, we just use the empty passphrase, which will fail and + return. */ + sprintf(buf, "Enter passphrase for RSA key '%.100s': ", comment); + if (may_ask_passphrase) + passphrase = read_passphrase(buf, 0); + else + { + debug("Will not query passphrase for %.100s in batch mode.", + comment); + passphrase = xstrdup(""); + } + + /* Load the authentication file using the pasphrase. */ + if (!load_private_key(authfile, passphrase, &private_key, NULL)) + { + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + error("Bad passphrase."); + + /* Send a dummy response packet to avoid protocol error. */ + packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); + for (i = 0; i < 16; i++) + packet_put_char(0); + packet_send(); + packet_write_wait(); + + /* Expect the server to reject it... */ + packet_read_expect(&plen, SSH_SMSG_FAILURE); + xfree(comment); + return 0; + } + + /* Destroy the passphrase. */ + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + } + + /* We no longer need the comment. */ + xfree(comment); + + /* Compute and send a response to the challenge. */ + respond_to_rsa_challenge(&challenge, &private_key); + + /* Destroy the private key. */ + rsa_clear_private_key(&private_key); + + /* We no longer need the challenge. */ + mpz_clear(&challenge); + + /* Wait for response from the server. */ + type = packet_read(&plen); + if (type == SSH_SMSG_SUCCESS) + { + debug("RSA authentication accepted by server."); + return 1; + } + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error waiting RSA auth response: %d", type); + debug("RSA authentication refused."); + return 0; +} + +/* Tries to authenticate the user using combined rhosts or /etc/hosts.equiv + authentication and RSA host authentication. */ + +int try_rhosts_rsa_authentication(const char *local_user, + RSAPrivateKey *host_key) +{ + int type; + MP_INT challenge; + int plen, clen; + + debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication."); + + /* Tell the server that we are willing to authenticate using this key. */ + packet_start(SSH_CMSG_AUTH_RHOSTS_RSA); + packet_put_string(local_user, strlen(local_user)); + packet_put_int(host_key->bits); + packet_put_mp_int(&host_key->e); + packet_put_mp_int(&host_key->n); + packet_send(); + packet_write_wait(); + + /* Wait for server's response. */ + type = packet_read(&plen); + + /* The server responds with failure if it doesn't admit our .rhosts + authentication or doesn't know our host key. */ + if (type == SSH_SMSG_FAILURE) + { + debug("Server refused our rhosts authentication or host key."); + return 0; /* Server refuses to authenticate us with this method. */ + } + + /* Otherwise, the server should respond with a challenge. */ + if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) + packet_disconnect("Protocol error during RSA authentication: %d", type); + + /* Get the challenge from the packet. */ + mpz_init(&challenge); + packet_get_mp_int(&challenge, &clen); + + packet_integrity_check(plen, clen, type); + + debug("Received RSA challenge for host key from server."); + + /* Compute a response to the challenge. */ + respond_to_rsa_challenge(&challenge, host_key); + + /* We no longer need the challenge. */ + mpz_clear(&challenge); + + /* Wait for response from the server. */ + type = packet_read(&plen); + if (type == SSH_SMSG_SUCCESS) + { + debug("Rhosts or /etc/hosts.equiv with RSA host authentication accepted by server."); + return 1; + } + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error waiting RSA auth response: %d", type); + debug("Rhosts or /etc/hosts.equiv with RSA host authentication refused."); + return 0; +} + +#ifdef KRB4 +int try_kerberos_authentication() +{ + KTEXT_ST auth; /* Kerberos data */ + char *reply; + char inst[INST_SZ]; + char *realm; + CREDENTIALS cred; + int r, type; + Key_schedule schedule; + u_long checksum, cksum; + MSG_DAT msg_data; + struct sockaddr_in local, foreign; + struct stat st; + int plen; + + /* Don't do anything if we don't have any tickets. */ + if (stat(tkt_string(), &st) < 0) return 0; + + debug("Trying Kerberos authentication."); + strncpy(inst, (char *) krb_get_phost(get_canonical_hostname()), INST_SZ); + + realm = (char *)krb_realmofhost(get_canonical_hostname()); + if (!realm) { + debug("Kerberos V4: no realm for %.100s", get_canonical_hostname()); + return 0; + } + /* This can really be anything. */ + checksum = (u_long) getpid(); + + r = krb_mk_req(&auth, KRB4_SERVICE_NAME, inst, realm, checksum); + if (r != KSUCCESS) { + debug("Kerberos V4 krb_mk_req failed: %.100s", krb_err_txt[r]); + return 0; + } + /* Get session key to decrypt the server's reply with. */ + r = krb_get_cred(KRB4_SERVICE_NAME, inst, realm, &cred); + if (r != KSUCCESS) { + debug("get_cred failed: %.100s", krb_err_txt[r]); + return 0; + } + des_key_sched((des_cblock *)cred.session, schedule); + + /* Send authentication info to server. */ + packet_start(SSH_CMSG_AUTH_KERBEROS); + packet_put_string((char *)auth.dat, auth.length); + packet_send(); + packet_write_wait(); + + /* zero the buffer */ + (void) memset(auth.dat, 0, MAX_KTXT_LEN); + + r = sizeof(local); + memset(&local, 0, sizeof(local)); + if (getsockname(packet_get_connection_in(), + (struct sockaddr *) &local, &r) < 0) + debug("getsockname failed: %.100s", strerror(errno)); + + r = sizeof(foreign); + memset(&foreign, 0, sizeof(foreign)); + if (getpeername(packet_get_connection_in(), + (struct sockaddr *)&foreign, &r) < 0) + debug("getpeername failed: %.100s", strerror(errno)); + + /* Get server reply. */ + type = packet_read(&plen); + switch(type) { + + case SSH_SMSG_FAILURE: /* Should really be SSH_SMSG_AUTH_KERBEROS_FAILURE */ + debug("Kerberos V4 authentication failed."); + return 0; + break; + + case SSH_SMSG_AUTH_KERBEROS_RESPONSE: /* SSH_SMSG_AUTH_KERBEROS_SUCCESS */ + debug("Kerberos V4 authentication accepted."); + + /* Get server's response. */ + reply = packet_get_string((unsigned int *)&auth.length); + memcpy(auth.dat, reply, auth.length); + xfree(reply); + + packet_integrity_check(plen, 4 + auth.length, type); + + /* If his response isn't properly encrypted with the session key, + and the decrypted checksum fails to match, he's bogus. Bail out. */ + r = krb_rd_priv(auth.dat, auth.length, schedule, &cred.session, + &foreign, &local, &msg_data); + if (r != KSUCCESS) { + debug("Kerberos V4 krb_rd_priv failed: %.100s", krb_err_txt[r]); + packet_disconnect("Kerberos V4 challenge failed!"); + } + /* fetch the (incremented) checksum that we supplied in the request */ + (void)memcpy((char *)&cksum, (char *)msg_data.app_data, sizeof(cksum)); + cksum = ntohl(cksum); + + /* If it matches, we're golden. */ + if (cksum == checksum + 1) { + debug("Kerberos V4 challenge successful."); + return 1; + } + else + packet_disconnect("Kerberos V4 challenge failed!"); + break; + + default: + packet_disconnect("Protocol error on Kerberos V4 response: %d", type); + } + return 0; +} +#endif /* KRB4 */ + +#ifdef AFS + +#ifdef KERBEROS_TGT_PASSING +int send_kerberos_tgt() +{ + CREDENTIALS *creds; + char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; + int r, plen, type; + unsigned char buffer[8192]; + struct stat st; + + /* Don't do anything if we don't have any tickets. */ + if (stat(tkt_string(), &st) < 0) return 0; + + creds = xmalloc(sizeof(CREDENTIALS)); + + if ((r=krb_get_tf_fullname(TKT_FILE,pname,pinst,prealm)) != KSUCCESS) { + debug("Kerberos V4 tf_fullname failed: %.100s",krb_err_txt[r]); + return 0; +} + if ((r=krb_get_cred("krbtgt", prealm, prealm, creds)) != GC_OK) { + debug("Kerberos V4 get_cred failed: %.100s", krb_err_txt[r]); + return 0; + } + if (time(0) > krb_life_to_time(creds->issue_date, creds->lifetime)) { + debug("Kerberos V4 ticket expired: %.100s", TKT_FILE); + return 0; + } + + creds_to_radix(creds, buffer); + xfree(creds); + + packet_start(SSH_CMSG_HAVE_KERBEROS_TGT); + packet_put_string((char *)buffer, strlen(buffer)); + packet_send(); + packet_write_wait(); + + type = packet_read(&plen); + + if (type == SSH_SMSG_FAILURE) + debug("Kerberos TGT for realm %.100s rejected.", prealm); + else if (type != SSH_SMSG_SUCCESS) + packet_disconnect("Protocol error on Kerberos TGT response: %d", type); + + return 1; +} +#endif /* KERBEROS_TGT_PASSING */ + +/* Forwards our AFS tokens to the server. */ +void send_afs_tokens(void) +{ + CREDENTIALS creds; + struct ViceIoctl parms; + struct ClearToken ct; + int i, type; + int len, plen; + char buf[2048], *p, *server_cell; + unsigned char buffer[8192]; + + /* Move over ktc_GetToken, here's something leaner. */ + for (i = 0; i < 100; i++) { /* just in case */ + parms.in = (char *)&i; + parms.in_size = sizeof(i); + parms.out = buf; + parms.out_size = sizeof(buf); + if (k_pioctl(0, VIOCGETTOK, &parms, 0) != 0) break; + p = buf; + + /* Get secret token. */ + memcpy(&creds.ticket_st.length, p, sizeof(unsigned int)); + if (creds.ticket_st.length > MAX_KTXT_LEN) break; + p += sizeof(unsigned int); + memcpy(creds.ticket_st.dat, p, creds.ticket_st.length); + p += creds.ticket_st.length; + + /* Get clear token. */ + memcpy(&len, p, sizeof(len)); + if (len != sizeof(struct ClearToken)) break; + p += sizeof(len); + memcpy(&ct, p, len); + p += len; + p += sizeof(len); /* primary flag */ + server_cell = p; + + /* Flesh out our credentials. */ + strcpy(creds.service, "afs"); + creds.instance[0] = '\0'; + strncpy(creds.realm, server_cell, REALM_SZ); + memcpy(creds.session, ct.HandShakeKey, DES_KEY_SZ); + creds.issue_date = ct.BeginTimestamp; + creds.lifetime = krb_time_to_life(creds.issue_date, ct.EndTimestamp); + creds.kvno = ct.AuthHandle; + sprintf(creds.pname, "AFS ID %d", ct.ViceId); + creds.pinst[0] = '\0'; + + /* Encode token, ship it off. */ + if (!creds_to_radix(&creds, buffer)) break; + packet_start(SSH_CMSG_HAVE_AFS_TOKEN); + packet_put_string((char *)buffer, strlen(buffer)); + packet_send(); + packet_write_wait(); + + /* Roger, Roger. Clearance, Clarence. What's your vector, Victor? */ + type = packet_read(&plen); + + if (type == SSH_SMSG_FAILURE) + debug("AFS token for cell %.100s rejected.", server_cell); + else if (type != SSH_SMSG_SUCCESS) + packet_disconnect("Protocol error on AFS token response: %d", type); + } +} +#endif /* AFS */ + +/* Waits for the server identification string, and sends our own identification + string. */ + +void ssh_exchange_identification() +{ + char buf[256], remote_version[256]; /* must be same size! */ + int remote_major, remote_minor, i; + int connection_in = packet_get_connection_in(); + int connection_out = packet_get_connection_out(); + + /* Read other side\'s version identification. */ + for (i = 0; i < sizeof(buf) - 1; i++) + { + if (read(connection_in, &buf[i], 1) != 1) + fatal("read: %.100s", strerror(errno)); + if (buf[i] == '\r') + { + buf[i] = '\n'; + buf[i + 1] = 0; + break; + } + if (buf[i] == '\n') + { + buf[i + 1] = 0; + break; + } + } + buf[sizeof(buf) - 1] = 0; + + /* Check that the versions match. In future this might accept several + versions and set appropriate flags to handle them. */ + if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, + remote_version) != 3) + fatal("Bad remote protocol version identification: '%.100s'", buf); + debug("Remote protocol version %d.%d, remote software version %.100s", + remote_major, remote_minor, remote_version); +#if 0 + /* Removed for now, to permit compatibility with latter versions. The server + will reject our version and disconnect if it doesn't support it. */ + if (remote_major != PROTOCOL_MAJOR) + fatal("Protocol major versions differ: %d vs. %d", + PROTOCOL_MAJOR, remote_major); +#endif + + /* Check if the remote protocol version is too old. */ + if (remote_major == 1 && remote_minor == 0) + fatal("Remote machine has too old SSH software version."); + + /* Send our own protocol version identification. */ + sprintf(buf, "SSH-%d.%d-%.100s\n", + PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); + if (write(connection_out, buf, strlen(buf)) != strlen(buf)) + fatal("write: %.100s", strerror(errno)); +} + +int ssh_cipher_default = SSH_CIPHER_3DES; + +int read_yes_or_no(const char *prompt, int defval) +{ + char buf[1024]; + FILE *f; + int retval = -1; + + if (isatty(0)) + f = stdin; + else + f = fopen("/dev/tty", "rw"); + + if (f == NULL) + return 0; + + fflush(stdout); + + while (1) + { + fprintf(stderr, "%s", prompt); + if (fgets(buf, sizeof(buf), f) == NULL) + { + /* Print a newline (the prompt probably didn\'t have one). */ + fprintf(stderr, "\n"); + strcpy(buf, "no"); + } + /* Remove newline from response. */ + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + + if (buf[0] == 0) + retval = defval; + if (strcmp(buf, "yes") == 0) + retval = 1; + if (strcmp(buf, "no") == 0) + retval = 0; + + if (retval != -1) + { + if (f != stdin) + fclose(f); + return retval; + } + } +} + +/* Starts a dialog with the server, and authenticates the current user on the + server. This does not need any extra privileges. The basic connection + to the server must already have been established before this is called. + User is the remote user; if it is NULL, the current local user name will + be used. Anonymous indicates that no rhosts authentication will be used. + If login fails, this function prints an error and never returns. + This function does not require super-user privileges. */ + +void ssh_login(RandomState *state, int host_key_valid, + RSAPrivateKey *own_host_key, + const char *orighost, + Options *options, uid_t original_real_uid) +{ + int i, type; + char buf[1024]; + char *password; + struct passwd *pw; + MP_INT key; + RSAPublicKey host_key; + RSAPublicKey public_key; + unsigned char session_key[SSH_SESSION_KEY_LENGTH]; + const char *server_user, *local_user; + char *cp, *host; + struct stat st; + unsigned char check_bytes[8]; + unsigned int supported_ciphers, supported_authentications, protocol_flags; + HostStatus host_status; + int payload_len, clen, sum_len = 0; + + /* Convert the user-supplied hostname into all lowercase. */ + host = xstrdup(orighost); + for (cp = host; *cp; cp++) + if (isupper(*cp)) + *cp = tolower(*cp); + + /* Exchange protocol version identification strings with the server. */ + ssh_exchange_identification(); + + /* Put the connection into non-blocking mode. */ + packet_set_nonblocking(); + + /* Get local user name. Use it as server user if no user name + was given. */ + pw = getpwuid(original_real_uid); + if (!pw) + fatal("User id %d not found from user database.", original_real_uid); + local_user = xstrdup(pw->pw_name); + server_user = options->user ? options->user : local_user; + + debug("Waiting for server public key."); + + /* Wait for a public key packet from the server. */ + packet_read_expect(&payload_len, SSH_SMSG_PUBLIC_KEY); + + /* Get check bytes from the packet. */ + for (i = 0; i < 8; i++) + check_bytes[i] = packet_get_char(); + + /* Get the public key. */ + public_key.bits = packet_get_int(); + mpz_init(&public_key.e); + packet_get_mp_int(&public_key.e, &clen); + sum_len += clen; + mpz_init(&public_key.n); + packet_get_mp_int(&public_key.n, &clen); + sum_len += clen; + + /* Get the host key. */ + host_key.bits = packet_get_int(); + mpz_init(&host_key.e); + packet_get_mp_int(&host_key.e, &clen); + sum_len += clen; + mpz_init(&host_key.n); + packet_get_mp_int(&host_key.n, &clen); + sum_len += clen; + + /* Get protocol flags. */ + protocol_flags = packet_get_int(); + packet_set_protocol_flags(protocol_flags); + + /* Get supported cipher types. */ + supported_ciphers = packet_get_int(); + + /* Get supported authentication types. */ + supported_authentications = packet_get_int(); + + debug("Received server public key (%d bits) and host key (%d bits).", + public_key.bits, host_key.bits); + + packet_integrity_check(payload_len, + 8 + 4 + sum_len + 0 + 4 + 0 + 0 + 4 + 4 + 4, + SSH_SMSG_PUBLIC_KEY); + + /* Compute the session id. */ + compute_session_id(session_id, check_bytes, host_key.bits, &host_key.n, + public_key.bits, &public_key.n); + + /* Check if the host key is present in the user\'s list of known hosts + or in the systemwide list. */ + host_status = check_host_in_hostfile(options->user_hostfile, + host, host_key.bits, + &host_key.e, &host_key.n); + if (host_status == HOST_NEW) + host_status = check_host_in_hostfile(options->system_hostfile, host, + host_key.bits, &host_key.e, + &host_key.n); + + /* Force accepting of the host key for localhost and 127.0.0.1. + The problem is that if the home directory is NFS-mounted to multiple + machines, localhost will refer to a different machine in each of them, + and the user will get bogus HOST_CHANGED warnings. This essentially + disables host authentication for localhost; however, this is probably + not a real problem. */ + if (strcmp(host, "localhost") == 0 || + strcmp(host, "127.0.0.1") == 0) + { + debug("Forcing accepting of host key for localhost."); + host_status = HOST_OK; + } + + switch (host_status) + { + case HOST_OK: + /* The host is known and the key matches. */ + debug("Host '%.200s' is known and matches the host key.", host); + break; + case HOST_NEW: + /* The host is new. */ + if (options->strict_host_key_checking == 1) + { /* User has requested strict host key checking. We will not + add the host key automatically. The only alternative left + is to abort. */ + fatal("No host key is known for %.200s and you have requested strict checking.", host); + } + else if (options->strict_host_key_checking == 2) /* The default */ + { + char prompt[1024]; + sprintf(prompt, + "The authenticity of host '%.200s' can't be established.\n" + "Are you sure you want to continue connecting (yes/no)? ", + host); + if (!read_yes_or_no(prompt, -1)) + fatal("Aborted by user!\n"); + } + /* If not in strict mode, add the key automatically to the local + known_hosts file. */ + if (!add_host_to_hostfile(options->user_hostfile, host, host_key.bits, + &host_key.e, &host_key.n)) + log("Failed to add the host to the list of known hosts (%.500s).", + options->user_hostfile); + else + log("Warning: Permanently added host '%.200s' to the list of known hosts.", host); + break; + case HOST_CHANGED: + /* The host key has changed. */ + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: HOST IDENTIFICATION HAS CHANGED! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); + error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); + error("It is also possible that the host key has just been changed."); + error("Please contact your system administrator."); + error("Add correct host key in %.100s to get rid of this message.", + options->user_hostfile); + + /* If strict host key checking is in use, the user will have to edit + the key manually and we can only abort. */ + if (options->strict_host_key_checking) + fatal("Host key for %.200s has changed and you have requested strict checking.", host); + + /* If strict host key checking has not been requested, allow the + connection but without password authentication. */ + error("Password authentication is disabled to avoid trojan horses."); + options->password_authentication = 0; + /* XXX Should permit the user to change to use the new id. This could + be done by converting the host key to an identifying sentence, tell + that the host identifies itself by that sentence, and ask the user + if he/she whishes to accept the authentication. */ + break; + } + + /* Generate a session key. */ + + /* Initialize the random number generator. */ + sprintf(buf, "%.500s/%.200s", pw->pw_dir, SSH_CLIENT_SEEDFILE); + if (stat(buf, &st) < 0) + log("Creating random seed file ~/%.900s. This may take a while.", + SSH_CLIENT_SEEDFILE); + else + debug("Initializing random; seed file %.900s", buf); + random_initialize(state, buf); + + /* Generate an encryption key for the session. The key is a 256 bit + random number, interpreted as a 32-byte key, with the least significant + 8 bits being the first byte of the key. */ + for (i = 0; i < 32; i++) + session_key[i] = random_get_byte(state); + + /* Save the new random state. */ + random_save(state, buf); + random_stir(state); /* This is supposed to be irreversible. */ + + /* According to the protocol spec, the first byte of the session key is + the highest byte of the integer. The session key is xored with the + first 16 bytes of the session id. */ + mpz_init_set_ui(&key, 0); + for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) + { + mpz_mul_2exp(&key, &key, 8); + if (i < 16) + mpz_add_ui(&key, &key, session_key[i] ^ session_id[i]); + else + mpz_add_ui(&key, &key, session_key[i]); + } + + /* Encrypt the integer using the public key and host key of the server + (key with smaller modulus first). */ + if (mpz_cmp(&public_key.n, &host_key.n) < 0) + { + /* Public key has smaller modulus. */ + assert(host_key.bits >= public_key.bits + SSH_KEY_BITS_RESERVED); + + rsa_public_encrypt(&key, &key, &public_key, state); + rsa_public_encrypt(&key, &key, &host_key, state); + } + else + { + /* Host key has smaller modulus (or they are equal). */ + assert(public_key.bits >= host_key.bits + SSH_KEY_BITS_RESERVED); + + rsa_public_encrypt(&key, &key, &host_key, state); + rsa_public_encrypt(&key, &key, &public_key, state); + } + + if (options->cipher == SSH_CIPHER_NOT_SET) + if (cipher_mask() & supported_ciphers & (1 << ssh_cipher_default)) + options->cipher = ssh_cipher_default; + else + { + debug("Cipher %d not supported, using %.100s instead.", + cipher_name(ssh_cipher_default), + cipher_name(SSH_FALLBACK_CIPHER)); + options->cipher = SSH_FALLBACK_CIPHER; + } + + /* Check that the selected cipher is supported. */ + if (!(supported_ciphers & (1 << options->cipher))) + fatal("Selected cipher type %.100s not supported by server.", + cipher_name(options->cipher)); + + debug("Encryption type: %.100s", cipher_name(options->cipher)); + + /* Send the encrypted session key to the server. */ + packet_start(SSH_CMSG_SESSION_KEY); + packet_put_char(options->cipher); + + /* Send the check bytes back to the server. */ + for (i = 0; i < 8; i++) + packet_put_char(check_bytes[i]); + + /* Send the encrypted encryption key. */ + packet_put_mp_int(&key); + + /* Send protocol flags. */ + packet_put_int(SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN); + + /* Send the packet now. */ + packet_send(); + packet_write_wait(); + + /* Destroy the session key integer and the public keys since we no longer + need them. */ + mpz_clear(&key); + rsa_clear_public_key(&public_key); + rsa_clear_public_key(&host_key); + + debug("Sent encrypted session key."); + + /* Set the encryption key. */ + packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, + options->cipher, 1); + + /* We will no longer need the session key here. Destroy any extra copies. */ + memset(session_key, 0, sizeof(session_key)); + + /* Expect a success message from the server. Note that this message will + be received in encrypted form. */ + packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); + + debug("Received encrypted confirmation."); + + /* Send the name of the user to log in as on the server. */ + packet_start(SSH_CMSG_USER); + packet_put_string(server_user, strlen(server_user)); + packet_send(); + packet_write_wait(); + + /* The server should respond with success if no authentication is needed + (the user has no password). Otherwise the server responds with + failure. */ + type = packet_read(&payload_len); + if (type == SSH_SMSG_SUCCESS) + return; /* Connection was accepted without authentication. */ + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", + type); + +#ifdef KERBEROS_TGT_PASSING + /* Try Kerberos tgt passing if the server supports it. */ + if ((supported_authentications & (1 << SSH_PASS_KERBEROS_TGT)) && + options->kerberos_tgt_passing) { + if (options->cipher == SSH_CIPHER_NONE) + log("WARNING: Encryption is disabled! Ticket will be transmitted in the clear!"); + (void)send_kerberos_tgt(); + } +#endif /* KERBEROS_TGT_PASSING */ + +#ifdef AFS + /* Try AFS token passing if the server supports it. */ + if ((supported_authentications & (1 << SSH_PASS_AFS_TOKEN)) && + options->afs_token_passing && k_hasafs()) { + if (options->cipher == SSH_CIPHER_NONE) + log("WARNING: Encryption is disabled! Token will be transmitted in the clear!"); + send_afs_tokens(); + } +#endif /* AFS */ + +#if defined(KRB4) + if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) && + options->kerberos_authentication) + { + if (try_kerberos_authentication()) { + /* The server should respond with success or failure. */ + type = packet_read(&payload_len); + if (type == SSH_SMSG_SUCCESS) + return; /* Successful connection. */ + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error: got %d in response to Kerberos auth", type); + } + } +#endif /* KRB4 */ + + /* Use rhosts authentication if running in privileged socket and we do not + wish to remain anonymous. */ + if ((supported_authentications & (1 << SSH_AUTH_RHOSTS)) && + options->rhosts_authentication) + { + debug("Trying rhosts authentication."); + packet_start(SSH_CMSG_AUTH_RHOSTS); + packet_put_string(local_user, strlen(local_user)); + packet_send(); + packet_write_wait(); + + /* The server should respond with success or failure. */ + type = packet_read(&payload_len); + if (type == SSH_SMSG_SUCCESS) + return; /* Successful connection. */ + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error: got %d in response to rhosts auth", + type); + } + + /* Try .rhosts or /etc/hosts.equiv authentication with RSA host + authentication. */ + if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && + options->rhosts_rsa_authentication && host_key_valid) + { + if (try_rhosts_rsa_authentication(local_user, own_host_key)) + return; /* Successful authentication. */ + } + + /* Try RSA authentication if the server supports it. */ + if ((supported_authentications & (1 << SSH_AUTH_RSA)) && + options->rsa_authentication) + { + /* Try RSA authentication using the authentication agent. The agent + is tried first because no passphrase is needed for it, whereas + identity files may require passphrases. */ + if (try_agent_authentication()) + return; /* Successful connection. */ + + /* Try RSA authentication for each identity. */ + for (i = 0; i < options->num_identity_files; i++) + if (try_rsa_authentication(pw, options->identity_files[i], + !options->batch_mode)) + return; /* Successful connection. */ + } + + /* Try password authentication if the server supports it. */ + if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) && + options->password_authentication && !options->batch_mode) + { + debug("Doing password authentication."); + if (options->cipher == SSH_CIPHER_NONE) + log("WARNING: Encryption is disabled! Password will be transmitted in clear text."); + password = read_passphrase("Password: ", 0); + packet_start(SSH_CMSG_AUTH_PASSWORD); + packet_put_string(password, strlen(password)); + memset(password, 0, strlen(password)); + xfree(password); + packet_send(); + packet_write_wait(); + + type = packet_read(&payload_len); + if (type == SSH_SMSG_SUCCESS) + return; /* Successful connection. */ + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error: got %d in response to passwd auth", + type); + } + + /* All authentication methods have failed. Exit with an error message. */ + fatal("Permission denied."); + /*NOTREACHED*/ +} diff --git a/usr.bin/ssh/sshd.8 b/usr.bin/ssh/sshd.8 new file mode 100644 index 00000000000..5bffcc2be70 --- /dev/null +++ b/usr.bin/ssh/sshd.8 @@ -0,0 +1,734 @@ +.\" -*- nroff -*- +.\" +.\" sshd.8.in +.\" +.\" Author: Tatu Ylonen <ylo@cs.hut.fi> +.\" +.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +.\" All rights reserved +.\" +.\" Created: Sat Apr 22 21:55:14 1995 ylo +.\" +.\" $Id: sshd.8,v 1.1 1999/09/26 20:53:38 deraadt Exp $ +.\" +.TH SSHD 8 "November 8, 1995" "SSH" "SSH" + +.SH NAME +sshd \- secure shell daemon + +.SH SYNOPSIS +.na +.B sshd +[\c +.BI \-b \ bits\fR\c +] +[\c +.B \-d \c +] +[\c +.BI \-f \ config_file\fR\c +] +[\c +.BI \-g \ login_grace_time\fR\c +] +[\c +.BI \-h \ host_key_file\fR\c +] +[\c +.B \-i \c +] +[\c +.BI \-k \ key_gen_time\fR\c +] +[\c +.BI \-p \ port\fR\c +] +[\c +.B \-q \c +] +.ad + + +.SH DESCRIPTION +.LP +.B Sshd +(Secure Shell Daemon) is the daemon program for +.BR ssh ". +Together these programs replace rlogin and rsh programs, and +provide secure encrypted communications between two untrusted hosts +over an insecure network. The programs are intended to be as easy to +install and use as possible. +.LP +.B Sshd +is the daemon that listens for connections from clients. It is +normally started at boot from +.I /etc/rc.local +or equivalent. It forks a new +daemon for each incoming connection. The forked daemons handle +key exchange, encryption, authentication, command execution, +and data exchange. +.LP +Sshd works as follows. Each host has a host-specific RSA key +(normally 1024 bits) used to identify the host. Additionally, when +the daemon starts, it generates a server RSA key (normally 768 bits). +This key is normally regenerated every hour if it has been used, and +is never stored on disk. +.LP +Whenever a client connects the daemon, the daemon sends its host +and server public keys to the client. The client compares the +host key against its own database to verify that it has not changed. +The client then generates a 256 bit random number. It encrypts this +random number using both the host key and the server key, and sends +the encrypted number to the server. Both sides then start to use this +random number as a session key which is used to encrypt all further +communications in the session. The rest of the session is encrypted +using a conventional cipher. Currently, +.BR \s-1Blowfish\s0 ", +.BR \s-1IDEA\s0 ", +.BR \s-1DES\s0 ", +.BR \s-1\&3DES\s0 ", +.B \s-13DES\s0 +is used by default. The client selects the encryption algorithm to use +from those offered by the server. +.LP +Next, the server and the client enter an authentication dialog. The +client tries to authenticate itself using \|\s+2.\s0rhosts +authentication, \|\s+2.\s0rhosts authentication combined with RSA host +authentication, RSA challenge-response authentication, or password +based authentication. +.LP +Rhosts authentication is normally disabled +because it is fundamentally insecure, but can be enabled in the server +configuration file if desired. System security is not improved unless +.BR rshd "(8), +.BR rlogind "(8), +.BR rexecd "(8), and +.B rexd "(8) +are disabled (thus completely disabling +.BR rlogin (1) +and +.BR rsh (1) +into that machine). +.LP +If the client successfully authenticates itself, a dialog for +preparing the session is entered. At this time the client may request +things like allocating a pseudo-tty, forwarding X11 connections, +forwarding TCP/IP connections, or forwarding the authentication agent +connection over the secure channel. +.LP +Finally, the client either requests a shell or execution of a command. +The sides then enter session mode. In this mode, either side may send +data at any time, and such data is forwarded to/from the shell or +command on the server side, and the user terminal in the client side. +.LP +When the user program terminates and all forwarded X11 and other +connections have been closed, the server sends command exit status to +the client, and both sides exit. +.LP +.B Sshd +can be configured using command-line options or a configuration +file. Command-line options override values specified in the +configuration file. + + +.SH OPTIONS +.TP +.BI \-b \ bits +Specifies the number of bits in the server key (default 768). +.TP +.B \-d +Debug mode. The server sends verbose debug output to the system +log, and does not put itself in the background. The server also will +not fork and will only process one connection. This option is only +intended for debugging for the server. +.TP +.BI \-f \ configuration_file +Specifies the name of the configuration file. The default is +.IR /etc/sshd_config ". +.TP +.BI \-g \ login_grace_time +Gives the grace time for clients to authenticate themselves (default +300 seconds). If the client fails to authenticate the user within +this many seconds, the server disconnects and exits. A value of zero +indicates no limit. +.TP +.BI \-h \ host_key_file +Specifies the file from which the host key is read (default +.IR /etc/ssh_host_key). +This option must be given if sshd is not run as root (as the normal +host file is normally not readable by anyone but root). +.TP +.B \-i +Specifies that sshd is being run from inetd. Sshd is normally not run +from inetd because it needs to generate the server key before it can +respond to the client, and this may take tens of seconds. Clients +would have to wait too long if the key was regenerated every time. +However, with small key sizes (e.g. 512) using sshd from inetd may +be feasible. +.TP +.BI \-k \ key_gen_time +Specifies how often the server key is regenerated (default 3600 +seconds, or one hour). The motivation for regenerating the key fairly +often is that the key is not stored anywhere, and after about an hour, +it becomes impossible to recover the key for decrypting intercepted +communications even if the machine is cracked into or physically +seized. A value of zero indicates that the key will never be regenerated. +.TP +.BI \-p \ port +Specifies the port on which the server listens for connections +(default 22). +.TP +.B \-q +Quiet mode. Nothing is sent to the system log. Normally the beginning, +authentication, and termination of each connection is logged. + +.SH CONFIGURATION FILE + +.B Sshd +reads configuration data from +.I /etc/sshd_config +(or the file specified with -f on the command line). The file +contains keyword-value pairs, one per line. Lines starting with '#' +and empty lines are interpreted as comments. + +The following keywords are possible. +.TP +.B AFSTokenPassing +Specifies whether to accept AFS tokens passed from the client. Default +is "yes". +.TP +.B AllowHosts +This keyword can be followed by any number of host name patterns, +separated by spaces. If specified, login is allowed only from hosts +whose name matches one of the patterns. '*' and '?' can be used as +wildcards in the patterns. Normal name servers are used to map the +client's host into a canonical host name. If the name cannot be +mapped, its IP-address is used as the host name. By default all hosts +are allowed to connect. + +Note that +.B sshd +can also be configured to use tcp_wrappers using the --with-libwrap +compile-time configuration option. +.TP +.B DenyHosts +This keyword can be followed by any number of host name patterns, +separated by spaces. If specified, login is disallowed from the hosts +whose name matches any of the patterns. +.TP +.B FascistLogging +Specifies whether to use verbose logging. Verbose logging violates +the privacy of users and is not recommended. The argument must be +"yes" or "no" (without the quotes). The default is "no". +.TP +.B HostKey +Specifies the file containing the private host key (default +.IR /etc/ssh_host_key "). +.TP +.B IgnoreRhosts +Specifies that rhosts and shosts files will not be used in +authentication. +.I /etc/hosts.equiv +and +.I /etc/shosts.equiv +are still used. The default is "no". +.TP +.B KeepAlive +Specifies whether the system should send keepalive messages to the +other side. If they are sent, death of the connection or crash of one +of the machines will be properly noticed. However, this means that +connections will die if the route is down temporarily, and some people +find it annoying. On the other hand, if keepalives are not send, +sessions may hang indefinitely on the server, leaving "ghost" users +and consuming server resources. + +The default is "yes" (to send keepalives), and the server will notice +if the network goes down or the client host reboots. This avoids +infinitely hanging sessions. + +To disable keepalives, the value should be set to "no" in both the +server and the client configuration files. +.TP +.B KerberosAuthentication +Specifies whether Kerberos authentication is allowed. This can +be in the form of a Kerberos ticket, or if PasswordAuthentication +is yes, the password provided by the user will be validated through +the Kerberos KDC / AFS kaserver / DCE Security Server. Default is yes. +.TP +.B KerberosOrLocalPasswd +If set then if password authentication through Kerberos fails then +the password will be validated via any additional local mechanism +such as /etc/passwd or SecurID. Default is no. +.TP +.B KerberosTgtPassing +Specifies whether a Kerberos TGT may be forwarded to the server. +Default is no, TGT forwarding does only work with the AFS kaserver. +.TP +.B KerberosTicketCleanup +Specifies whether to automatically destroy the user's +ticket cache file on logout. Default is yes. +.TP +.B KeyRegenerationInterval +The server key is automatically regenerated after this many seconds +(if it has been used). The purpose of regeneration is to prevent +decrypting captured sessions by later breaking into the machine and +stealing the keys. The key is never stored anywhere. If the value is +0, the key is never regenerated. The default is 3600 +(seconds). +.TP +.B LoginGraceTime +The server disconnects after this time if the user has not +successfully logged in. If the value is 0, there is no time limit. +The default is 600 (seconds). +.TP +.B PasswordAuthentication +Specifies whether password authentication is allowed. +The default is "yes". +.TP +.B PermitEmptyPasswords +When password authentication is allowed, it specifies whether the +server allows login to accounts with empty password strings. The default +is "yes". +.TP +.B PermitRootLogin +Specifies whether the root can log in using +.BR ssh . +The default is "yes". + +Root login with RSA authentication when the "command" option has been +specified will be allowed regardless of the value of this setting +(which may be useful for taking remote backups even if root login is +normally not allowed). +.TP +.B Port +Specifies the port number that +.B sshd +listens on. The default is 22. +.TP +.B PrintMotd +Specifies whether +.B sshd +should print +.I /etc/motd +when a user logs in interactively. (On some systems it is also +printed by the shell, /etc/profile, or equivalent.) The default is +"yes". +.TP +.B QuietMode +Specifies whether the system runs in quiet mode. In quiet mode, +nothing is logged in the system log, except fatal errors. The default +is "no". +.TP +.B RandomSeed +Specifies the file containing the random seed for the server; this +file is created automatically and updated regularly. The default is +.IR /etc/ssh_random_seed ". +.TP +.B RhostsAuthentication +Specifies whether authentication using rhosts or /etc/hosts.equiv +files is sufficient. Normally, this method should not be permitted +because it is insecure. RhostsRSAAuthentication should be used +instead, because it performs RSA-based host authentication in addition +to normal rhosts or /etc/hosts.equiv authentication. +The default is "no". +.TP +.B RhostsRSAAuthentication +Specifies whether rhosts or /etc/hosts.equiv authentication together +with successful RSA host authentication is allowed. The default is "yes". +.TP +.B RSAAuthentication +Specifies whether pure RSA authentication is allowed. The default is "yes". +.TP +.B ServerKeyBits +Defines the number of bits in the server key. The minimum value is +512, and the default is 768. +.TP +.B StrictModes +Specifies whether ssh should check file modes and ownership of the +user's home directory and rhosts files before accepting login. This +is normally desirable because novices sometimes accidentally leave their +directory or files world-writable. The default is "yes". +.TP +.B SyslogFacility +Gives the facility code that is used when logging messages from +.B sshd. +The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2, +LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The default is DAEMON. +.TP +.B X11Forwarding +Specifies whether X11 forwarding is permitted. The default is "yes". +Note that disabling X11 forwarding does not improve security in any +way, as users can always install their own forwarders. + +.SH LOGIN PROCESS + +When a user successfully logs in, +.B sshd +does the following: +.IP 1. +If the login is on a tty, and no command has been specified, +prints last login time and +.B /etc/motd +(unless prevented in the configuration file or by +.IR $HOME/\s+2.\s0hushlogin ; +see the FILES section). +.IP 2. +If the login is on a tty, records login time. +.IP 3. +Checks /etc/nologin; if it exists, prints contents and quits +(unless root). +.IP 4. +Changes to run with normal user privileges. +.IP 5. +Sets up basic environment. +.IP 6. +Reads /etc/environment if it exists. +.IP 7. +Reads $HOME/.ssh/environment if it exists. +.IP 8. +Changes to user's home directory. +.IP 9. +If $HOME/.ssh/rc exists, runs it; else if /etc/sshrc exists, runs +it; otherwise runs xauth. The "rc" files are given the X11 +authentication protocol and cookie in standard input. +.IP 10. +Runs user's shell or command. +.RT + + +.SH AUTHORIZED_KEYS FILE FORMAT +.LP +The +.I \&$HOME/\s+2.\s0ssh/authorized_keys +file lists the RSA keys that are +permitted for RSA authentication. Each line of the file contains one +key (empty lines and lines starting with a '#' are ignored as +comments). Each line consists of the following fields, separated by +spaces: options, bits, exponent, modulus, comment. The options field +is optional; its presence is determined by whether the line starts +with a number or not (the option field never starts with a number). +The bits, exponent, modulus and comment fields give the RSA key; the +comment field is not used for anything (but may be convenient for the +user to identify the key). +.LP +Note that lines in this file are usually several hundred bytes long +(because of the size of the RSA key modulus). You don't want to type +them in; instead, copy the +.I identity.pub +file and edit it. +.LP +The options (if present) consists of comma-separated option +specifications. No spaces are permitted, except within double quotes. +The following option specifications are supported: +.IP +.ti -.5i +\fBfrom="pattern-list" \fR +.br +Specifies that in addition to RSA authentication, the canonical name +of the remote host must be present in the comma-separated list of +patterns ('*' and '?' serve as wildcards). The list may also contain +patterns negated by prefixing them with '!'; if the canonical host +name matches a negated pattern, the key is not accepted. The purpose +of this option is to optionally increase security: RSA authentication +by itself does not trust the network or name servers or anything (but +the key); however, if somebody somehow steals the key, the key +permits an intruder to log in from anywhere in the world. This +additional option makes using a stolen key more difficult (name +servers and/or routers would have to be compromised in addition to +just the key). +.IP +.ti -.5i +\fBcommand="command"\fR +.br +Specifies that the command is executed whenever this key is used for +authentication. The command supplied by the user (if any) is ignored. +The command is run on a pty if the connection requests a pty; +otherwise it is run without a tty. A quote may be included in the +command by quoting it with a backslash. This option might be useful +to restrict certain RSA keys to perform just a specific operation. An +example might be a key that permits remote backups but nothing +else. Notice that the client may specify TCP/IP and/or X11 +forwardings unless they are explicitly prohibited. +.IP +.ti -.5i +\fBenvironment="NAME=value"\fR +.br +Specifies that the string is to be added to the environment when +logging in using this key. Environment variables set this way +override other default environment values. Multiple options of this +type are permitted. +.TP +.B no-port-forwarding +Forbids TCP/IP forwarding when this key is used for authentication. +Any port forward requests by the client will return an error. This +might be used e.g. in connection with the +.B command +option. +.TP +.B no-X11-forwarding +Forbids X11 forwarding when this key is used for authentication. +Any X11 forward requests by the client will return an error. +.TP +.B no-agent-forwarding +Forbids authentication agent forwarding when this key is used for +authentication. +.TP +.B no-pty +Prevents tty allocation (a request to allocate a pty will fail). + +.SS Examples +.LP +1024 33 12121.\|.\|.\|312314325 ylo@foo.bar +.LP +from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23.\|.\|.\|2334 ylo@niksula +.LP +command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hut.fi + + + +.SH SSH_KNOWN_HOSTS FILE FORMAT +.LP +The +.I /etc/ssh_known_hosts +and +.I \&$HOME/\s+2.\s0ssh/known_hosts +files contain host public keys for all known hosts. The global file should +be prepared by the admistrator (optional), and the per-user file is +maintained automatically: whenever the user connects an unknown host +its key is added to the per-user file. The recommended way to create +.I /etc/ssh_known_hosts +is to use the +.B make-ssh-known-hosts +command. +.LP +Each line in these files contains the following fields: hostnames, +bits, exponent, modulus, comment. The fields are separated by spaces. +.LP +Hostnames is a comma-separated list of patterns ('*' and '?' act as +wildcards); each pattern in turn is matched against the canonical host +name (when authenticating a client) or against the user-supplied +name (when authenticating a server). A pattern may also be preceded +by '!' to indicate negation: if the host name matches a negated +pattern, it is not accepted (by that line) even if it matched another +pattern on the line. +.LP +Bits, exponent, and modulus are taken directly from the host key; they +can be obtained e.g. from +.IR /etc/ssh_host_key.pub ". +The optional comment field continues to the end of the line, and is not used. +.LP +Lines starting with '#' and empty lines are ignored as comments. +.LP +When performing host authentication, authentication is accepted if any +matching line has the proper key. It is thus permissible (but not +recommended) to have several lines or different host keys for the same +names. This will inevitably happen when short forms of host names +from different domains are put in the file. It is possible +that the files contain conflicting information; authentication is +accepted if valid information can be found from either file. +.LP +Note that the lines in these files are typically hundreds of characters +long, and you definitely don't want to type in the host keys by hand. +Rather, generate them by a script (see +.BR make-ssh-known-hosts (1)) +or by taking +.I /etc/ssh_host_key.pub +and adding the host names at the front. + +.SS Examples + +closenet,closenet.hut.fi,.\|.\|.\|,130.233.208.41 1024 37 159.\|.\|.93 closenet.hut.fi + +.SH FILES +.TP +.I /etc/sshd_config +Contains configuration data for +.BR sshd . +This file should be writable by root only, but it is recommended +(though not necessary) that it be world-readable. +.TP +.I /etc/ssh_host_key +Contains the private part of the host key. This file is normally +created automatically by "make install", but can also be created +manually using +.BR ssh-keygen (1). +This file should only be owned by root, readable only by root, and not +accessible to others. +.TP +.I /etc/ssh_host_key.pub +Contains the public part of the host key. This file is normally +created automatically by "make install", but can also be created +manually. This file should be world-readable but writable only by +root. Its contents should match the private part. This file is not +really used for anything; it is only provided for the convenience of +the user so its contents can be copied to known hosts files. +.TP +.I /etc/ssh_random_seed +This file contains a seed for the random number generator. This file +should only be accessible by root. +.TP +.I /var/run/sshd.pid +Contains the process id of the +.B sshd +listening for connections (if there are several daemons running +concurrently for different ports, this contains the pid of the one +started last). The contents of this file are not sensitive; it can be +world-readable. +.TP +.I \&$HOME/\s+2.\s0ssh/authorized_keys +Lists the RSA keys that can be used to log into the user's account. +This file must be readable by root (which may on some machines imply +it being world-readable if the user's home directory resides on an NFS +volume). It is recommended that it not be accessible by others. The +format of this file is described above. +.TP +.I "/etc/ssh_known_hosts\fR and \fI$HOME/\s+2.\s0ssh/known_hosts\fR +These files are consulted when using rhosts with RSA host +authentication to check the public key of the host. The key must be +listed in one of these files to be accepted. (The client uses the +same files to verify that the remote host is the one we intended to +connect.) These files should be writable only by root/the owner. +.I /etc/ssh_known_hosts +should be world-readable, and \fI$HOME/\s+2.\s0ssh/known_hosts\fR can +but need not be world-readable. +.TP +.I /etc/nologin +If this file exists, +.B sshd +refuses to let anyone except root log in. The contents of the file +are displayed to anyone trying to log in, and non-root connections are +refused. The file should be world-readable. +.TP +.I \&$HOME/\s+2.\s0rhosts +This file contains host-username pairs, separated by a space, one per +line. The given user on the corresponding host is permitted to log in +without password. The same file is used by rlogind and rshd. +.B Ssh +differs from rlogind +and rshd in that it requires RSA host authentication in addition to +validating the host name retrieved from domain name servers (unless +compiled with the \-\-with\-rhosts configuration option). The file must +be writable only by the user; it is recommended that it not be +accessible by others. + +If is also possible to use netgroups in the file. Either host or user +name may be of the form +@groupname to specify all hosts or all users +in the group. +.TP +.I \&$HOME/\s+2.\s0shosts +For +.B ssh, +this file is exactly the same as for \s+2.\s0rhosts. However, this file is +not used by rlogin and rshd, so using this permits access using +.B ssh +only. +.TP +.I /etc/hosts.equiv +This file is used during \s+2.\s0rhosts authentication. In the +simplest form, this file contains host names, one per line. Users on +those hosts are permitted to log in without a password, provided they +have the same user name on both machines. The host name may also be +followed by a user name; such users are permitted to log in as +.B any +user on this machine (except root). Additionally, the syntax +@group +can be used to specify netgroups. Negated entries start with '-'. + +If the client host/user is successfully matched in this file, login is +automatically permitted provided the client and server user names are the +same. Additionally, successful RSA host authentication is normally +required. This file must be writable only by root; it is recommended +that it be world-readable. + +\fBWarning: It is almost never a good idea to use user names in +hosts.equiv.\fR +Beware that it really means that the named user(s) can log in as +\fBanybody\fR, +which includes bin, daemon, adm, and other accounts that own critical +binaries and directories. Using a user name practically grants the +user root access. The only valid use for user names that I can think +of is in negative entries. +\fBNote that this warning also applies to rsh/rlogin.\fR +.TP +.I /etc/shosts.equiv +This is processed exactly as +.I /etc/hosts.equiv. +However, this file may be useful in environments that want to run both +rsh/rlogin and +.B ssh. +.TP +.I /etc/environment +This file is read into the environment at login (if it exists). It +can only contain empty lines, comment lines (that start with '#'), and +assignment lines of the form name=value. This file is processed in +all environments (normal rsh/rlogin only process it on AIX and +potentially some other systems). The file should be writable only by +root, and should be world-readable. +.TP +.I \&$HOME/\s+2.\s0ssh/environment +This file is read into the environment after /etc/environment. It has +the same format. The file should be writable only by the user; it +need not be readable by anyone else. +.TP +.I \&$HOME/\s+2.\s0ssh/rc +If this file exists, it is run with /bin/sh after reading the +environment files but before starting the user's shell or command. If +X11 spoofing is in use, this will receive the "proto cookie" pair in +standard input (and DISPLAY in environment). This must call xauth in +that case. + +The primary purpose of this file is to run any initialization routines +which may be needed before the user's home directory becomes +accessible; AFS is a particular example of such an environment. + +This file will probably contain some initialization code followed by +something similar to: "if read proto cookie; then echo add $DISPLAY +$proto $cookie | xauth -q -; fi". + +If this file does not exist, /etc/sshrc is run, and if that +does not exist either, xauth is used to store the cookie. + +This file should be writable only by the user, and need not be +readable by anyone else. +.TP +.I /etc/sshrc +Like $HOME/\s+2.\s0ssh/rc. This can be used to specify +machine-specific login-time initializations globally. This file +should be writable only by root, and should be world-readable. + + +.SH INSTALLATION +.LP +.B Sshd +is normally run as root. If it is not run as root, it can +only log in as the user it is running as, and password authentication +may not work if the system uses shadow passwords. An alternative +host key file must also be used. +.LP +.B Sshd +is normally started from +.I /etc/rc.local +or equivalent at system boot. +.LP +Considerable work has been put to making +.B sshd +secure. However, if you find a security problem, please report it +immediately to <ssh-bugs@cs.hut.fi>. + +.SH AUTHOR +.LP +Tatu Ylonen <ylo@cs.hut.fi> +.LP +Information about new releases, mailing lists, and other related +issues can be found from the ssh WWW home page at +http://www.cs.hut.fi/ssh. + +.SH SEE ALSO +.LP +.BR ssh (1), +.BR make-ssh-known-hosts (1), +.BR ssh-keygen (1), +.BR ssh-agent (1), +.BR ssh-add (1), +.BR scp (1), +.BR rlogin (1), +.BR rsh (1) diff --git a/usr.bin/ssh/sshd.8.in b/usr.bin/ssh/sshd.8.in new file mode 100644 index 00000000000..419c132144c --- /dev/null +++ b/usr.bin/ssh/sshd.8.in @@ -0,0 +1,734 @@ +.\" -*- nroff -*- +.\" +.\" sshd.8.in +.\" +.\" Author: Tatu Ylonen <ylo@cs.hut.fi> +.\" +.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland +.\" All rights reserved +.\" +.\" Created: Sat Apr 22 21:55:14 1995 ylo +.\" +.\" $Id: sshd.8.in,v 1.1 1999/09/26 20:53:38 deraadt Exp $ +.\" +.TH SSHD 8 "November 8, 1995" "SSH" "SSH" + +.SH NAME +sshd \- secure shell daemon + +.SH SYNOPSIS +.na +.B sshd +[\c +.BI \-b \ bits\fR\c +] +[\c +.B \-d \c +] +[\c +.BI \-f \ config_file\fR\c +] +[\c +.BI \-g \ login_grace_time\fR\c +] +[\c +.BI \-h \ host_key_file\fR\c +] +[\c +.B \-i \c +] +[\c +.BI \-k \ key_gen_time\fR\c +] +[\c +.BI \-p \ port\fR\c +] +[\c +.B \-q \c +] +.ad + + +.SH DESCRIPTION +.LP +.B Sshd +(Secure Shell Daemon) is the daemon program for +.BR ssh ". +Together these programs replace rlogin and rsh programs, and +provide secure encrypted communications between two untrusted hosts +over an insecure network. The programs are intended to be as easy to +install and use as possible. +.LP +.B Sshd +is the daemon that listens for connections from clients. It is +normally started at boot from +.I /etc/rc.local +or equivalent. It forks a new +daemon for each incoming connection. The forked daemons handle +key exchange, encryption, authentication, command execution, +and data exchange. +.LP +Sshd works as follows. Each host has a host-specific RSA key +(normally 1024 bits) used to identify the host. Additionally, when +the daemon starts, it generates a server RSA key (normally 768 bits). +This key is normally regenerated every hour if it has been used, and +is never stored on disk. +.LP +Whenever a client connects the daemon, the daemon sends its host +and server public keys to the client. The client compares the +host key against its own database to verify that it has not changed. +The client then generates a 256 bit random number. It encrypts this +random number using both the host key and the server key, and sends +the encrypted number to the server. Both sides then start to use this +random number as a session key which is used to encrypt all further +communications in the session. The rest of the session is encrypted +using a conventional cipher. Currently, +.BR \s-1Blowfish\s0 ", +.BR \s-1IDEA\s0 ", +.BR \s-1DES\s0 ", +.BR \s-1\&3DES\s0 ", +.B \s-13DES\s0 +is used by default. The client selects the encryption algorithm to use +from those offered by the server. +.LP +Next, the server and the client enter an authentication dialog. The +client tries to authenticate itself using \|\s+2.\s0rhosts +authentication, \|\s+2.\s0rhosts authentication combined with RSA host +authentication, RSA challenge-response authentication, or password +based authentication. +.LP +Rhosts authentication is normally disabled +because it is fundamentally insecure, but can be enabled in the server +configuration file if desired. System security is not improved unless +.BR rshd "(8), +.BR rlogind "(8), +.BR rexecd "(8), and +.B rexd "(8) +are disabled (thus completely disabling +.BR rlogin (1) +and +.BR rsh (1) +into that machine). +.LP +If the client successfully authenticates itself, a dialog for +preparing the session is entered. At this time the client may request +things like allocating a pseudo-tty, forwarding X11 connections, +forwarding TCP/IP connections, or forwarding the authentication agent +connection over the secure channel. +.LP +Finally, the client either requests a shell or execution of a command. +The sides then enter session mode. In this mode, either side may send +data at any time, and such data is forwarded to/from the shell or +command on the server side, and the user terminal in the client side. +.LP +When the user program terminates and all forwarded X11 and other +connections have been closed, the server sends command exit status to +the client, and both sides exit. +.LP +.B Sshd +can be configured using command-line options or a configuration +file. Command-line options override values specified in the +configuration file. + + +.SH OPTIONS +.TP +.BI \-b \ bits +Specifies the number of bits in the server key (default 768). +.TP +.B \-d +Debug mode. The server sends verbose debug output to the system +log, and does not put itself in the background. The server also will +not fork and will only process one connection. This option is only +intended for debugging for the server. +.TP +.BI \-f \ configuration_file +Specifies the name of the configuration file. The default is +.IR @ETCDIR@/sshd_config ". +.TP +.BI \-g \ login_grace_time +Gives the grace time for clients to authenticate themselves (default +300 seconds). If the client fails to authenticate the user within +this many seconds, the server disconnects and exits. A value of zero +indicates no limit. +.TP +.BI \-h \ host_key_file +Specifies the file from which the host key is read (default +.IR @ETCDIR@/ssh_host_key). +This option must be given if sshd is not run as root (as the normal +host file is normally not readable by anyone but root). +.TP +.B \-i +Specifies that sshd is being run from inetd. Sshd is normally not run +from inetd because it needs to generate the server key before it can +respond to the client, and this may take tens of seconds. Clients +would have to wait too long if the key was regenerated every time. +However, with small key sizes (e.g. 512) using sshd from inetd may +be feasible. +.TP +.BI \-k \ key_gen_time +Specifies how often the server key is regenerated (default 3600 +seconds, or one hour). The motivation for regenerating the key fairly +often is that the key is not stored anywhere, and after about an hour, +it becomes impossible to recover the key for decrypting intercepted +communications even if the machine is cracked into or physically +seized. A value of zero indicates that the key will never be regenerated. +.TP +.BI \-p \ port +Specifies the port on which the server listens for connections +(default 22). +.TP +.B \-q +Quiet mode. Nothing is sent to the system log. Normally the beginning, +authentication, and termination of each connection is logged. + +.SH CONFIGURATION FILE + +.B Sshd +reads configuration data from +.I @ETCDIR@/sshd_config +(or the file specified with -f on the command line). The file +contains keyword-value pairs, one per line. Lines starting with '#' +and empty lines are interpreted as comments. + +The following keywords are possible. +.TP +.B AFSTokenPassing +Specifies whether to accept AFS tokens passed from the client. Default +is "yes". +.TP +.B AllowHosts +This keyword can be followed by any number of host name patterns, +separated by spaces. If specified, login is allowed only from hosts +whose name matches one of the patterns. '*' and '?' can be used as +wildcards in the patterns. Normal name servers are used to map the +client's host into a canonical host name. If the name cannot be +mapped, its IP-address is used as the host name. By default all hosts +are allowed to connect. + +Note that +.B sshd +can also be configured to use tcp_wrappers using the --with-libwrap +compile-time configuration option. +.TP +.B DenyHosts +This keyword can be followed by any number of host name patterns, +separated by spaces. If specified, login is disallowed from the hosts +whose name matches any of the patterns. +.TP +.B FascistLogging +Specifies whether to use verbose logging. Verbose logging violates +the privacy of users and is not recommended. The argument must be +"yes" or "no" (without the quotes). The default is "no". +.TP +.B HostKey +Specifies the file containing the private host key (default +.IR @ETCDIR@/ssh_host_key "). +.TP +.B IgnoreRhosts +Specifies that rhosts and shosts files will not be used in +authentication. +.I /etc/hosts.equiv +and +.I @ETCDIR@/shosts.equiv +are still used. The default is "no". +.TP +.B KeepAlive +Specifies whether the system should send keepalive messages to the +other side. If they are sent, death of the connection or crash of one +of the machines will be properly noticed. However, this means that +connections will die if the route is down temporarily, and some people +find it annoying. On the other hand, if keepalives are not send, +sessions may hang indefinitely on the server, leaving "ghost" users +and consuming server resources. + +The default is "yes" (to send keepalives), and the server will notice +if the network goes down or the client host reboots. This avoids +infinitely hanging sessions. + +To disable keepalives, the value should be set to "no" in both the +server and the client configuration files. +.TP +.B KerberosAuthentication +Specifies whether Kerberos authentication is allowed. This can +be in the form of a Kerberos ticket, or if PasswordAuthentication +is yes, the password provided by the user will be validated through +the Kerberos KDC / AFS kaserver / DCE Security Server. Default is yes. +.TP +.B KerberosOrLocalPasswd +If set then if password authentication through Kerberos fails then +the password will be validated via any additional local mechanism +such as /etc/passwd or SecurID. Default is no. +.TP +.B KerberosTgtPassing +Specifies whether a Kerberos TGT may be forwarded to the server. +Default is no, TGT forwarding does only work with the AFS kaserver. +.TP +.B KerberosTicketCleanup +Specifies whether to automatically destroy the user's +ticket cache file on logout. Default is yes. +.TP +.B KeyRegenerationInterval +The server key is automatically regenerated after this many seconds +(if it has been used). The purpose of regeneration is to prevent +decrypting captured sessions by later breaking into the machine and +stealing the keys. The key is never stored anywhere. If the value is +0, the key is never regenerated. The default is 3600 +(seconds). +.TP +.B LoginGraceTime +The server disconnects after this time if the user has not +successfully logged in. If the value is 0, there is no time limit. +The default is 600 (seconds). +.TP +.B PasswordAuthentication +Specifies whether password authentication is allowed. +The default is "yes". +.TP +.B PermitEmptyPasswords +When password authentication is allowed, it specifies whether the +server allows login to accounts with empty password strings. The default +is "yes". +.TP +.B PermitRootLogin +Specifies whether the root can log in using +.BR ssh . +The default is "yes". + +Root login with RSA authentication when the "command" option has been +specified will be allowed regardless of the value of this setting +(which may be useful for taking remote backups even if root login is +normally not allowed). +.TP +.B Port +Specifies the port number that +.B sshd +listens on. The default is 22. +.TP +.B PrintMotd +Specifies whether +.B sshd +should print +.I /etc/motd +when a user logs in interactively. (On some systems it is also +printed by the shell, /etc/profile, or equivalent.) The default is +"yes". +.TP +.B QuietMode +Specifies whether the system runs in quiet mode. In quiet mode, +nothing is logged in the system log, except fatal errors. The default +is "no". +.TP +.B RandomSeed +Specifies the file containing the random seed for the server; this +file is created automatically and updated regularly. The default is +.IR @ETCDIR@/ssh_random_seed ". +.TP +.B RhostsAuthentication +Specifies whether authentication using rhosts or /etc/hosts.equiv +files is sufficient. Normally, this method should not be permitted +because it is insecure. RhostsRSAAuthentication should be used +instead, because it performs RSA-based host authentication in addition +to normal rhosts or /etc/hosts.equiv authentication. +The default is "no". +.TP +.B RhostsRSAAuthentication +Specifies whether rhosts or /etc/hosts.equiv authentication together +with successful RSA host authentication is allowed. The default is "yes". +.TP +.B RSAAuthentication +Specifies whether pure RSA authentication is allowed. The default is "yes". +.TP +.B ServerKeyBits +Defines the number of bits in the server key. The minimum value is +512, and the default is 768. +.TP +.B StrictModes +Specifies whether ssh should check file modes and ownership of the +user's home directory and rhosts files before accepting login. This +is normally desirable because novices sometimes accidentally leave their +directory or files world-writable. The default is "yes". +.TP +.B SyslogFacility +Gives the facility code that is used when logging messages from +.B sshd. +The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2, +LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The default is DAEMON. +.TP +.B X11Forwarding +Specifies whether X11 forwarding is permitted. The default is "yes". +Note that disabling X11 forwarding does not improve security in any +way, as users can always install their own forwarders. + +.SH LOGIN PROCESS + +When a user successfully logs in, +.B sshd +does the following: +.IP 1. +If the login is on a tty, and no command has been specified, +prints last login time and +.B /etc/motd +(unless prevented in the configuration file or by +.IR $HOME/\s+2.\s0hushlogin ; +see the FILES section). +.IP 2. +If the login is on a tty, records login time. +.IP 3. +Checks /etc/nologin; if it exists, prints contents and quits +(unless root). +.IP 4. +Changes to run with normal user privileges. +.IP 5. +Sets up basic environment. +.IP 6. +Reads /etc/environment if it exists. +.IP 7. +Reads $HOME/.ssh/environment if it exists. +.IP 8. +Changes to user's home directory. +.IP 9. +If $HOME/.ssh/rc exists, runs it; else if @ETCDIR@/sshrc exists, runs +it; otherwise runs xauth. The "rc" files are given the X11 +authentication protocol and cookie in standard input. +.IP 10. +Runs user's shell or command. +.RT + + +.SH AUTHORIZED_KEYS FILE FORMAT +.LP +The +.I \&$HOME/\s+2.\s0ssh/authorized_keys +file lists the RSA keys that are +permitted for RSA authentication. Each line of the file contains one +key (empty lines and lines starting with a '#' are ignored as +comments). Each line consists of the following fields, separated by +spaces: options, bits, exponent, modulus, comment. The options field +is optional; its presence is determined by whether the line starts +with a number or not (the option field never starts with a number). +The bits, exponent, modulus and comment fields give the RSA key; the +comment field is not used for anything (but may be convenient for the +user to identify the key). +.LP +Note that lines in this file are usually several hundred bytes long +(because of the size of the RSA key modulus). You don't want to type +them in; instead, copy the +.I identity.pub +file and edit it. +.LP +The options (if present) consists of comma-separated option +specifications. No spaces are permitted, except within double quotes. +The following option specifications are supported: +.IP +.ti -.5i +\fBfrom="pattern-list" \fR +.br +Specifies that in addition to RSA authentication, the canonical name +of the remote host must be present in the comma-separated list of +patterns ('*' and '?' serve as wildcards). The list may also contain +patterns negated by prefixing them with '!'; if the canonical host +name matches a negated pattern, the key is not accepted. The purpose +of this option is to optionally increase security: RSA authentication +by itself does not trust the network or name servers or anything (but +the key); however, if somebody somehow steals the key, the key +permits an intruder to log in from anywhere in the world. This +additional option makes using a stolen key more difficult (name +servers and/or routers would have to be compromised in addition to +just the key). +.IP +.ti -.5i +\fBcommand="command"\fR +.br +Specifies that the command is executed whenever this key is used for +authentication. The command supplied by the user (if any) is ignored. +The command is run on a pty if the connection requests a pty; +otherwise it is run without a tty. A quote may be included in the +command by quoting it with a backslash. This option might be useful +to restrict certain RSA keys to perform just a specific operation. An +example might be a key that permits remote backups but nothing +else. Notice that the client may specify TCP/IP and/or X11 +forwardings unless they are explicitly prohibited. +.IP +.ti -.5i +\fBenvironment="NAME=value"\fR +.br +Specifies that the string is to be added to the environment when +logging in using this key. Environment variables set this way +override other default environment values. Multiple options of this +type are permitted. +.TP +.B no-port-forwarding +Forbids TCP/IP forwarding when this key is used for authentication. +Any port forward requests by the client will return an error. This +might be used e.g. in connection with the +.B command +option. +.TP +.B no-X11-forwarding +Forbids X11 forwarding when this key is used for authentication. +Any X11 forward requests by the client will return an error. +.TP +.B no-agent-forwarding +Forbids authentication agent forwarding when this key is used for +authentication. +.TP +.B no-pty +Prevents tty allocation (a request to allocate a pty will fail). + +.SS Examples +.LP +1024 33 12121.\|.\|.\|312314325 ylo@foo.bar +.LP +from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23.\|.\|.\|2334 ylo@niksula +.LP +command="dump /home",no-pty,no-port-forwarding 1024 33 23.\|.\|.\|2323 backup.hut.fi + + + +.SH SSH_KNOWN_HOSTS FILE FORMAT +.LP +The +.I @ETCDIR@/ssh_known_hosts +and +.I \&$HOME/\s+2.\s0ssh/known_hosts +files contain host public keys for all known hosts. The global file should +be prepared by the admistrator (optional), and the per-user file is +maintained automatically: whenever the user connects an unknown host +its key is added to the per-user file. The recommended way to create +.I @ETCDIR@/ssh_known_hosts +is to use the +.B make-ssh-known-hosts +command. +.LP +Each line in these files contains the following fields: hostnames, +bits, exponent, modulus, comment. The fields are separated by spaces. +.LP +Hostnames is a comma-separated list of patterns ('*' and '?' act as +wildcards); each pattern in turn is matched against the canonical host +name (when authenticating a client) or against the user-supplied +name (when authenticating a server). A pattern may also be preceded +by '!' to indicate negation: if the host name matches a negated +pattern, it is not accepted (by that line) even if it matched another +pattern on the line. +.LP +Bits, exponent, and modulus are taken directly from the host key; they +can be obtained e.g. from +.IR @ETCDIR@/ssh_host_key.pub ". +The optional comment field continues to the end of the line, and is not used. +.LP +Lines starting with '#' and empty lines are ignored as comments. +.LP +When performing host authentication, authentication is accepted if any +matching line has the proper key. It is thus permissible (but not +recommended) to have several lines or different host keys for the same +names. This will inevitably happen when short forms of host names +from different domains are put in the file. It is possible +that the files contain conflicting information; authentication is +accepted if valid information can be found from either file. +.LP +Note that the lines in these files are typically hundreds of characters +long, and you definitely don't want to type in the host keys by hand. +Rather, generate them by a script (see +.BR make-ssh-known-hosts (1)) +or by taking +.I @ETCDIR@/ssh_host_key.pub +and adding the host names at the front. + +.SS Examples + +closenet,closenet.hut.fi,.\|.\|.\|,130.233.208.41 1024 37 159.\|.\|.93 closenet.hut.fi + +.SH FILES +.TP +.I @ETCDIR@/sshd_config +Contains configuration data for +.BR sshd . +This file should be writable by root only, but it is recommended +(though not necessary) that it be world-readable. +.TP +.I @ETCDIR@/ssh_host_key +Contains the private part of the host key. This file is normally +created automatically by "make install", but can also be created +manually using +.BR ssh-keygen (1). +This file should only be owned by root, readable only by root, and not +accessible to others. +.TP +.I @ETCDIR@/ssh_host_key.pub +Contains the public part of the host key. This file is normally +created automatically by "make install", but can also be created +manually. This file should be world-readable but writable only by +root. Its contents should match the private part. This file is not +really used for anything; it is only provided for the convenience of +the user so its contents can be copied to known hosts files. +.TP +.I @ETCDIR@/ssh_random_seed +This file contains a seed for the random number generator. This file +should only be accessible by root. +.TP +.I @PIDDIR@/sshd.pid +Contains the process id of the +.B sshd +listening for connections (if there are several daemons running +concurrently for different ports, this contains the pid of the one +started last). The contents of this file are not sensitive; it can be +world-readable. +.TP +.I \&$HOME/\s+2.\s0ssh/authorized_keys +Lists the RSA keys that can be used to log into the user's account. +This file must be readable by root (which may on some machines imply +it being world-readable if the user's home directory resides on an NFS +volume). It is recommended that it not be accessible by others. The +format of this file is described above. +.TP +.I "@ETCDIR@/ssh_known_hosts\fR and \fI$HOME/\s+2.\s0ssh/known_hosts\fR +These files are consulted when using rhosts with RSA host +authentication to check the public key of the host. The key must be +listed in one of these files to be accepted. (The client uses the +same files to verify that the remote host is the one we intended to +connect.) These files should be writable only by root/the owner. +.I @ETCDIR@/ssh_known_hosts +should be world-readable, and \fI$HOME/\s+2.\s0ssh/known_hosts\fR can +but need not be world-readable. +.TP +.I /etc/nologin +If this file exists, +.B sshd +refuses to let anyone except root log in. The contents of the file +are displayed to anyone trying to log in, and non-root connections are +refused. The file should be world-readable. +.TP +.I \&$HOME/\s+2.\s0rhosts +This file contains host-username pairs, separated by a space, one per +line. The given user on the corresponding host is permitted to log in +without password. The same file is used by rlogind and rshd. +.B Ssh +differs from rlogind +and rshd in that it requires RSA host authentication in addition to +validating the host name retrieved from domain name servers (unless +compiled with the \-\-with\-rhosts configuration option). The file must +be writable only by the user; it is recommended that it not be +accessible by others. + +If is also possible to use netgroups in the file. Either host or user +name may be of the form +@groupname to specify all hosts or all users +in the group. +.TP +.I \&$HOME/\s+2.\s0shosts +For +.B ssh, +this file is exactly the same as for \s+2.\s0rhosts. However, this file is +not used by rlogin and rshd, so using this permits access using +.B ssh +only. +.TP +.I /etc/hosts.equiv +This file is used during \s+2.\s0rhosts authentication. In the +simplest form, this file contains host names, one per line. Users on +those hosts are permitted to log in without a password, provided they +have the same user name on both machines. The host name may also be +followed by a user name; such users are permitted to log in as +.B any +user on this machine (except root). Additionally, the syntax +@group +can be used to specify netgroups. Negated entries start with '-'. + +If the client host/user is successfully matched in this file, login is +automatically permitted provided the client and server user names are the +same. Additionally, successful RSA host authentication is normally +required. This file must be writable only by root; it is recommended +that it be world-readable. + +\fBWarning: It is almost never a good idea to use user names in +hosts.equiv.\fR +Beware that it really means that the named user(s) can log in as +\fBanybody\fR, +which includes bin, daemon, adm, and other accounts that own critical +binaries and directories. Using a user name practically grants the +user root access. The only valid use for user names that I can think +of is in negative entries. +\fBNote that this warning also applies to rsh/rlogin.\fR +.TP +.I @ETCDIR@/shosts.equiv +This is processed exactly as +.I /etc/hosts.equiv. +However, this file may be useful in environments that want to run both +rsh/rlogin and +.B ssh. +.TP +.I /etc/environment +This file is read into the environment at login (if it exists). It +can only contain empty lines, comment lines (that start with '#'), and +assignment lines of the form name=value. This file is processed in +all environments (normal rsh/rlogin only process it on AIX and +potentially some other systems). The file should be writable only by +root, and should be world-readable. +.TP +.I \&$HOME/\s+2.\s0ssh/environment +This file is read into the environment after /etc/environment. It has +the same format. The file should be writable only by the user; it +need not be readable by anyone else. +.TP +.I \&$HOME/\s+2.\s0ssh/rc +If this file exists, it is run with /bin/sh after reading the +environment files but before starting the user's shell or command. If +X11 spoofing is in use, this will receive the "proto cookie" pair in +standard input (and DISPLAY in environment). This must call xauth in +that case. + +The primary purpose of this file is to run any initialization routines +which may be needed before the user's home directory becomes +accessible; AFS is a particular example of such an environment. + +This file will probably contain some initialization code followed by +something similar to: "if read proto cookie; then echo add $DISPLAY +$proto $cookie | xauth -q -; fi". + +If this file does not exist, @ETCDIR@/sshrc is run, and if that +does not exist either, xauth is used to store the cookie. + +This file should be writable only by the user, and need not be +readable by anyone else. +.TP +.I @ETCDIR@/sshrc +Like $HOME/\s+2.\s0ssh/rc. This can be used to specify +machine-specific login-time initializations globally. This file +should be writable only by root, and should be world-readable. + + +.SH INSTALLATION +.LP +.B Sshd +is normally run as root. If it is not run as root, it can +only log in as the user it is running as, and password authentication +may not work if the system uses shadow passwords. An alternative +host key file must also be used. +.LP +.B Sshd +is normally started from +.I /etc/rc.local +or equivalent at system boot. +.LP +Considerable work has been put to making +.B sshd +secure. However, if you find a security problem, please report it +immediately to <ssh-bugs@cs.hut.fi>. + +.SH AUTHOR +.LP +Tatu Ylonen <ylo@cs.hut.fi> +.LP +Information about new releases, mailing lists, and other related +issues can be found from the ssh WWW home page at +http://www.cs.hut.fi/ssh. + +.SH SEE ALSO +.LP +.BR ssh (1), +.BR make-ssh-known-hosts (1), +.BR ssh-keygen (1), +.BR ssh-agent (1), +.BR ssh-add (1), +.BR scp (1), +.BR rlogin (1), +.BR rsh (1) diff --git a/usr.bin/ssh/sshd.c b/usr.bin/ssh/sshd.c new file mode 100644 index 00000000000..bdf86bb0e05 --- /dev/null +++ b/usr.bin/ssh/sshd.c @@ -0,0 +1,2373 @@ +/* + +sshd.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Fri Mar 17 17:09:28 1995 ylo + +This program is the ssh daemon. It listens for connections from clients, and +performs authentication, executes use commands or shell, and forwards +information to/from the application to the user client over an encrypted +connection. This can also handle forwarding of X11, TCP/IP, and authentication +agent connections. + +*/ + +#include "includes.h" +RCSID("$Id: sshd.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); + +#include <gmp.h> +#include "xmalloc.h" +#include "rsa.h" +#include "ssh.h" +#include "pty.h" +#include "packet.h" +#include "buffer.h" +#include "cipher.h" +#include "mpaux.h" +#include "servconf.h" +#include "uidswap.h" +#ifdef HAVE_USERSEC_H +#include <usersec.h> +#endif /* HAVE_USERSEC_H */ +#ifdef HAVE_ULIMIT_H +#include <ulimit.h> +#endif /* HAVE_ULIMIT_H */ + +#ifdef LIBWRAP +#include <tcpd.h> +#include <syslog.h> +#ifdef NEED_SYS_SYSLOG_H +#include <sys/syslog.h> +#endif /* NEED_SYS_SYSLOG_H */ +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; +#endif /* LIBWRAP */ + +#ifdef _PATH_BSHELL +#define DEFAULT_SHELL _PATH_BSHELL +#else +#define DEFAULT_SHELL "/bin/sh" +#endif + +#ifndef DEFAULT_PATH +#ifdef _PATH_USERPATH +#define DEFAULT_PATH _PATH_USERPATH +#else +#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bin/X11:/usr/local/bin" +#endif +#endif /* DEFAULT_PATH */ + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +#ifdef KRB4 +#include <sys/param.h> +#include <krb.h> +char *ticket = NULL; +#ifdef AFS +#include <kafs.h> +#endif /* AFS */ +#endif /* KRB4 */ + +/* Local Xauthority file. */ +char *xauthfile = NULL; + +/* Server configuration options. */ +ServerOptions options; + +/* Name of the server configuration file. */ +char *config_file_name = SERVER_CONFIG_FILE; + +/* Debug mode flag. This can be set on the command line. If debug + mode is enabled, extra debugging output will be sent to the system + log, the daemon will not go to background, and will exit after processing + the first connection. */ +int debug_flag = 0; + +/* Flag indicating that the daemon is being started from inetd. */ +int inetd_flag = 0; + +/* argv[0] without path. */ +char *av0; + +/* Saved arguments to main(). */ +char **saved_argv; + +/* This is set to the socket that the server is listening; this is used in + the SIGHUP signal handler. */ +int listen_sock; + +/* Flags set in auth-rsa from authorized_keys flags. These are set in + auth-rsa.c. */ +int no_port_forwarding_flag = 0; +int no_agent_forwarding_flag = 0; +int no_x11_forwarding_flag = 0; +int no_pty_flag = 0; +char *forced_command = NULL; /* RSA authentication "command=" option. */ +struct envstring *custom_environment = NULL; + /* RSA authentication "environment=" options. */ + +/* Session id for the current session. */ +unsigned char session_id[16]; + +/* Any really sensitive data in the application is contained in this structure. + The idea is that this structure could be locked into memory so that the + pages do not get written into swap. However, there are some problems. + The private key contains MP_INTs, and we do not (in principle) have + access to the internals of them, and locking just the structure is not + very useful. Currently, memory locking is not implemented. */ +struct +{ + /* Random number generator. */ + RandomState random_state; + + /* Private part of server key. */ + RSAPrivateKey private_key; + + /* Private part of host key. */ + RSAPrivateKey host_key; +} sensitive_data; + +/* Flag indicating whether the current session key has been used. This flag + is set whenever the key is used, and cleared when the key is regenerated. */ +int key_used = 0; + +/* This is set to true when SIGHUP is received. */ +int received_sighup = 0; + +/* Public side of the server key. This value is regenerated regularly with + the private key. */ +RSAPublicKey public_key; + +/* Prototypes for various functions defined later in this file. */ +void do_connection(int privileged_port); +void do_authentication(char *user, int privileged_port); +void do_authenticated(struct passwd *pw); +void do_exec_pty(const char *command, int ptyfd, int ttyfd, + const char *ttyname, struct passwd *pw, const char *term, + const char *display, const char *auth_proto, + const char *auth_data); +void do_exec_no_pty(const char *command, struct passwd *pw, + const char *display, const char *auth_proto, + const char *auth_data); +void do_child(const char *command, struct passwd *pw, const char *term, + const char *display, const char *auth_proto, + const char *auth_data, const char *ttyname); + +/* Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP; + the effect is to reread the configuration file (and to regenerate + the server key). */ + +RETSIGTYPE sighup_handler(int sig) +{ + received_sighup = 1; + signal(SIGHUP, sighup_handler); +} + +/* Called from the main program after receiving SIGHUP. Restarts the + server. */ + +void sighup_restart() +{ + log("Received SIGHUP; restarting."); + close(listen_sock); + execv(saved_argv[0], saved_argv); + log("RESTART FAILED: av0='%s', error: %s.", av0, strerror(errno)); + exit(1); +} + +/* Generic signal handler for terminating signals in the master daemon. + These close the listen socket; not closing it seems to cause "Address + already in use" problems on some machines, which is inconvenient. */ + +RETSIGTYPE sigterm_handler(int sig) +{ + log("Received signal %d; terminating.", sig); + close(listen_sock); + exit(255); +} + +/* SIGCHLD handler. This is called whenever a child dies. This will then + reap any zombies left by exited c. */ + +RETSIGTYPE main_sigchld_handler(int sig) +{ + int status; + wait(&status); + signal(SIGCHLD, main_sigchld_handler); +} + +/* Signal handler for the alarm after the login grace period has expired. */ + +RETSIGTYPE grace_alarm_handler(int sig) +{ + /* Close the connection. */ + packet_close(); + + /* Log error and exit. */ + fatal("Timeout before authentication."); +} + +/* Signal handler for the key regeneration alarm. Note that this + alarm only occurs in the daemon waiting for connections, and it does not + do anything with the private key or random state before forking. Thus there + should be no concurrency control/asynchronous execution problems. */ + +RETSIGTYPE key_regeneration_alarm(int sig) +{ + /* Check if we should generate a new key. */ + if (key_used) + { + /* This should really be done in the background. */ + log("Generating new %d bit RSA key.", options.server_key_bits); + random_acquire_light_environmental_noise(&sensitive_data.random_state); + rsa_generate_key(&sensitive_data.private_key, &public_key, + &sensitive_data.random_state, options.server_key_bits); + random_stir(&sensitive_data.random_state); + random_save(&sensitive_data.random_state, options.random_seed_file); + key_used = 0; + log("RSA key generation complete."); + } + + /* Reschedule the alarm. */ + signal(SIGALRM, key_regeneration_alarm); + alarm(options.key_regeneration_time); +} + +/* Main program for the daemon. */ + +int main(int ac, char **av) +{ + extern char *optarg; + extern int optind; + int opt, aux, sock_in, sock_out, newsock, i, pid, on = 1; + int remote_major, remote_minor; + struct sockaddr_in sin; + char buf[100]; /* Must not be larger than remote_version. */ + char remote_version[100]; /* Must be at least as big as buf. */ + char *comment; + FILE *f; +#ifdef SO_LINGER + struct linger linger; +#endif /* SO_LINGER */ + + /* Save argv[0]. */ + saved_argv = av; + if (strchr(av[0], '/')) + av0 = strrchr(av[0], '/') + 1; + else + av0 = av[0]; + + /* Initialize configuration options to their default values. */ + initialize_server_options(&options); + + /* Parse command-line arguments. */ + while ((opt = getopt(ac, av, "f:p:b:k:h:g:diq")) != EOF) + { + switch (opt) + { + case 'f': + config_file_name = optarg; + break; + case 'd': + debug_flag = 1; + break; + case 'i': + inetd_flag = 1; + break; + case 'q': + options.quiet_mode = 1; + break; + case 'b': + options.server_key_bits = atoi(optarg); + break; + case 'p': + options.port = atoi(optarg); + break; + case 'g': + options.login_grace_time = atoi(optarg); + break; + case 'k': + options.key_regeneration_time = atoi(optarg); + break; + case 'h': + options.host_key_file = optarg; + break; + case '?': + default: + fprintf(stderr, "sshd version %s\n", SSH_VERSION); + fprintf(stderr, "Usage: %s [options]\n", av0); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -f file Configuration file (default %s/sshd_config)\n", ETCDIR); + fprintf(stderr, " -d Debugging mode\n"); + fprintf(stderr, " -i Started from inetd\n"); + fprintf(stderr, " -q Quiet (no logging)\n"); + fprintf(stderr, " -p port Listen on the specified port (default: 22)\n"); + fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n"); + fprintf(stderr, " -g seconds Grace period for authentication (default: 300)\n"); + fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n"); + fprintf(stderr, " -h file File from which to read host key (default: %s)\n", + HOST_KEY_FILE); + exit(1); + } + } + + /* Read server configuration options from the configuration file. */ + read_server_config(&options, config_file_name); + + /* Fill in default values for those options not explicitly set. */ + fill_default_server_options(&options); + + /* Check certain values for sanity. */ + if (options.server_key_bits < 512 || + options.server_key_bits > 32768) + { + fprintf(stderr, "Bad server key size.\n"); + exit(1); + } + if (options.port < 1 || options.port > 65535) + { + fprintf(stderr, "Bad port number.\n"); + exit(1); + } + + /* Check that there are no remaining arguments. */ + if (optind < ac) + { + fprintf(stderr, "Extra argument %s.\n", av[optind]); + exit(1); + } + + /* Initialize the log (it is reinitialized below in case we forked). */ + log_init(av0, debug_flag && !inetd_flag, + debug_flag || options.fascist_logging, + options.quiet_mode, options.log_facility); + + debug("sshd version %.100s", SSH_VERSION); + + /* Load the host key. It must have empty passphrase. */ + if (!load_private_key(options.host_key_file, "", + &sensitive_data.host_key, &comment)) + { + if (debug_flag) + fprintf(stderr, "Could not load host key: %s: %s\n", + options.host_key_file, strerror(errno)); + else + { + int err = errno; + log_init(av0, !inetd_flag, 1, 0, options.log_facility); + error("Could not load host key: %.200s: %.100s", + options.host_key_file, strerror(err)); + } + exit(1); + } + xfree(comment); + +#ifdef SCO + (void) set_auth_parameters(ac, av); +#endif + +#ifdef HAVE_OSF1_C2_SECURITY + initialize_osf_security(ac, av); +#endif /* HAVE_OSF1_C2_SECURITY */ + + /* If not in debugging mode, and not started from inetd, disconnect from + the controlling terminal, and fork. The original process exits. */ + if (!debug_flag && !inetd_flag) + { +#ifdef TIOCNOTTY + int fd; +#endif /* TIOCNOTTY */ + + /* Fork, and have the parent exit. The child becomes the server. */ + if (fork()) + exit(0); + + /* Redirect stdin, stdout, and stderr to /dev/null. */ + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + + /* Disconnect from the controlling tty. */ +#ifdef TIOCNOTTY + fd = open("/dev/tty", O_RDWR|O_NOCTTY); + if (fd >= 0) + { + (void)ioctl(fd, TIOCNOTTY, NULL); + close(fd); + } +#endif /* TIOCNOTTY */ +#ifdef HAVE_SETSID + (void)setsid(); +#endif /* HAVE_SETSID */ + } + + /* Reinitialize the log (because of the fork above). */ + log_init(av0, debug_flag && !inetd_flag, + debug_flag || options.fascist_logging, + options.quiet_mode, options.log_facility); + + /* Check that server and host key lengths differ sufficiently. This is + necessary to make double encryption work with rsaref. Oh, I hate + software patents. */ + if (options.server_key_bits > + sensitive_data.host_key.bits - SSH_KEY_BITS_RESERVED && + options.server_key_bits < + sensitive_data.host_key.bits + SSH_KEY_BITS_RESERVED) + { + options.server_key_bits = + sensitive_data.host_key.bits + SSH_KEY_BITS_RESERVED; + debug("Forcing server key to %d bits to make it differ from host key.", + options.server_key_bits); + } + + /* Initialize memory allocation so that any freed MP_INT data will be + zeroed. */ + rsa_set_mp_memory_allocation(); + + /* Do not display messages to stdout in RSA code. */ + rsa_set_verbose(0); + + /* Initialize the random number generator. */ + debug("Initializing random number generator; seed file %.200s", + options.random_seed_file); + random_initialize(&sensitive_data.random_state, options.random_seed_file); + + /* Chdir to the root directory so that the current disk can be unmounted + if desired. */ + chdir("/"); + + /* Close connection cleanly after attack. */ + cipher_attack_detected = packet_disconnect; + + /* Start listening for a socket, unless started from inetd. */ + if (inetd_flag) + { + int s1, s2; + s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */ + s2 = dup(s1); + sock_in = dup(0); + sock_out = dup(1); + /* We intentionally do not close the descriptors 0, 1, and 2 as our + code for setting the descriptors won\'t work if ttyfd happens to + be one of those. */ + debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); + + /* Generate an rsa key. */ + log("Generating %d bit RSA key.", options.server_key_bits); + rsa_generate_key(&sensitive_data.private_key, &public_key, + &sensitive_data.random_state, + options.server_key_bits); + random_stir(&sensitive_data.random_state); + random_save(&sensitive_data.random_state, options.random_seed_file); + log("RSA key generation complete."); + } + else + { + /* Create socket for listening. */ + listen_sock = socket(AF_INET, SOCK_STREAM, 0); + if (listen_sock < 0) + fatal("socket: %.100s", strerror(errno)); + + /* Set socket options. We try to make the port reusable and have it + close as fast as possible without waiting in unnecessary wait states + on close. */ + setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, + sizeof(on)); +#ifdef SO_LINGER + linger.l_onoff = 1; + linger.l_linger = 5; + setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (void *)&linger, + sizeof(linger)); +#endif /* SO_LINGER */ + + /* Initialize the socket address. */ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr = options.listen_addr; + sin.sin_port = htons(options.port); + + /* Bind the socket to the desired port. */ + if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) + { + error("bind: %.100s", strerror(errno)); + shutdown(listen_sock, 2); + close(listen_sock); + fatal("Bind to port %d failed.", options.port); + } + + if (!debug_flag) + { + /* Record our pid in /etc/sshd_pid to make it easier to kill the + correct sshd. We don\'t want to do this before the bind above + because the bind will fail if there already is a daemon, and this + will overwrite any old pid in the file. */ + f = fopen(SSH_DAEMON_PID_FILE, "w"); + if (f) + { + fprintf(f, "%u\n", (unsigned int)getpid()); + fclose(f); + } + } + + /* Start listening on the port. */ + log("Server listening on port %d.", options.port); + if (listen(listen_sock, 5) < 0) + fatal("listen: %.100s", strerror(errno)); + + /* Generate an rsa key. */ + log("Generating %d bit RSA key.", options.server_key_bits); + rsa_generate_key(&sensitive_data.private_key, &public_key, + &sensitive_data.random_state, + options.server_key_bits); + random_stir(&sensitive_data.random_state); + random_save(&sensitive_data.random_state, options.random_seed_file); + log("RSA key generation complete."); + + /* Schedule server key regeneration alarm. */ + signal(SIGALRM, key_regeneration_alarm); + alarm(options.key_regeneration_time); + + /* Arrange to restart on SIGHUP. The handler needs listen_sock. */ + signal(SIGHUP, sighup_handler); + signal(SIGTERM, sigterm_handler); + signal(SIGQUIT, sigterm_handler); + + /* Arrange SIGCHLD to be caught. */ + signal(SIGCHLD, main_sigchld_handler); + + /* Stay listening for connections until the system crashes or the + daemon is killed with a signal. */ + for (;;) + { + if (received_sighup) + sighup_restart(); + /* Wait in accept until there is a connection. */ + aux = sizeof(sin); + newsock = accept(listen_sock, (struct sockaddr *)&sin, &aux); + if (received_sighup) + sighup_restart(); + if (newsock < 0) + { + if (errno == EINTR) + continue; + error("accept: %.100s", strerror(errno)); + continue; + } + +#ifdef LIBWRAP + { + struct request_info req; + request_init(&req, RQ_DAEMON, av0, RQ_FILE, newsock, NULL); + fromhost(&req); + if (!hosts_access(&req)) + { + error("Connection from %.500s refused by tcp_wrappers.", + eval_client(&req)); + shutdown(newsock, 2); + close(newsock); + continue; + } + /* if from inet: refuse(&req); */ + log("connect from %.500s", eval_client(&req)); + } +#endif /* LIBWRAP */ + + /* Got connection. Fork a child to handle it, unless we are in + debugging mode. */ + if (debug_flag) + { + /* In debugging mode. Close the listening socket, and start + processing the connection without forking. */ + debug("Server will not fork when running in debugging mode."); + close(listen_sock); + sock_in = newsock; + sock_out = newsock; + pid = getpid(); + break; + } + else + { + /* Normal production daemon. Fork, and have the child process + the connection. The parent continues listening. */ + if ((pid = fork()) == 0) + { + /* Child. Close the listening socket, and start using + the accepted socket. Reinitialize logging (since our + pid has changed). We break out of the loop to handle + the connection. */ + close(listen_sock); + sock_in = newsock; + sock_out = newsock; + log_init(av0, debug_flag && !inetd_flag, + options.fascist_logging || debug_flag, + options.quiet_mode, options.log_facility); + break; + } + } + + /* Parent. Stay in the loop. */ + if (pid < 0) + error("fork: %.100s", strerror(errno)); + else + debug("Forked child %d.", pid); + + /* Mark that the key has been used (it was "given" to the child). */ + key_used = 1; + + /* Close the new socket (the child is now taking care of it). */ + close(newsock); + } + } + + /* This is the child processing a new connection. */ + + /* Disable the key regeneration alarm. We will not regenerate the key + since we are no longer in a position to give it to anyone. We will + not restart on SIGHUP since it no longer makes sense. */ + alarm(0); + signal(SIGALRM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + + /* Set socket options for the connection. We want the socket to close + as fast as possible without waiting for anything. If the connection + is not a socket, these will do nothing. */ + /* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ +#ifdef SO_LINGER + linger.l_onoff = 1; + linger.l_linger = 5; + setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); +#endif /* SO_LINGER */ + + /* Register our connection. This turns encryption off because we do not + have a key. */ + packet_set_connection(sock_in, sock_out, &sensitive_data.random_state); + + /* Log the connection. */ + log("Connection from %.100s port %d", + get_remote_ipaddr(), get_remote_port()); + + /* Check whether logins are denied from this host. */ + if (options.num_deny_hosts > 0) + { + const char *hostname = get_canonical_hostname(); + const char *ipaddr = get_remote_ipaddr(); + int i; + for (i = 0; i < options.num_deny_hosts; i++) + if (match_pattern(hostname, options.deny_hosts[i]) || + match_pattern(ipaddr, options.deny_hosts[i])) + { + log("Connection from %.200s denied.\n", hostname); + hostname = "You are not allowed to connect. Go away!\r\n"; + write(sock_out, hostname, strlen(hostname)); + close(sock_in); + close(sock_out); + exit(0); + } + } + + /* We don\'t want to listen forever unless the other side successfully + authenticates itself. So we set up an alarm which is cleared after + successful authentication. A limit of zero indicates no limit. + Note that we don\'t set the alarm in debugging mode; it is just annoying + to have the server exit just when you are about to discover the bug. */ + signal(SIGALRM, grace_alarm_handler); + if (!debug_flag) + alarm(options.login_grace_time); + + /* Send our protocol version identification. */ + sprintf(buf, "SSH-%d.%d-%.100s\n", + PROTOCOL_MAJOR, PROTOCOL_MINOR, SSH_VERSION); + if (write(sock_out, buf, strlen(buf)) != strlen(buf)) + fatal("Could not write ident string."); + + /* Read other side\'s version identification. */ + for (i = 0; i < sizeof(buf) - 1; i++) + { + if (read(sock_in, &buf[i], 1) != 1) + fatal("Did not receive ident string."); + if (buf[i] == '\r') + { + buf[i] = '\n'; + buf[i + 1] = 0; + break; + } + if (buf[i] == '\n') + { + /* buf[i] == '\n' */ + buf[i + 1] = 0; + break; + } + } + buf[sizeof(buf) - 1] = 0; + + /* Check that the versions match. In future this might accept several + versions and set appropriate flags to handle them. */ + if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, + remote_version) != 3) + { + const char *s = "Protocol mismatch.\n"; + (void) write(sock_out, s, strlen(s)); + close(sock_in); + close(sock_out); + fatal("Bad protocol version identification: %.100s", buf); + } + debug("Client protocol version %d.%d; client software version %.100s", + remote_major, remote_minor, remote_version); + if (remote_major != PROTOCOL_MAJOR) + { + const char *s = "Protocol major versions differ.\n"; + (void) write(sock_out, s, strlen(s)); + close(sock_in); + close(sock_out); + fatal("Protocol major versions differ: %d vs. %d", + PROTOCOL_MAJOR, remote_major); + } + + /* Check that the client has sufficiently high software version. */ + if (remote_major == 1 && remote_minor == 0) + packet_disconnect("Your ssh version is too old and is no longer supported. Please install a newer version."); + + /* Check whether logins are permitted from this host. */ + if (options.num_allow_hosts > 0) + { + const char *hostname = get_canonical_hostname(); + const char *ipaddr = get_remote_ipaddr(); + int i; + for (i = 0; i < options.num_allow_hosts; i++) + if (match_pattern(hostname, options.allow_hosts[i]) || + match_pattern(ipaddr, options.allow_hosts[i])) + break; + if (i >= options.num_allow_hosts) + { + log("Connection from %.200s not allowed.\n", hostname); + packet_disconnect("Sorry, you are not allowed to connect."); + /*NOTREACHED*/ + } + } + + packet_set_nonblocking(); + + /* Handle the connection. We pass as argument whether the connection + came from a privileged port. */ + do_connection(get_remote_port() < 1024); + +#ifdef KRB4 + /* Cleanup user's ticket cache file. */ + if (options.kerberos_ticket_cleanup) + (void) dest_tkt(); +#endif /* KRB4 */ + + /* Cleanup user's local Xauthority file. */ + if (xauthfile) unlink(xauthfile); + + /* The connection has been terminated. */ + log("Closing connection to %.100s", inet_ntoa(sin.sin_addr)); + packet_close(); + exit(0); +} + +/* Process an incoming connection. Protocol version identifiers have already + been exchanged. This sends server key and performs the key exchange. + Server and host keys will no longer be needed after this functions. */ + +void do_connection(int privileged_port) +{ + int i; + MP_INT session_key_int; + unsigned char session_key[SSH_SESSION_KEY_LENGTH]; + unsigned char check_bytes[8]; + char *user; + unsigned int cipher_type, auth_mask, protocol_flags; + int plen, slen; + + /* Generate check bytes that the client must send back in the user packet + in order for it to be accepted; this is used to defy ip spoofing + attacks. Note that this only works against somebody doing IP spoofing + from a remote machine; any machine on the local network can still see + outgoing packets and catch the random cookie. This only affects + rhosts authentication, and this is one of the reasons why it is + inherently insecure. */ + for (i = 0; i < 8; i++) + check_bytes[i] = random_get_byte(&sensitive_data.random_state); + + /* Send our public key. We include in the packet 64 bits of random + data that must be matched in the reply in order to prevent IP spoofing. */ + packet_start(SSH_SMSG_PUBLIC_KEY); + for (i = 0; i < 8; i++) + packet_put_char(check_bytes[i]); + + /* Store our public server RSA key. */ + packet_put_int(public_key.bits); + packet_put_mp_int(&public_key.e); + packet_put_mp_int(&public_key.n); + + /* Store our public host RSA key. */ + packet_put_int(sensitive_data.host_key.bits); + packet_put_mp_int(&sensitive_data.host_key.e); + packet_put_mp_int(&sensitive_data.host_key.n); + + /* Put protocol flags. */ + packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); + + /* Declare which ciphers we support. */ + packet_put_int(cipher_mask()); + + /* Declare supported authentication types. */ + auth_mask = 0; + if (options.rhosts_authentication) + auth_mask |= 1 << SSH_AUTH_RHOSTS; + if (options.rhosts_rsa_authentication) + auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA; + if (options.rsa_authentication) + auth_mask |= 1 << SSH_AUTH_RSA; +#ifdef KRB4 + if (options.kerberos_authentication && (access(KEYFILE, R_OK) == 0)) + auth_mask |= 1 << SSH_AUTH_KERBEROS; +#endif +#ifdef KERBEROS_TGT_PASSING + if (options.kerberos_tgt_passing) + auth_mask |= 1 << SSH_PASS_KERBEROS_TGT; +#endif +#ifdef AFS + if (options.afs_token_passing && k_hasafs()) + auth_mask |= 1 << SSH_PASS_AFS_TOKEN; +#endif + if (options.password_authentication) + auth_mask |= 1 << SSH_AUTH_PASSWORD; + packet_put_int(auth_mask); + + /* Send the packet and wait for it to be sent. */ + packet_send(); + packet_write_wait(); + + debug("Sent %d bit public key and %d bit host key.", + public_key.bits, sensitive_data.host_key.bits); + + /* Read clients reply (cipher type and session key). */ + packet_read_expect(&plen, SSH_CMSG_SESSION_KEY); + + /* Get cipher type. */ + cipher_type = packet_get_char(); + + /* Get check bytes from the packet. These must match those we sent earlier + with the public key packet. */ + for (i = 0; i < 8; i++) + if (check_bytes[i] != packet_get_char()) + packet_disconnect("IP Spoofing check bytes do not match."); + + debug("Encryption type: %.200s", cipher_name(cipher_type)); + + /* Get the encrypted integer. */ + mpz_init(&session_key_int); + packet_get_mp_int(&session_key_int, &slen); + + /* Get protocol flags. */ + protocol_flags = packet_get_int(); + packet_set_protocol_flags(protocol_flags); + + packet_integrity_check(plen, 1 + 8 + slen + 4, SSH_CMSG_SESSION_KEY); + + /* Decrypt it using our private server key and private host key (key with + larger modulus first). */ + if (mpz_cmp(&sensitive_data.private_key.n, &sensitive_data.host_key.n) > 0) + { + /* Private key has bigger modulus. */ + assert(sensitive_data.private_key.bits >= + sensitive_data.host_key.bits + SSH_KEY_BITS_RESERVED); + rsa_private_decrypt(&session_key_int, &session_key_int, + &sensitive_data.private_key); + rsa_private_decrypt(&session_key_int, &session_key_int, + &sensitive_data.host_key); + } + else + { + /* Host key has bigger modulus (or they are equal). */ + assert(sensitive_data.host_key.bits >= + sensitive_data.private_key.bits + SSH_KEY_BITS_RESERVED); + rsa_private_decrypt(&session_key_int, &session_key_int, + &sensitive_data.host_key); + rsa_private_decrypt(&session_key_int, &session_key_int, + &sensitive_data.private_key); + } + + /* Compute session id for this session. */ + compute_session_id(session_id, check_bytes, sensitive_data.host_key.bits, + &sensitive_data.host_key.n, + sensitive_data.private_key.bits, + &sensitive_data.private_key.n); + + /* Extract session key from the decrypted integer. The key is in the + least significant 256 bits of the integer; the first byte of the + key is in the highest bits. */ + mp_linearize_msb_first(session_key, sizeof(session_key), + &session_key_int); + + /* Xor the first 16 bytes of the session key with the session id. */ + for (i = 0; i < 16; i++) + session_key[i] ^= session_id[i]; + + /* Destroy the decrypted integer. It is no longer needed. */ + mpz_clear(&session_key_int); + + /* Set the session key. From this on all communications will be + encrypted. */ + packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, + cipher_type, 0); + + /* Destroy our copy of the session key. It is no longer needed. */ + memset(session_key, 0, sizeof(session_key)); + + debug("Received session key; encryption turned on."); + + /* Send an acknowledgement packet. Note that this packet is sent + encrypted. */ + packet_start(SSH_SMSG_SUCCESS); + packet_send(); + packet_write_wait(); + + /* Get the name of the user that we wish to log in as. */ + packet_read_expect(&plen, SSH_CMSG_USER); + + /* Get the user name. */ + { + int ulen; + user = packet_get_string(&ulen); + packet_integrity_check(plen, (4 + ulen), SSH_CMSG_USER); + } + + /* Destroy the private and public keys. They will no longer be needed. */ + rsa_clear_public_key(&public_key); + rsa_clear_private_key(&sensitive_data.private_key); + rsa_clear_private_key(&sensitive_data.host_key); + + /* Do the authentication. */ + do_authentication(user, privileged_port); +} + +/* Performs authentication of an incoming connection. Session key has already + been exchanged and encryption is enabled. User is the user name to log + in as (received from the clinet). Privileged_port is true if the + connection comes from a privileged port (used for .rhosts authentication).*/ + +void do_authentication(char *user, int privileged_port) +{ + int type; + int authenticated = 0; + char *password; + struct passwd *pw, pwcopy; + char *client_user; + unsigned int client_host_key_bits; + MP_INT client_host_key_e, client_host_key_n; + +#ifdef AFS + /* If machine has AFS, set process authentication group. */ + if (k_hasafs()) { + k_setpag(); + k_unlog(); + } +#endif /* AFS */ + + /* Verify that the user is a valid user. */ + pw = getpwnam(user); + if (!pw) + { + /* The user does not exist. */ + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + + /* Keep reading packets, and always respond with a failure. This is to + avoid disclosing whether such a user really exists. */ + for (;;) + { + /* Read a packet. This will not return if the client disconnects. */ + int plen; + (void) packet_read(&plen); + + /* Send failure. This should be indistinguishable from a failed + authentication. */ + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + } + /*NOTREACHED*/ + abort(); + } + + /* Take a copy of the returned structure. */ + memset(&pwcopy, 0, sizeof(pwcopy)); + pwcopy.pw_name = xstrdup(pw->pw_name); + pwcopy.pw_passwd = xstrdup(pw->pw_passwd); + pwcopy.pw_uid = pw->pw_uid; + pwcopy.pw_gid = pw->pw_gid; + pwcopy.pw_dir = xstrdup(pw->pw_dir); + pwcopy.pw_shell = xstrdup(pw->pw_shell); + pw = &pwcopy; + + /* If we are not running as root, the user must have the same uid as the + server. */ + if (getuid() != 0 && pw->pw_uid != getuid()) + packet_disconnect("Cannot change user when server not running as root."); + + debug("Attempting authentication for %.100s.", user); + + /* If the user has no password, accept authentication immediately. */ + if (options.password_authentication && +#ifdef KRB4 + options.kerberos_or_local_passwd && +#endif /* KRB4 */ + auth_password(user, "")) + { + /* Authentication with empty password succeeded. */ + debug("Login for user %.100s accepted without authentication.", user); + /* authentication_type = SSH_AUTH_PASSWORD; */ + authenticated = 1; + /* Success packet will be sent after loop below. */ + } + else + { + /* Indicate that authentication is needed. */ + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + } + + /* Loop until the user has been authenticated or the connection is closed. */ + while (!authenticated) + { + int plen; + /* Get a packet from the client. */ + type = packet_read(&plen); + + /* Process the packet. */ + switch (type) + { + +#ifdef KERBEROS_TGT_PASSING + case SSH_CMSG_HAVE_KERBEROS_TGT: + if (!options.kerberos_tgt_passing) + { + log("Kerberos tgt passing disabled."); + break; + } + /* Accept Kerberos tgt. */ + { + int dlen; + char *data = packet_get_string(&dlen); + packet_integrity_check(plen, 4 + dlen, type); + if (!auth_kerberos_tgt(pw, data)) + debug("Kerberos tgt REFUSED for %.100s", user); + } + continue; +#endif /* KERBEROS_TGT_PASSING */ + +#ifdef AFS + case SSH_CMSG_HAVE_AFS_TOKEN: + if (!options.afs_token_passing || !k_hasafs()) { + /* packet_get_all(); */ + log("AFS token passing disabled."); + break; + } + else { + /* Accept AFS token. */ + int dlen; + char *token_string = packet_get_string(&dlen); + packet_integrity_check(plen, 4 + dlen, type); + if (!auth_afs_token(user, pw->pw_uid, token_string)) + debug("AFS token REFUSED for %.100s", user); + xfree(token_string); + continue; + } +#endif /* AFS */ + +#ifdef KRB4 + case SSH_CMSG_AUTH_KERBEROS: + if (!options.kerberos_authentication) + { + log("Kerberos authentication disabled."); + break; + } + { + /* Try Kerberos v4 authentication. */ + KTEXT_ST auth; + char *tkt_user = NULL; + char *kdata = packet_get_string((unsigned int *)&auth.length); + packet_integrity_check(plen, 4 + auth.length, type); + + memcpy(auth.dat, kdata, auth.length); + xfree(kdata); + + if (auth_krb4(user, &auth, &tkt_user)) { + /* Client has successfully authenticated to us. */ + log("Kerberos authentication accepted %.100s for account " + "%.100s from %.200s", tkt_user, user, + get_canonical_hostname()); + /* authentication_type = SSH_AUTH_KERBEROS; */ + authenticated = 1; + xfree(tkt_user); + break; + } + log("Kerberos authentication failed for account " + "%.100s from %.200s", user, get_canonical_hostname()); + } + break; +#endif /* KRB4 */ + + case SSH_CMSG_AUTH_RHOSTS: + if (!options.rhosts_authentication) + { + log("Rhosts authentication disabled."); + break; + } + + /* Rhosts authentication (also uses /etc/hosts.equiv). */ + if (!privileged_port) + { + log("Rhosts authentication not available for connections from unprivileged port."); + break; + } + + /* Get client user name. Note that we just have to trust the client; + this is one reason why rhosts authentication is insecure. + (Another is IP-spoofing on a local network.) */ + { + int dlen; + client_user = packet_get_string(&dlen); + packet_integrity_check(plen, 4 + dlen, type); + } + + /* Try to authenticate using /etc/hosts.equiv and .rhosts. */ + if (auth_rhosts(pw, client_user, options.ignore_rhosts, + options.strict_modes)) + { + /* Authentication accepted. */ + log("Rhosts authentication accepted for %.100s, remote %.100s on %.700s.", + user, client_user, get_canonical_hostname()); + authenticated = 1; + xfree(client_user); + break; + } + debug("Rhosts authentication failed for %.100s, remote %.100s.", + user, client_user); + xfree(client_user); + break; + + case SSH_CMSG_AUTH_RHOSTS_RSA: + if (!options.rhosts_rsa_authentication) + { + log("Rhosts with RSA authentication disabled."); + break; + } + + /* Rhosts authentication (also uses /etc/hosts.equiv) with RSA + host authentication. */ + if (!privileged_port) + { + log("Rhosts authentication not available for connections from unprivileged port."); + break; + } + + { + int ulen, elen, nlen; + /* Get client user name. Note that we just have to trust + the client; root on the client machine can claim to be + any user. */ + client_user = packet_get_string(&ulen); + + /* Get the client host key. */ + mpz_init(&client_host_key_e); + mpz_init(&client_host_key_n); + client_host_key_bits = packet_get_int(); + packet_get_mp_int(&client_host_key_e, &elen); + packet_get_mp_int(&client_host_key_n, &nlen); + + packet_integrity_check(plen, (4 + ulen) + 4 + elen + nlen, type); + } + + /* Try to authenticate using /etc/hosts.equiv and .rhosts. */ + if (auth_rhosts_rsa(&sensitive_data.random_state, + pw, client_user, + client_host_key_bits, &client_host_key_e, + &client_host_key_n, options.ignore_rhosts, + options.strict_modes)) + { + /* Authentication accepted. */ + authenticated = 1; + xfree(client_user); + mpz_clear(&client_host_key_e); + mpz_clear(&client_host_key_n); + break; + } + debug("Rhosts authentication failed for %.100s, remote %.100s.", + user, client_user); + xfree(client_user); + mpz_clear(&client_host_key_e); + mpz_clear(&client_host_key_n); + break; + + case SSH_CMSG_AUTH_RSA: + if (!options.rsa_authentication) + { + log("RSA authentication disabled."); + break; + } + + /* RSA authentication requested. */ + { + int nlen; + MP_INT n; + mpz_init(&n); + packet_get_mp_int(&n, &nlen); + + packet_integrity_check(plen, nlen, type); + + if (auth_rsa(pw, &n, &sensitive_data.random_state)) + { + /* Successful authentication. */ + mpz_clear(&n); + log("RSA authentication for %.100s accepted.", user); + authenticated = 1; + break; + } + mpz_clear(&n); + debug("RSA authentication for %.100s failed.", user); + } + break; + + case SSH_CMSG_AUTH_PASSWORD: + if (!options.password_authentication) + { + log("Password authentication disabled."); + break; + } + + /* Password authentication requested. */ + /* Read user password. It is in plain text, but was transmitted + over the encrypted channel so it is not visible to an outside + observer. */ + { + int passw_len; + password = packet_get_string(&passw_len); + packet_integrity_check(plen, 4 + passw_len, type); + } + + /* Try authentication with the password. */ + if (auth_password(user, password)) + { + /* Successful authentication. */ + /* Clear the password from memory. */ + memset(password, 0, strlen(password)); + xfree(password); + log("Password authentication for %.100s accepted.", user); + authenticated = 1; + break; + } + debug("Password authentication for %.100s failed.", user); + memset(password, 0, strlen(password)); + xfree(password); + break; + + default: + /* Any unknown messages will be ignored (and failure returned) + during authentication. */ + log("Unknown message during authentication: type %d", type); + break; /* Respond with a failure message. */ + } + /* If successfully authenticated, break out of loop. */ + if (authenticated) + break; + + /* Send a message indicating that the authentication attempt failed. */ + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + } + + /* Check if the user is logging in as root and root logins are disallowed. */ + if (pw->pw_uid == 0 && !options.permit_root_login) + { + if (forced_command) + log("Root login accepted for forced command.", forced_command); + else + packet_disconnect("ROOT LOGIN REFUSED FROM %.200s", + get_canonical_hostname()); + } + + /* The user has been authenticated and accepted. */ + packet_start(SSH_SMSG_SUCCESS); + packet_send(); + packet_write_wait(); + + /* Perform session preparation. */ + do_authenticated(pw); +} + +/* Prepares for an interactive session. This is called after the user has + been successfully authenticated. During this message exchange, pseudo + terminals are allocated, X11, TCP/IP, and authentication agent forwardings + are requested, etc. */ + +void do_authenticated(struct passwd *pw) +{ + int type; +#ifdef WITH_ZLIB + int compression_level = 0, enable_compression_after_reply = 0; +#endif /* WITH_ZLIB */ + int have_pty = 0, ptyfd = -1, ttyfd = -1; + int row, col, xpixel, ypixel, screen; + char ttyname[64]; + char *command, *term = NULL, *display = NULL, *proto = NULL, *data = NULL; + struct group *grp; + gid_t tty_gid; + mode_t tty_mode; + int n_bytes; + + /* Cancel the alarm we set to limit the time taken for authentication. */ + alarm(0); + + /* Inform the channel mechanism that we are the server side and that + the client may request to connect to any port at all. (The user could + do it anyway, and we wouldn\'t know what is permitted except by the + client telling us, so we can equally well trust the client not to request + anything bogus.) */ + channel_permit_all_opens(); + + /* We stay in this loop until the client requests to execute a shell or a + command. */ + while (1) + { + int plen, dlen; + + /* Get a packet from the client. */ + type = packet_read(&plen); + + /* Process the packet. */ + switch (type) + { +#ifdef WITH_ZLIB + case SSH_CMSG_REQUEST_COMPRESSION: + packet_integrity_check(plen, 4, type); + compression_level = packet_get_int(); + if (compression_level < 1 || compression_level > 9) + { + packet_send_debug("Received illegal compression level %d.", + compression_level); + goto fail; + } + /* Enable compression after we have responded with SUCCESS. */ + enable_compression_after_reply = 1; + break; +#endif /* WITH_ZLIB */ + + case SSH_CMSG_REQUEST_PTY: + if (no_pty_flag) + { + debug("Allocating a pty not permitted for this authentication."); + goto fail; + } + if (have_pty) + packet_disconnect("Protocol error: you already have a pty."); + + debug("Allocating pty."); + + /* Allocate a pty and open it. */ + if (!pty_allocate(&ptyfd, &ttyfd, ttyname)) + { + error("Failed to allocate pty."); + goto fail; + } + + /* Determine the group to make the owner of the tty. */ +#ifdef TTY_GROUP + grp = getgrnam(TTY_GROUP); +#else /* TTY_GROUP */ + grp = getgrnam("tty"); +#endif /* TTY_GROUP */ + if (grp) + { + tty_gid = grp->gr_gid; + tty_mode = S_IRUSR|S_IWUSR|S_IWGRP; + } + else + { + tty_gid = pw->pw_gid; + tty_mode = S_IRUSR|S_IWUSR|S_IWGRP|S_IWOTH; + } + + /* Change ownership of the tty. */ + if (chown(ttyname, pw->pw_uid, tty_gid) < 0) + fatal("chown(%.100s, %d, %d) failed: %.100s", + ttyname, pw->pw_uid, tty_gid, strerror(errno)); + if (chmod(ttyname, tty_mode) < 0) + fatal("chmod(%.100s, 0%o) failed: %.100s", + ttyname, tty_mode, strerror(errno)); + + /* Get TERM from the packet. Note that the value may be of arbitrary + length. */ + + term = packet_get_string(&dlen); + packet_integrity_check(dlen, strlen(term), type); + /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */ + /* Remaining bytes */ + n_bytes = plen - (4 + dlen + 4*4); + + if (strcmp(term, "") == 0) + term = NULL; + + /* Get window size from the packet. */ + row = packet_get_int(); + col = packet_get_int(); + xpixel = packet_get_int(); + ypixel = packet_get_int(); + pty_change_window_size(ptyfd, row, col, xpixel, ypixel); + + /* Get tty modes from the packet. */ + tty_parse_modes(ttyfd, &n_bytes); + packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); + + /* Indicate that we now have a pty. */ + have_pty = 1; + break; + + case SSH_CMSG_X11_REQUEST_FORWARDING: + if (!options.x11_forwarding) + { + packet_send_debug("X11 forwarding disabled in server configuration file."); + goto fail; + } +#ifdef XAUTH_PATH + if (no_x11_forwarding_flag) + { + packet_send_debug("X11 forwarding not permitted for this authentication."); + goto fail; + } + debug("Received request for X11 forwarding with auth spoofing."); + if (display) + packet_disconnect("Protocol error: X11 display already set."); + { + int proto_len, data_len; + proto = packet_get_string(&proto_len); + data = packet_get_string(&data_len); + packet_integrity_check(plen, 4+proto_len + 4+data_len + 4, type); + } + if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER) + screen = packet_get_int(); + else + screen = 0; + display = x11_create_display_inet(screen); + if (!display) + goto fail; + + /* Setup to always have a local .Xauthority. */ + xauthfile = xmalloc(MAXPATHLEN); + sprintf(xauthfile, "/tmp/Xauth%d_%d", pw->pw_uid, getpid()); + + break; +#else /* XAUTH_PATH */ + /* No xauth program; we won't accept forwarding with spoofing. */ + packet_send_debug("No xauth program; cannot forward with spoofing."); + goto fail; +#endif /* XAUTH_PATH */ + + case SSH_CMSG_AGENT_REQUEST_FORWARDING: + if (no_agent_forwarding_flag) + { + debug("Authentication agent forwarding not permitted for this authentication."); + goto fail; + } + debug("Received authentication agent forwarding request."); + auth_input_request_forwarding(pw); + break; + + case SSH_CMSG_PORT_FORWARD_REQUEST: + if (no_port_forwarding_flag) + { + debug("Port forwarding not permitted for this authentication."); + goto fail; + } + debug("Received TCP/IP port forwarding request."); + channel_input_port_forward_request(pw->pw_uid == 0); + break; + + case SSH_CMSG_EXEC_SHELL: + /* Set interactive/non-interactive mode. */ + packet_set_interactive(have_pty || display != NULL, + options.keepalives); + + if (forced_command != NULL) + goto do_forced_command; + debug("Forking shell."); + packet_integrity_check(plen, 0, type); + if (have_pty) + do_exec_pty(NULL, ptyfd, ttyfd, ttyname, pw, term, display, proto, + data); + else + do_exec_no_pty(NULL, pw, display, proto, data); + return; + + case SSH_CMSG_EXEC_CMD: + /* Set interactive/non-interactive mode. */ + packet_set_interactive(have_pty || display != NULL, + options.keepalives); + + if (forced_command != NULL) + goto do_forced_command; + /* Get command from the packet. */ + { + int dlen; + command = packet_get_string(&dlen); + debug("Executing command '%.500s'", command); + packet_integrity_check(plen, 4 + dlen, type); + } + if (have_pty) + do_exec_pty(command, ptyfd, ttyfd, ttyname, pw, term, display, + proto, data); + else + do_exec_no_pty(command, pw, display, proto, data); + xfree(command); + return; + + default: + /* Any unknown messages in this phase are ignored, and a failure + message is returned. */ + log("Unknown packet type received after authentication: %d", type); + goto fail; + } + + /* The request was successfully processed. */ + packet_start(SSH_SMSG_SUCCESS); + packet_send(); + packet_write_wait(); + +#ifdef WITH_ZLIB + /* Enable compression now that we have replied if appropriate. */ + if (enable_compression_after_reply) + { + enable_compression_after_reply = 0; + packet_start_compression(compression_level); + } +#endif /* WITH_ZLIB */ + + continue; + + fail: + /* The request failed. */ + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + continue; + + do_forced_command: + /* There is a forced command specified for this login. Execute it. */ + debug("Executing forced command: %.900s", forced_command); + if (have_pty) + do_exec_pty(forced_command, ptyfd, ttyfd, ttyname, pw, term, display, + proto, data); + else + do_exec_no_pty(forced_command, pw, display, proto, data); + return; + } +} + +/* This is called to fork and execute a command when we have no tty. This + will call do_child from the child, and server_loop from the parent after + setting up file descriptors and such. */ + +void do_exec_no_pty(const char *command, struct passwd *pw, + const char *display, const char *auth_proto, + const char *auth_data) +{ + int pid; + +#ifdef USE_PIPES + int pin[2], pout[2], perr[2]; + /* Allocate pipes for communicating with the program. */ + if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) + packet_disconnect("Could not create pipes: %.100s", + strerror(errno)); +#else /* USE_PIPES */ + int inout[2], err[2]; + /* Uses socket pairs to communicate with the program. */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || + socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) + packet_disconnect("Could not create socket pairs: %.100s", + strerror(errno)); +#endif /* USE_PIPES */ + + /* Fork the child. */ + if ((pid = fork()) == 0) + { + /* Child. Reinitialize the log since the pid has changed. */ + log_init(av0, debug_flag && !inetd_flag, debug_flag, + options.quiet_mode, options.log_facility); + +#ifdef USE_PIPES + /* Redirect stdin. We close the parent side of the socket pair, + and make the child side the standard input. */ + close(pin[1]); + if (dup2(pin[0], 0) < 0) + perror("dup2 stdin"); + close(pin[0]); + + /* Redirect stdout. */ + close(pout[0]); + if (dup2(pout[1], 1) < 0) + perror("dup2 stdout"); + close(pout[1]); + + /* Redirect stderr. */ + close(perr[0]); + if (dup2(perr[1], 2) < 0) + perror("dup2 stderr"); + close(perr[1]); +#else /* USE_PIPES */ + /* Redirect stdin, stdout, and stderr. Stdin and stdout will use the + same socket, as some programs (particularly rdist) seem to depend + on it. */ + close(inout[1]); + close(err[1]); + if (dup2(inout[0], 0) < 0) /* stdin */ + perror("dup2 stdin"); + if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ + perror("dup2 stdout"); + if (dup2(err[0], 2) < 0) /* stderr */ + perror("dup2 stderr"); +#endif /* USE_PIPES */ + + /* Do processing for the child (exec command etc). */ + do_child(command, pw, NULL, display, auth_proto, auth_data, NULL); + /*NOTREACHED*/ + } + if (pid < 0) + packet_disconnect("fork failed: %.100s", strerror(errno)); +#ifdef USE_PIPES + /* We are the parent. Close the child sides of the pipes. */ + close(pin[0]); + close(pout[1]); + close(perr[1]); + + /* Enter the interactive session. */ + server_loop(pid, pin[1], pout[0], perr[0]); + /* server_loop has closed pin[1], pout[1], and perr[1]. */ +#else /* USE_PIPES */ + /* We are the parent. Close the child sides of the socket pairs. */ + close(inout[0]); + close(err[0]); + + /* Enter the interactive session. Note: server_loop must be able to handle + the case that fdin and fdout are the same. */ + server_loop(pid, inout[1], inout[1], err[1]); + /* server_loop has closed inout[1] and err[1]. */ +#endif /* USE_PIPES */ +} + +struct pty_cleanup_context +{ + const char *ttyname; + int pid; +}; + +/* Function to perform cleanup if we get aborted abnormally (e.g., due to a + dropped connection). */ + +void pty_cleanup_proc(void *context) +{ + struct pty_cleanup_context *cu = context; + + debug("pty_cleanup_proc called"); + +#if defined(KRB4) || defined(AFS) + /* Destroy user's ticket cache file. */ + (void) dest_tkt(); +#endif /* KRB4 || AFS */ + + /* Record that the user has logged out. */ + record_logout(cu->pid, cu->ttyname); + + /* Release the pseudo-tty. */ + pty_release(cu->ttyname); +} + +/* This is called to fork and execute a command when we have a tty. This + will call do_child from the child, and server_loop from the parent after + setting up file descriptors, controlling tty, updating wtmp, utmp, + lastlog, and other such operations. */ + +void do_exec_pty(const char *command, int ptyfd, int ttyfd, + const char *ttyname, struct passwd *pw, const char *term, + const char *display, const char *auth_proto, + const char *auth_data) +{ + int pid, fdout; + const char *hostname; + time_t last_login_time; + char buf[100], *time_string; + FILE *f; + char line[256]; + struct stat st; + int quiet_login; + struct sockaddr_in from; + int fromlen; + struct pty_cleanup_context cleanup_context; + + /* Get remote host name. */ + hostname = get_canonical_hostname(); + + /* Get the time when the user last logged in. Buf will be set to contain + the hostname the last login was from. */ + last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, + buf, sizeof(buf)); + + /* Fork the child. */ + if ((pid = fork()) == 0) + { + pid = getpid(); + + /* Child. Reinitialize the log because the pid has changed. */ + log_init(av0, debug_flag && !inetd_flag, debug_flag, options.quiet_mode, + options.log_facility); + + /* Close the master side of the pseudo tty. */ + close(ptyfd); + + /* Make the pseudo tty our controlling tty. */ + pty_make_controlling_tty(&ttyfd, ttyname); + + /* Redirect stdin from the pseudo tty. */ + if (dup2(ttyfd, fileno(stdin)) < 0) + error("dup2 stdin failed: %.100s", strerror(errno)); + + /* Redirect stdout to the pseudo tty. */ + if (dup2(ttyfd, fileno(stdout)) < 0) + error("dup2 stdin failed: %.100s", strerror(errno)); + + /* Redirect stderr to the pseudo tty. */ + if (dup2(ttyfd, fileno(stderr)) < 0) + error("dup2 stdin failed: %.100s", strerror(errno)); + + /* Close the extra descriptor for the pseudo tty. */ + close(ttyfd); + + /* Get IP address of client. This is needed because we want to record + where the user logged in from. If the connection is not a socket, + let the ip address be 0.0.0.0. */ + memset(&from, 0, sizeof(from)); + if (packet_get_connection_in() == packet_get_connection_out()) + { + fromlen = sizeof(from); + if (getpeername(packet_get_connection_in(), + (struct sockaddr *)&from, &fromlen) < 0) + fatal("getpeername: %.100s", strerror(errno)); + } + + /* Record that there was a login on that terminal. */ + record_login(pid, ttyname, pw->pw_name, pw->pw_uid, hostname, + &from); + + /* Check if .hushlogin exists. */ + sprintf(line, "%.200s/.hushlogin", pw->pw_dir); + quiet_login = stat(line, &st) >= 0; + + /* If the user has logged in before, display the time of last login. + However, don't display anything extra if a command has been + specified (so that ssh can be used to execute commands on a remote + machine without users knowing they are going to another machine). */ + if (command == NULL && last_login_time != 0 && !quiet_login) + { + /* Convert the date to a string. */ + time_string = ctime(&last_login_time); + /* Remove the trailing newline. */ + if (strchr(time_string, '\n')) + *strchr(time_string, '\n') = 0; + /* Display the last login time. Host if displayed if known. */ + if (strcmp(buf, "") == 0) + printf("Last login: %s\r\n", time_string); + else + printf("Last login: %s from %s\r\n", time_string, buf); + } + + /* Print /etc/motd unless a command was specified or printing it was + disabled in server options. Note that some machines appear to + print it in /etc/profile or similar. */ + if (command == NULL && options.print_motd && !quiet_login) + { + /* Print /etc/motd if it exists. */ + f = fopen("/etc/motd", "r"); + if (f) + { + while (fgets(line, sizeof(line), f)) + fputs(line, stdout); + fclose(f); + } + } + + /* Do common processing for the child, such as execing the command. */ + do_child(command, pw, term, display, auth_proto, auth_data, ttyname); + /*NOTREACHED*/ + } + if (pid < 0) + packet_disconnect("fork failed: %.100s", strerror(errno)); + /* Parent. Close the slave side of the pseudo tty. */ + close(ttyfd); + + /* Create another descriptor of the pty master side for use as the standard + input. We could use the original descriptor, but this simplifies code + in server_loop. The descriptor is bidirectional. */ + fdout = dup(ptyfd); + if (fdout < 0) + packet_disconnect("dup failed: %.100s", strerror(errno)); + + /* Add a cleanup function to clear the utmp entry and record logout time + in case we call fatal() (e.g., the connection gets closed). */ + cleanup_context.pid = pid; + cleanup_context.ttyname = ttyname; + fatal_add_cleanup(pty_cleanup_proc, (void *)&cleanup_context); + + /* Enter interactive session. */ + server_loop(pid, ptyfd, fdout, -1); + /* server_loop has not closed ptyfd and fdout. */ + + /* Cancel the cleanup function. */ + fatal_remove_cleanup(pty_cleanup_proc, (void *)&cleanup_context); + + /* Record that the user has logged out. */ + record_logout(pid, ttyname); + + /* Release the pseudo-tty. */ + pty_release(ttyname); + + /* Close the server side of the socket pairs. We must do this after the + pty cleanup, so that another process doesn't get this pty while we're + still cleaning up. */ + close(ptyfd); + close(fdout); +} + +/* Sets the value of the given variable in the environment. If the variable + already exists, its value is overriden. */ + +void child_set_env(char ***envp, unsigned int *envsizep, const char *name, + const char *value) +{ + unsigned int i, namelen; + char **env; + + /* Find the slot where the value should be stored. If the variable already + exists, we reuse the slot; otherwise we append a new slot at the end + of the array, expanding if necessary. */ + env = *envp; + namelen = strlen(name); + for (i = 0; env[i]; i++) + if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') + break; + if (env[i]) + { + /* Name already exists. Reuse the slot. */ + xfree(env[i]); + } + else + { + /* New variable. Expand the array if necessary. */ + if (i >= (*envsizep) - 1) + { + (*envsizep) += 50; + env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *)); + } + + /* Need to set the NULL pointer at end of array beyond the new + slot. */ + env[i + 1] = NULL; + } + + /* Allocate space and format the variable in the appropriate slot. */ + env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1); + sprintf(env[i], "%s=%s", name, value); +} + +/* Reads environment variables from the given file and adds/overrides them + into the environment. If the file does not exist, this does nothing. + Otherwise, it must consist of empty lines, comments (line starts with '#') + and assignments of the form name=value. No other forms are allowed. */ + +void read_environment_file(char ***env, unsigned int *envsize, + const char *filename) +{ + FILE *f; + char buf[4096]; + char *cp, *value; + + /* Open the environment file. */ + f = fopen(filename, "r"); + if (!f) + return; /* Not found. */ + + /* Process each line. */ + while (fgets(buf, sizeof(buf), f)) + { + /* Skip leading whitespace. */ + for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Ignore empty and comment lines. */ + if (!*cp || *cp == '#' || *cp == '\n') + continue; + + /* Remove newline. */ + if (strchr(cp, '\n')) + *strchr(cp, '\n') = '\0'; + + /* Find the equals sign. Its lack indicates badly formatted line. */ + value = strchr(cp, '='); + if (value == NULL) + { + fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf); + continue; + } + + /* Replace the equals sign by nul, and advance value to the value + string. */ + *value = '\0'; + value++; + + /* Set the value in environment. */ + child_set_env(env, envsize, cp, value); + } + + fclose(f); +} + + +#ifdef HAVE_ETC_DEFAULT_LOGIN + +/* Gets the value of the given variable in the environment. If the + variable does not exist, returns NULL. */ + +char *child_get_env(char **env, const char *name) +{ + unsigned int i, namelen; + + namelen = strlen(name); + + for (i = 0; env[i]; i++) + if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=') + break; + if (env[i]) + return &env[i][namelen + 1]; + else + return NULL; +} + +/* Processes /etc/default/login; this involves things like environment + settings, ulimit, etc. This file exists at least on Solaris 2.x. */ + +void read_etc_default_login(char ***env, unsigned int *envsize, + struct passwd *pw) +{ + unsigned int defenvsize; + char **defenv, *def; + int i; + + /* Read /etc/default/login into a separate temporary environment. */ + defenvsize = 10; + defenv = xmalloc(defenvsize * sizeof(char *)); + defenv[0] = NULL; + read_environment_file(&defenv, &defenvsize, "/etc/default/login"); + + /* Set SHELL if ALTSHELL is YES. */ + def = child_get_env(defenv, "ALTSHELL"); + if (def != NULL && strcmp(def, "YES") == 0) + child_set_env(env, envsize, "SHELL", pw->pw_shell); + + /* Set PATH from SUPATH if we are logging in as root, and PATH + otherwise. If neither of these exists, we use the default ssh + path. */ + if (pw->pw_uid == 0) + def = child_get_env(defenv, "SUPATH"); + else + def = child_get_env(defenv, "PATH"); + if (def != NULL) + child_set_env(env, envsize, "PATH", def); + else + child_set_env(env, envsize, "PATH", DEFAULT_PATH); + + /* Set TZ if TIMEZONE is defined and we haven't inherited a value + for TZ. */ + def = getenv("TZ"); + if (def == NULL) + def = child_get_env(defenv, "TIMEZONE"); + if (def != NULL) + child_set_env(env, envsize, "TZ", def); + + /* Set HZ if defined. */ + def = child_get_env(defenv, "HZ"); + if (def != NULL) + child_set_env(env, envsize, "HZ", def); + + /* Set up the default umask if UMASK is defined. */ + def = child_get_env(defenv, "UMASK"); + if (def != NULL) + { + int i, value; + + for (value = i = 0; + def[i] && isdigit(def[i]) && def[i] != '8' && def[i] != '9'; + i++) + value = value * 8 + def[i] - '0'; + + umask(value); + } + + /* Set up the file size ulimit if ULIMIT is set. */ + def = child_get_env(defenv, "ULIMIT"); + if (def != NULL && atoi(def) > 0) + ulimit(UL_SETFSIZE, atoi(def)); + + /* Free the temporary environment. */ + for (i = 0; defenv[i]; i++) + xfree(defenv[i]); + xfree(defenv); +} + +#endif /* HAVE_ETC_DEFAULT_LOGIN */ + +/* Performs common processing for the child, such as setting up the + environment, closing extra file descriptors, setting the user and group + ids, and executing the command or shell. */ + +void do_child(const char *command, struct passwd *pw, const char *term, + const char *display, const char *auth_proto, + const char *auth_data, const char *ttyname) +{ + const char *shell, *cp; + char buf[256]; + FILE *f; + unsigned int envsize, i; + char **env; + extern char **environ; + struct stat st; + char *argv[10]; + + /* Check /etc/nologin. */ + f = fopen("/etc/nologin", "r"); + if (f) + { /* /etc/nologin exists. Print its contents and exit. */ + while (fgets(buf, sizeof(buf), f)) + fputs(buf, stderr); + fclose(f); + if (pw->pw_uid != 0) + exit(254); + } + +#ifdef HAVE_SETLOGIN + /* Set login name in the kernel. */ + setlogin(pw->pw_name); +#endif /* HAVE_SETLOGIN */ + +#ifdef HAVE_USERSEC_H + /* On AIX, this "sets process credentials". I am not sure what this + includes, but it seems to be important. This also does setuid + (but we do it below as well just in case). */ + if (setpcred((char *)pw->pw_name, NULL)) + log("setpcred %.100s: %.100s", strerror(errno)); +#endif /* HAVE_USERSEC_H */ + + /* Set uid, gid, and groups. */ + if (getuid() == 0 || geteuid() == 0) + { + if (setgid(pw->pw_gid) < 0) + { + perror("setgid"); + exit(1); + } +#ifdef HAVE_INITGROUPS + /* Initialize the group list. */ + if (initgroups(pw->pw_name, pw->pw_gid) < 0) + { + perror("initgroups"); + exit(1); + } +#endif /* HAVE_INITGROUPS */ + endgrent(); + +#ifdef HAVE_SETLUID + /* Initialize login UID. */ + if (setluid(user_uid) < 0) + { + perror("setluid"); + exit(1); + } +#endif /* HAVE_SETLUID */ + + /* Permanently switch to the desired uid. */ + permanently_set_uid(pw->pw_uid); + } + + if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) + fatal("Failed to set uids to %d.", (int)pw->pw_uid); + + /* Get the shell from the password data. An empty shell field is legal, + and means /bin/sh. */ + shell = (pw->pw_shell[0] == '\0') ? DEFAULT_SHELL : pw->pw_shell; + +#ifdef AFS + /* Try to get AFS tokens for the local cell. */ + if (k_hasafs()) { + char cell[64]; + + if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) + krb_afslog(cell, 0); + + krb_afslog(0, 0); + } +#endif /* AFS */ + + /* Initialize the environment. In the first part we allocate space for + all environment variables. */ + envsize = 100; + env = xmalloc(envsize * sizeof(char *)); + env[0] = NULL; + + /* Set basic environment. */ + child_set_env(&env, &envsize, "USER", pw->pw_name); + child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); + child_set_env(&env, &envsize, "HOME", pw->pw_dir); + child_set_env(&env, &envsize, "PATH", DEFAULT_PATH); + + /* Let it inherit timezone if we have one. */ + if (getenv("TZ")) + child_set_env(&env, &envsize, "TZ", getenv("TZ")); + +#ifdef MAIL_SPOOL_DIRECTORY + sprintf(buf, "%.200s/%.50s", MAIL_SPOOL_DIRECTORY, pw->pw_name); + child_set_env(&env, &envsize, "MAIL", buf); +#else /* MAIL_SPOOL_DIRECTORY */ +#ifdef HAVE_TILDE_NEWMAIL + sprintf(buf, "%.200s/newmail", pw->pw_dir); + child_set_env(&env, &envsize, "MAIL", buf); +#endif /* HAVE_TILDE_NEWMAIL */ +#endif /* MAIL_SPOOL_DIRECTORY */ + +#ifdef HAVE_ETC_DEFAULT_LOGIN + /* Read /etc/default/login; this exists at least on Solaris 2.x. */ + read_etc_default_login(&env, &envsize, pw); +#else /* HAVE_ETC_DEFAULT_LOGIN */ + /* Normal systems set SHELL by default. */ + child_set_env(&env, &envsize, "SHELL", shell); +#endif /* HAVE_ETC_DEFAULT_LOGIN */ + + /* Set custom environment options from RSA authentication. */ + while (custom_environment) + { + struct envstring *ce = custom_environment; + char *s = ce->s; + int i; + for (i = 0; s[i] != '=' && s[i]; i++) + ; + if (s[i] == '=') + { + s[i] = 0; + child_set_env(&env, &envsize, s, s + i + 1); + } + custom_environment = ce->next; + xfree(ce->s); + xfree(ce); + } + + /* Set SSH_CLIENT. */ + sprintf(buf, "%.50s %d %d", + get_remote_ipaddr(), get_remote_port(), options.port); + child_set_env(&env, &envsize, "SSH_CLIENT", buf); + + /* Set SSH_TTY if we have a pty. */ + if (ttyname) + child_set_env(&env, &envsize, "SSH_TTY", ttyname); + + /* Set TERM if we have a pty. */ + if (term) + child_set_env(&env, &envsize, "TERM", term); + + /* Set DISPLAY if we have one. */ + if (display) + child_set_env(&env, &envsize, "DISPLAY", display); + +#ifdef KRB4 /* XXX - how to make these coexist? */ + if (ticket) + child_set_env(&env, &envsize, "KRBTKFILE", ticket); +#endif /* KRB4 */ + + /* Set XAUTHORITY to always be a local file. */ + if (xauthfile) + child_set_env(&env, &envsize, "XAUTHORITY", xauthfile); + + /* Set variable for forwarded authentication connection, if we have one. */ + if (get_permanent_fd(pw->pw_shell) < 0) + { + if (auth_get_socket_name() != NULL) + child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, + auth_get_socket_name()); + } + else + if (auth_get_fd() >= 0) + { + sprintf(buf, "%d", auth_get_fd()); + child_set_env(&env, &envsize, SSH_AUTHFD_ENV_NAME, buf); + } + + /* Read environment variable settings from /etc/environment. (This exists + at least on AIX, but could be useful also elsewhere.) */ + read_environment_file(&env, &envsize, "/etc/environment"); + + /* Read $HOME/.ssh/environment. */ + sprintf(buf, "%.200s/.ssh/environment", pw->pw_dir); + read_environment_file(&env, &envsize, buf); + + /* If debugging, dump the environment to stderr. */ + if (debug_flag) + { + fprintf(stderr, "Environment:\n"); + for (i = 0; env[i]; i++) + fprintf(stderr, " %.200s\n", env[i]); + } + + /* Close the connection descriptors; note that this is the child, and the + server will still have the socket open, and it is important that we + do not shutdown it. Note that the descriptors cannot be closed before + building the environment, as we call get_remote_ipaddr there. */ + if (packet_get_connection_in() == packet_get_connection_out()) + close(packet_get_connection_in()); + else + { + close(packet_get_connection_in()); + close(packet_get_connection_out()); + } + /* Close all descriptors related to channels. They will still remain + open in the parent. */ + channel_close_all(); + + /* Close any extra file descriptors. Note that there may still be + descriptors left by system functions. They will be closed later. */ + endpwent(); + endhostent(); + + /* Close any extra open file descriptors so that we don\'t have them + hanging around in clients. Note that we want to do this after + initgroups, because at least on Solaris 2.3 it leaves file descriptors + open. */ + for (i = 3; i < 64; i++) + { + if (i == auth_get_fd()) + continue; + close(i); + } + + /* Change current directory to the user\'s home directory. */ + if (chdir(pw->pw_dir) < 0) + fprintf(stderr, "Could not chdir to home directory %s: %s\n", + pw->pw_dir, strerror(errno)); + + /* Must take new environment into use so that .ssh/rc, /etc/sshrc and + xauth are run in the proper environment. */ + environ = env; + + /* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first + in this order). */ + if (stat(SSH_USER_RC, &st) >= 0) + { + if (debug_flag) + fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC); + + f = popen("/bin/sh " SSH_USER_RC, "w"); + if (f) + { + if (auth_proto != NULL && auth_data != NULL) + fprintf(f, "%s %s\n", auth_proto, auth_data); + pclose(f); + } + else + fprintf(stderr, "Could not run %s\n", SSH_USER_RC); + } + else + if (stat(SSH_SYSTEM_RC, &st) >= 0) + { + if (debug_flag) + fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC); + + f = popen("/bin/sh " SSH_SYSTEM_RC, "w"); + if (f) + { + if (auth_proto != NULL && auth_data != NULL) + fprintf(f, "%s %s\n", auth_proto, auth_data); + pclose(f); + } + else + fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC); + } +#ifdef XAUTH_PATH + else + { + /* Add authority data to .Xauthority if appropriate. */ + if (auth_proto != NULL && auth_data != NULL) + { + if (debug_flag) + fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n", + XAUTH_PATH, display, auth_proto, auth_data); + + f = popen(XAUTH_PATH " -q -", "w"); + if (f) + { + fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data); + fclose(f); + } + else + fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH); + } + } +#endif /* XAUTH_PATH */ + + /* Get the last component of the shell name. */ + cp = strrchr(shell, '/'); + if (cp) + cp++; + else + cp = shell; + + /* If we have no command, execute the shell. In this case, the shell name + to be passed in argv[0] is preceded by '-' to indicate that this is + a login shell. */ + if (!command) + { + char buf[256]; + + /* Start the shell. Set initial character to '-'. */ + buf[0] = '-'; + strncpy(buf + 1, cp, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = 0; + /* Execute the shell. */ + argv[0] = buf; + argv[1] = NULL; + execve(shell, argv, env); + /* Executing the shell failed. */ + perror(shell); + exit(1); + } + + /* Execute the command using the user's shell. This uses the -c option + to execute the command. */ + argv[0] = (char *)cp; + argv[1] = "-c"; + argv[2] = (char *)command; + argv[3] = NULL; + execve(shell, argv, env); + perror(shell); + exit(1); +} diff --git a/usr.bin/ssh/tildexpand.c b/usr.bin/ssh/tildexpand.c new file mode 100644 index 00000000000..390eab3c064 --- /dev/null +++ b/usr.bin/ssh/tildexpand.c @@ -0,0 +1,71 @@ +/* + +tildexpand.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Wed Jul 12 01:07:36 1995 ylo + +*/ + +#include "includes.h" +RCSID("$Id: tildexpand.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); + +#include "xmalloc.h" +#include "ssh.h" + +/* Expands tildes in the file name. Returns data allocated by xmalloc. + Warning: this calls getpw*. */ + +char *tilde_expand_filename(const char *filename, uid_t my_uid) +{ + const char *cp; + unsigned int userlen; + char *expanded; + struct passwd *pw; + char user[100]; + + /* Return immediately if no tilde. */ + if (filename[0] != '~') + return xstrdup(filename); + + + /* Skiop the tilde. */ + filename++; + + /* Find where the username ends. */ + cp = strchr(filename, '/'); + if (cp) + userlen = cp - filename; /* Have something after username. */ + else + userlen = strlen(filename); /* Nothign after username. */ + if (userlen == 0) + pw = getpwuid(my_uid); /* Own home directory. */ + else + { + /* Tilde refers to someone elses home directory. */ + if (userlen > sizeof(user) - 1) + fatal("User name after tilde too long."); + memcpy(user, filename, userlen); + user[userlen] = 0; + pw = getpwnam(user); + } + + /* Check that we found the user. */ + if (!pw) + fatal("Unknown user %100s.", user); + + /* If referring to someones home directory, return it now. */ + if (!cp) + { /* Only home directory specified */ + return xstrdup(pw->pw_dir); + } + + /* Build a path combining the specified directory and path. */ + expanded = xmalloc(strlen(pw->pw_dir) + strlen(cp + 1) + 2); + sprintf(expanded, "%s/%s", pw->pw_dir, cp + 1); + return expanded; +} diff --git a/usr.bin/ssh/ttymodes.c b/usr.bin/ssh/ttymodes.c new file mode 100644 index 00000000000..c03e968937c --- /dev/null +++ b/usr.bin/ssh/ttymodes.c @@ -0,0 +1,499 @@ +/* + +ttymodes.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Tue Mar 21 15:59:15 1995 ylo + +Encoding and decoding of terminal modes in a portable way. +Much of the format is defined in ttymodes.h; it is included multiple times +into this file with the appropriate macro definitions to generate the +suitable code. + +*/ + +#include "includes.h" +RCSID("$Id: ttymodes.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); + +#include "packet.h" +#include "ssh.h" + +#define TTY_OP_END 0 +#define TTY_OP_ISPEED 192 /* int follows */ +#define TTY_OP_OSPEED 193 /* int follows */ + +/* Speed extraction & setting macros for sgtty. */ + +#ifdef USING_SGTTY +#define cfgetospeed(tio) ((tio)->sg_ospeed) +#define cfgetispeed(tio) ((tio)->sg_ispeed) +#define cfsetospeed(tio, spd) ((tio)->sg_ospeed = (spd), 0) +#define cfsetispeed(tio, spd) ((tio)->sg_ispeed = (spd), 0) +#ifndef SPEED_T_IN_STDTYPES_H +typedef char speed_t; +#endif +#endif + +/* Converts POSIX speed_t to a baud rate. The values of the constants + for speed_t are not themselves portable. */ + +static int speed_to_baud(speed_t speed) +{ + switch (speed) + { + case B0: + return 0; + case B50: + return 50; + case B75: + return 75; + case B110: + return 110; + case B134: + return 134; + case B150: + return 150; + case B200: + return 200; + case B300: + return 300; + case B600: + return 600; + case B1200: + return 1200; + case B1800: + return 1800; + case B2400: + return 2400; + case B4800: + return 4800; + case B9600: + return 9600; + +#ifdef B19200 + case B19200: + return 19200; +#else /* B19200 */ +#ifdef EXTA + case EXTA: + return 19200; +#endif /* EXTA */ +#endif /* B19200 */ + +#ifdef B38400 + case B38400: + return 38400; +#else /* B38400 */ +#ifdef EXTB + case EXTB: + return 38400; +#endif /* EXTB */ +#endif /* B38400 */ + +#ifdef B7200 + case B7200: + return 7200; +#endif /* B7200 */ +#ifdef B14400 + case B14400: + return 14400; +#endif /* B14400 */ +#ifdef B28800 + case B28800: + return 28800; +#endif /* B28800 */ +#ifdef B57600 + case B57600: + return 57600; +#endif /* B57600 */ +#ifdef B76800 + case B76800: + return 76800; +#endif /* B76800 */ +#ifdef B115200 + case B115200: + return 115200; +#endif /* B115200 */ +#ifdef B230400 + case B230400: + return 230400; +#endif /* B230400 */ + default: + return 9600; + } +} + +/* Converts a numeric baud rate to a POSIX speed_t. */ + +static speed_t baud_to_speed(int baud) +{ + switch (baud) + { + case 0: + return B0; + case 50: + return B50; + case 75: + return B75; + case 110: + return B110; + case 134: + return B134; + case 150: + return B150; + case 200: + return B200; + case 300: + return B300; + case 600: + return B600; + case 1200: + return B1200; + case 1800: + return B1800; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + +#ifdef B19200 + case 19200: + return B19200; +#else /* B19200 */ +#ifdef EXTA + case 19200: + return EXTA; +#endif /* EXTA */ +#endif /* B19200 */ + +#ifdef B38400 + case 38400: + return B38400; +#else /* B38400 */ +#ifdef EXTB + case 38400: + return EXTB; +#endif /* EXTB */ +#endif /* B38400 */ + +#ifdef B7200 + case 7200: + return B7200; +#endif /* B7200 */ +#ifdef B14400 + case 14400: + return B14400; +#endif /* B14400 */ +#ifdef B28800 + case 28800: + return B28800; +#endif /* B28800 */ +#ifdef B57600 + case 57600: + return B57600; +#endif /* B57600 */ +#ifdef B76800 + case 76800: + return B76800; +#endif /* B76800 */ +#ifdef B115200 + case 115200: + return B115200; +#endif /* B115200 */ +#ifdef B230400 + case 230400: + return B230400; +#endif /* B230400 */ + default: + return B9600; + } +} + +/* Encodes terminal modes for the terminal referenced by fd in a portable + manner, and appends the modes to a packet being constructed. */ + +void tty_make_modes(int fd) +{ +#ifdef USING_TERMIOS + struct termios tio; +#endif +#ifdef USING_SGTTY + struct sgttyb tio; + struct tchars tiotc; + struct ltchars tioltc; + int tiolm; +#ifdef TIOCGSTAT + struct tstatus tiots; +#endif /* TIOCGSTAT */ +#endif /* USING_SGTTY */ + int baud; + + /* Get the modes. */ +#ifdef USING_TERMIOS + if (tcgetattr(fd, &tio) < 0) + { + packet_put_char(TTY_OP_END); + log("tcgetattr: %.100s", strerror(errno)); + return; + } +#endif /* USING_TERMIOS */ +#ifdef USING_SGTTY + if (ioctl(fd, TIOCGETP, &tio) < 0) + { + packet_put_char(TTY_OP_END); + log("ioctl(fd, TIOCGETP, ...): %.100s", strerror(errno)); + return; + } + if (ioctl(fd, TIOCGETC, &tiotc) < 0) + { + packet_put_char(TTY_OP_END); + log("ioctl(fd, TIOCGETC, ...): %.100s", strerror(errno)); + return; + } + if (ioctl(fd, TIOCLGET, &tiolm) < 0) + { + packet_put_char(TTY_OP_END); + log("ioctl(fd, TIOCLGET, ...): %.100s", strerror(errno)); + return; + } + if (ioctl(fd, TIOCGLTC, &tioltc) < 0) + { + packet_put_char(TTY_OP_END); + log("ioctl(fd, TIOCGLTC, ...): %.100s", strerror(errno)); + return; + } +#ifdef TIOCGSTAT + if (ioctl(fd, TIOCGSTAT, &tiots) < 0) + { + packet_put_char(TTY_OP_END); + log("ioctl(fd, TIOCGSTAT, ...): %.100s", strerror(errno)); + return; + } +#endif /* TIOCGSTAT */ +#endif /* USING_SGTTY */ + + /* Store input and output baud rates. */ + baud = speed_to_baud(cfgetospeed(&tio)); + packet_put_char(TTY_OP_OSPEED); + packet_put_int(baud); + baud = speed_to_baud(cfgetispeed(&tio)); + packet_put_char(TTY_OP_ISPEED); + packet_put_int(baud); + + /* Store values of mode flags. */ +#ifdef USING_TERMIOS +#define TTYCHAR(NAME, OP) \ + packet_put_char(OP); packet_put_char(tio.c_cc[NAME]); +#define TTYMODE(NAME, FIELD, OP) \ + packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0); +#define SGTTYCHAR(NAME, OP) +#define SGTTYMODE(NAME, FIELD, OP) +#define SGTTYMODEN(NAME, FIELD, OP) +#endif /* USING_TERMIOS */ + +#ifdef USING_SGTTY +#define TTYCHAR(NAME, OP) +#define TTYMODE(NAME, FIELD, OP) +#define SGTTYCHAR(NAME, OP) \ + packet_put_char(OP); packet_put_char(NAME); +#define SGTTYMODE(NAME, FIELD, OP) \ + packet_put_char(OP); packet_put_char((FIELD & NAME) != 0); +#define SGTTYMODEN(NAME, FIELD, OP) \ + packet_put_char(OP); packet_put_char((FIELD & NAME) == 0); +#endif /* USING_SGTTY */ + +#include "ttymodes.h" + +#undef TTYCHAR +#undef TTYMODE +#undef SGTTYCHAR +#undef SGTTYMODE +#undef SGTTYMODEN + + /* Mark end of mode data. */ + packet_put_char(TTY_OP_END); +} + +/* Decodes terminal modes for the terminal referenced by fd in a portable + manner from a packet being read. */ + +void tty_parse_modes(int fd, int *n_bytes_ptr) +{ +#ifdef USING_TERMIOS + struct termios tio; +#endif /* USING_TERMIOS */ +#ifdef USING_SGTTY + struct sgttyb tio; + struct tchars tiotc; + struct ltchars tioltc; + int tiolm; +#ifdef TIOCGSTAT + struct tstatus tiots; +#endif /* TIOCGSTAT */ +#endif + int opcode, baud; + int n_bytes = 0; + int failure = 0; + + /* Get old attributes for the terminal. We will modify these flags. + I am hoping that if there are any machine-specific modes, they will + initially have reasonable values. */ +#ifdef USING_TERMIOS + if (tcgetattr(fd, &tio) < 0) + failure = -1; +#endif /* USING_TERMIOS */ +#ifdef USING_SGTTY + if (ioctl(fd, TIOCGETP, &tio) < 0) + failure = -1; + if (ioctl(fd, TIOCGETC, &tiotc) < 0) + failure = -1; + if (ioctl(fd, TIOCLGET, &tiolm) < 0) + failure = -1; + if (ioctl(fd, TIOCGLTC, &tioltc) < 0) + failure = -1; +#ifdef TIOCGSTAT + if (ioctl(fd, TIOCGSTAT, &tiots) < 0) + failure = -1; +#endif /* TIOCGSTAT */ +#endif /* USING_SGTTY */ + + for (;;) + { + n_bytes += 1; + opcode = packet_get_char(); + switch (opcode) + { + case TTY_OP_END: + goto set; + + case TTY_OP_ISPEED: + n_bytes += 4; + baud = packet_get_int(); + if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0) + error("cfsetispeed failed for %d", baud); + break; + + case TTY_OP_OSPEED: + n_bytes += 4; + baud = packet_get_int(); + if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0) + error("cfsetospeed failed for %d", baud); + break; + +#ifdef USING_TERMIOS +#define TTYCHAR(NAME, OP) \ + case OP: \ + n_bytes += 1; \ + tio.c_cc[NAME] = packet_get_char(); \ + break; +#define TTYMODE(NAME, FIELD, OP) \ + case OP: \ + n_bytes += 1; \ + if (packet_get_char()) \ + tio.FIELD |= NAME; \ + else \ + tio.FIELD &= ~NAME; \ + break; +#define SGTTYCHAR(NAME, OP) +#define SGTTYMODE(NAME, FIELD, OP) +#define SGTTYMODEN(NAME, FIELD, OP) +#endif /* USING_TERMIOS */ + +#ifdef USING_SGTTY +#define TTYCHAR(NAME, OP) +#define TTYMODE(NAME, FIELD, OP) +#define SGTTYCHAR(NAME, OP) \ + case OP: \ + n_bytes += 1; \ + NAME = packet_get_char(); \ + break; +#define SGTTYMODE(NAME, FIELD, OP) \ + case OP: \ + n_bytes += 1; \ + if (packet_get_char()) \ + FIELD |= NAME; \ + else \ + FIELD &= ~NAME; \ + break; +#define SGTTYMODEN(NAME, FIELD, OP) \ + case OP: \ + n_bytes += 1; \ + if (packet_get_char()) \ + FIELD &= ~NAME; \ + else \ + FIELD |= NAME; \ + break; +#endif /* USING_SGTTY */ + +#include "ttymodes.h" + +#undef TTYCHAR +#undef TTYMODE +#undef SGTTYCHAR +#undef SGTTYMODE +#undef SGTTYMODEN + + default: + debug("Ignoring unsupported tty mode opcode %d (0x%x)", + opcode, opcode); + /* Opcodes 0 to 127 are defined to have a one-byte argument. */ + if (opcode >= 0 && opcode < 128) + { + n_bytes += 1; + (void)packet_get_char(); + break; + } + else + { + /* Opcodes 128 to 159 are defined to have an integer argument. */ + if (opcode >= 128 && opcode < 160) + { + n_bytes += 4; + (void)packet_get_int(); + break; + } + } + /* It is a truly undefined opcode (160 to 255). We have no idea + about its arguments. So we must stop parsing. Note that some + data may be left in the packet; hopefully there is nothing more + coming after the mode data. */ + log("parse_tty_modes: unknown opcode %d", opcode); + packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY); + goto set; + } + } + + set: + if (*n_bytes_ptr != n_bytes) + { + *n_bytes_ptr = n_bytes; + return; /* Don't process bytes passed */ + } + + if (failure == -1) + return; /* Packet parsed ok but tty stuff failed */ + + /* Set the new modes for the terminal. */ +#ifdef USING_TERMIOS + if (tcsetattr(fd, TCSANOW, &tio) < 0) + log("Setting tty modes failed: %.100s", strerror(errno)); +#endif /* USING_TERMIOS */ +#ifdef USING_SGTTY + if (ioctl(fd, TIOCSETP, &tio) < 0 + || ioctl(fd, TIOCSETC, &tiotc) < 0 + || ioctl(fd, TIOCLSET, &tiolm) < 0 + || ioctl(fd, TIOCSLTC, &tioltc) < 0 +#ifdef TIOCSSTAT + || ioctl(fd, TIOCSSTAT, &tiots) < 0 +#endif /* TIOCSSTAT */ + ) + log("Setting tty modes failed: %.100s", strerror(errno)); +#endif /* USING_SGTTY */ + return; +} diff --git a/usr.bin/ssh/ttymodes.h b/usr.bin/ssh/ttymodes.h new file mode 100644 index 00000000000..a9a064903c5 --- /dev/null +++ b/usr.bin/ssh/ttymodes.h @@ -0,0 +1,138 @@ +/* + +ttymodes.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + SGTTY stuff contributed by Janne Snabb <snabb@niksula.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Tue Mar 21 15:42:09 1995 ylo + +*/ + +/* RCSID("$Id: ttymodes.h,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); */ + +/* The tty mode description is a stream of bytes. The stream consists of + opcode-arguments pairs. It is terminated by opcode TTY_OP_END (0). + Opcodes 1-127 have one-byte arguments. Opcodes 128-159 have integer + arguments. Opcodes 160-255 are not yet defined, and cause parsing to + stop (they should only be used after 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 + tty interface. The protocol can support other systems as well, but might + require reimplementing as mode names would likely be different. */ + +/* Some constants and prototypes are defined in packet.h; this file + is only intended for including from ttymodes.h. */ + +/* termios macro */ /* sgtty macro */ +/* name, op */ +TTYCHAR(VINTR, 1) SGTTYCHAR(tiotc.t_intrc, 1) +TTYCHAR(VQUIT, 2) SGTTYCHAR(tiotc.t_quitc, 2) +TTYCHAR(VERASE, 3) SGTTYCHAR(tio.sg_erase, 3) +#if defined(VKILL) || defined(USING_SGTTY) +TTYCHAR(VKILL, 4) SGTTYCHAR(tio.sg_kill, 4) +#endif /* VKILL */ +TTYCHAR(VEOF, 5) SGTTYCHAR(tiotc.t_eofc, 5) +#if defined(VEOL) || defined(USING_SGTTY) +TTYCHAR(VEOL, 6) SGTTYCHAR(tiotc.t_brkc, 6) +#endif /* VEOL */ +#ifdef VEOL2 /* n/a */ +TTYCHAR(VEOL2, 7) +#endif /* VEOL2 */ +TTYCHAR(VSTART, 8) SGTTYCHAR(tiotc.t_startc, 8) +TTYCHAR(VSTOP, 9) SGTTYCHAR(tiotc.t_stopc, 9) +#if defined(VSUSP) || defined(USING_SGTTY) +TTYCHAR(VSUSP, 10) SGTTYCHAR(tioltc.t_suspc, 10) +#endif /* VSUSP */ +#if defined(VDSUSP) || defined(USING_SGTTY) +TTYCHAR(VDSUSP, 11) SGTTYCHAR(tioltc.t_dsuspc, 11) +#endif /* VDSUSP */ +#if defined(VREPRINT) || defined(USING_SGTTY) +TTYCHAR(VREPRINT, 12) SGTTYCHAR(tioltc.t_rprntc, 12) +#endif /* VREPRINT */ +#if defined(VWERASE) || defined(USING_SGTTY) +TTYCHAR(VWERASE, 13) SGTTYCHAR(tioltc.t_werasc, 13) +#endif /* VWERASE */ +#if defined(VLNEXT) || defined(USING_SGTTY) +TTYCHAR(VLNEXT, 14) SGTTYCHAR(tioltc.t_lnextc, 14) +#endif /* VLNEXT */ +#if defined(VFLUSH) || defined(USING_SGTTY) +TTYCHAR(VFLUSH, 15) SGTTYCHAR(tioltc.t_flushc, 15) +#endif /* VFLUSH */ +#ifdef VSWTCH +TTYCHAR(VSWTCH, 16) /* n/a */ +#endif /* VSWTCH */ +#if defined(VSTATUS) || (defined(USING_SGTTY) && defined(TIOCGSTAT)) +TTYCHAR(VSTATUS, 17) SGTTYCHAR(tiots.tc_statusc, 17) +#endif /* VSTATUS */ +#ifdef VDISCARD +TTYCHAR(VDISCARD, 18) /* n/a */ +#endif /* VDISCARD */ + +/* name, field, op */ +TTYMODE(IGNPAR, c_iflag, 30) /* n/a */ +TTYMODE(PARMRK, c_iflag, 31) /* n/a */ +TTYMODE(INPCK, c_iflag, 32) SGTTYMODEN(ANYP, tio.sg_flags, 32) +TTYMODE(ISTRIP, c_iflag, 33) SGTTYMODEN(LPASS8, tiolm, 33) +TTYMODE(INLCR, c_iflag, 34) /* n/a */ +TTYMODE(IGNCR, c_iflag, 35) /* n/a */ +TTYMODE(ICRNL, c_iflag, 36) SGTTYMODE(CRMOD, tio.sg_flags, 36) +#if defined(IUCLC) || defined(USING_SGTTY) +TTYMODE(IUCLC, c_iflag, 37) SGTTYMODE(LCASE, tio.sg_flags, 37) +#endif +TTYMODE(IXON, c_iflag, 38) /* n/a */ +TTYMODE(IXANY, c_iflag, 39) SGTTYMODEN(LDECCTQ, tiolm, 39) +TTYMODE(IXOFF, c_iflag, 40) SGTTYMODE(TANDEM, tio.sg_flags, 40) +#ifdef IMAXBEL +TTYMODE(IMAXBEL,c_iflag, 41) /* n/a */ +#endif /* IMAXBEL */ + +TTYMODE(ISIG, c_lflag, 50) /* n/a */ +TTYMODE(ICANON, c_lflag, 51) SGTTYMODEN(CBREAK, tio.sg_flags, 51) +#ifdef XCASE +TTYMODE(XCASE, c_lflag, 52) /* n/a */ +#endif +TTYMODE(ECHO, c_lflag, 53) SGTTYMODE(ECHO, tio.sg_flags, 53) +TTYMODE(ECHOE, c_lflag, 54) SGTTYMODE(LCRTERA, tiolm, 54) +TTYMODE(ECHOK, c_lflag, 55) SGTTYMODE(LCRTKIL, tiolm, 55) +TTYMODE(ECHONL, c_lflag, 56) /* n/a */ +TTYMODE(NOFLSH, c_lflag, 57) SGTTYMODE(LNOFLSH, tiolm, 57) +TTYMODE(TOSTOP, c_lflag, 58) SGTTYMODE(LTOSTOP, tiolm, 58) +#ifdef IEXTEN +TTYMODE(IEXTEN, c_lflag, 59) /* n/a */ +#endif /* IEXTEN */ +#if defined(ECHOCTL) || defined(USING_SGTTY) +TTYMODE(ECHOCTL,c_lflag, 60) SGTTYMODE(LCTLECH, tiolm, 60) +#endif /* ECHOCTL */ +#ifdef ECHOKE +TTYMODE(ECHOKE, c_lflag, 61) /* n/a */ +#endif /* ECHOKE */ +#if defined(PENDIN) || defined(USING_SGTTY) +TTYMODE(PENDIN, c_lflag, 62) SGTTYMODE(LPENDIN, tiolm, 62) +#endif /* PENDIN */ + +TTYMODE(OPOST, c_oflag, 70) /* n/a */ +#if defined(OLCUC) || defined(USING_SGTTY) +TTYMODE(OLCUC, c_oflag, 71) SGTTYMODE(LCASE, tio.sg_flags, 71) +#endif +TTYMODE(ONLCR, c_oflag, 72) SGTTYMODE(CRMOD, tio.sg_flags, 72) +#ifdef OCRNL +TTYMODE(OCRNL, c_oflag, 73) /* n/a */ +#endif +#ifdef ONOCR +TTYMODE(ONOCR, c_oflag, 74) /* n/a */ +#endif +#ifdef ONLRET +TTYMODE(ONLRET, c_oflag, 75) /* n/a */ +#endif + +TTYMODE(CS7, c_cflag, 90) /* n/a */ +TTYMODE(CS8, c_cflag, 91) SGTTYMODE(LPASS8, tiolm, 91) +TTYMODE(PARENB, c_cflag, 92) /* n/a */ +TTYMODE(PARODD, c_cflag, 93) SGTTYMODE(ODDP, tio.sg_flags, 93) + diff --git a/usr.bin/ssh/uidswap.c b/usr.bin/ssh/uidswap.c new file mode 100644 index 00000000000..314be452980 --- /dev/null +++ b/usr.bin/ssh/uidswap.c @@ -0,0 +1,126 @@ +/* + +uidswap.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Sep 9 01:56:14 1995 ylo + +Code for uid-swapping. + +*/ + +#include "includes.h" +RCSID("$Id: uidswap.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); + +#include "ssh.h" +#include "uidswap.h" + +/* Note: all these functions must work in all of the following cases: + + 1. euid=0, ruid=0 + 2. euid=0, ruid!=0 + 3. euid!=0, ruid!=0 + + Additionally, they must work regardless of whether the system has + POSIX saved uids or not. */ + +#ifdef HAVE_SETEUID + +#ifdef _POSIX_SAVED_IDS +/* Lets assume that posix saved ids also work with seteuid, even though that + is not part of the posix specification. */ +#define SAVED_IDS_WORK_WITH_SETEUID +#endif /* _POSIX_SAVED_IDS */ + +/* Saved effective uid. */ +static uid_t saved_euid = 0; + +/* Temporarily changes to the given uid. If the effective user id is not + root, this does nothing. This call cannot be nested. */ + +void temporarily_use_uid(uid_t uid) +{ +#ifdef SAVED_IDS_WORK_WITH_SETEUID + + /* Save the current euid. */ + saved_euid = geteuid(); + + /* Set the effective uid to the given (unprivileged) uid. */ + if (seteuid(uid) == -1) + debug("seteuid %d: %.100s", (int)uid, strerror(errno)); + +#else /* SAVED_IDS_WORK_WITH_SETUID */ + + /* Propagate the privileged uid to all of our uids. */ + if (setuid(geteuid()) < 0) + debug("setuid %d: %.100s", (int)geteuid(), strerror(errno)); + + /* Set the effective uid to the given (unprivileged) uid. */ + if (seteuid(uid) == -1) + debug("seteuid %d: %.100s", (int)uid, strerror(errno)); + +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ + +} + +/* Restores to the original uid. */ + +void restore_uid() +{ +#ifdef SAVED_IDS_WORK_WITH_SETEUID + + /* Set the effective uid back to the saved uid. */ + if (seteuid(saved_euid) < 0) + debug("seteuid %d: %.100s", (int)saved_euid, strerror(errno)); + +#else /* SAVED_IDS_WORK_WITH_SETEUID */ + + /* We are unable to restore the real uid to its unprivileged value. */ + /* Propagate the real uid (usually more privileged) to effective uid + as well. */ + setuid(getuid()); + +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ +} + +/* Permanently sets all uids to the given uid. This cannot be called while + temporarily_use_uid is effective. */ + +void permanently_set_uid(uid_t uid) +{ + if (setuid(uid) < 0) + debug("setuid %d: %.100s", (int)uid, strerror(errno)); +} + +#else /* HAVE_SETEUID */ + +YOUR_SYSTEM_DOES_NOT_PERMIT_UID_SWAPPING_READ_AND_EDIT_UIDSWAP_C; +/* If we ever come here, if means that your system does not support any of + the uid swapping methods we are aware of. Tough. This means that + ssh will have to read certain files as root, which causes some security + problems. Unless your are very concerned about security, you can + comment out the above line. The effect is that local users on your + machine might be able to read each other's files. Also, you may encounter + problems if home directories are on a NFS volume. You may also + encounter other problems; please don't complain unless you have some idea + how to fix it. */ + +void temporarily_use_uid(uid_t uid) +{ +} + +void restore_uid() +{ +} + +void permanently_set_uid(uid_t uid) +{ + if (setuid(uid) < 0) + debug("setuid %d: %.100s", (int)uid, strerror(errno)); +} + +#endif /* HAVE_SETEUID */ diff --git a/usr.bin/ssh/uidswap.h b/usr.bin/ssh/uidswap.h new file mode 100644 index 00000000000..af4f924f0ce --- /dev/null +++ b/usr.bin/ssh/uidswap.h @@ -0,0 +1,30 @@ +/* + +uidswap.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Sat Sep 9 01:43:15 1995 ylo +Last modified: Sat Sep 9 02:34:04 1995 ylo + +*/ + +#ifndef UIDSWAP_H +#define UIDSWAP_H + +/* Temporarily changes to the given uid. If the effective user id is not + root, this does nothing. This call cannot be nested. */ +void temporarily_use_uid(uid_t uid); + +/* Restores the original effective user id after temporarily_use_uid(). + This should only be called while temporarily_use_uid is effective. */ +void restore_uid(); + +/* Permanently sets all uids to the given uid. This cannot be called while + temporarily_use_uid is effective. This must also clear any saved uids. */ +void permanently_set_uid(uid_t uid); + +#endif /* UIDSWAP_H */ diff --git a/usr.bin/ssh/version.h b/usr.bin/ssh/version.h new file mode 100644 index 00000000000..ca606fd62a3 --- /dev/null +++ b/usr.bin/ssh/version.h @@ -0,0 +1 @@ +#define SSH_VERSION "ossh-1.2.16" diff --git a/usr.bin/ssh/xmalloc.c b/usr.bin/ssh/xmalloc.c new file mode 100644 index 00000000000..b50959a9d27 --- /dev/null +++ b/usr.bin/ssh/xmalloc.c @@ -0,0 +1,60 @@ +/* + +xmalloc.c + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Mon Mar 20 21:23:10 1995 ylo + +Versions of malloc and friends that check their results, and never return +failure (they call fatal if they encounter an error). + +*/ + +#include "includes.h" +RCSID("$Id: xmalloc.c,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); + +#include "ssh.h" + +#if 0 +void *malloc(size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); +#endif + +void *xmalloc(size_t size) +{ + void *ptr = malloc(size); + if (ptr == NULL) + fatal("xmalloc: out of memory (allocating %d bytes)", (int)size); + return ptr; +} + +void *xrealloc(void *ptr, size_t new_size) +{ + void *new_ptr; + + if (ptr == NULL) + fatal("xrealloc: NULL pointer given as argument"); + new_ptr = realloc(ptr, new_size); + if (new_ptr == NULL) + fatal("xrealloc: out of memory (new_size %d bytes)", (int)new_size); + return new_ptr; +} + +void xfree(void *ptr) +{ + if (ptr == NULL) + fatal("xfree: NULL pointer given as argument"); + free(ptr); +} + +char *xstrdup(const char *str) +{ + char *cp = xmalloc(strlen(str) + 1); + strcpy(cp, str); + return cp; +} diff --git a/usr.bin/ssh/xmalloc.h b/usr.bin/ssh/xmalloc.h new file mode 100644 index 00000000000..ffdde62ed1d --- /dev/null +++ b/usr.bin/ssh/xmalloc.h @@ -0,0 +1,34 @@ +/* + +xmalloc.h + +Author: Tatu Ylonen <ylo@cs.hut.fi> + +Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + All rights reserved + +Created: Mon Mar 20 22:09:17 1995 ylo + +Versions of malloc and friends that check their results, and never return +failure (they call fatal if they encounter an error). + +*/ + +/* RCSID("$Id: xmalloc.h,v 1.1 1999/09/26 20:53:38 deraadt Exp $"); */ + +#ifndef XMALLOC_H +#define XMALLOC_H + +/* Like malloc, but calls fatal() if out of memory. */ +void *xmalloc(size_t size); + +/* Like realloc, but calls fatal() if out of memory. */ +void *xrealloc(void *ptr, size_t new_size); + +/* Frees memory allocated using xmalloc or xrealloc. */ +void xfree(void *ptr); + +/* Allocates memory using xmalloc, and copies the string into that memory. */ +char *xstrdup(const char *str); + +#endif /* XMALLOC_H */ |