diff options
author | 1999-09-26 20:53:32 +0000 | |
---|---|---|
committer | 1999-09-26 20:53:32 +0000 | |
commit | 84959968510b547c35dddcbd0b9dcce9f25fdf8f (patch) | |
tree | e37579877300876b034163932595ec47d00e0d8b | |
parent | Increase MAXMAGIS again, and change the reallocation - don't need to (diff) | |
download | wireguard-openbsd-84959968510b547c35dddcbd0b9dcce9f25fdf8f.tar.xz wireguard-openbsd-84959968510b547c35dddcbd0b9dcce9f25fdf8f.zip |
i bet a lot of people didn't know what ssh 1.2.16 had a nice license.
well, except for the patent issues. someone in sweden (forget their
name at the moment) cleaned out most of the patented code, and now
this code removes rsa code. when this is done, it will link against
libssl, but the work isn't completely done yet. then we need to bring
this up to modern days, featurewise.
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 */ |