From: Scott Ullrich Date: Mon, 30 Aug 2004 21:59:58 +0000 (+0000) Subject: Import OpenSSH-3.9p1 from openbsd.org X-Git-Tag: v2.0.1~10389^2 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/47fa77c331b21f295f654f272bff04ea33b8ed6d Import OpenSSH-3.9p1 from openbsd.org Assistance-from: Chris Pressey, Jörg Sonnenberger Testing-by: Guillermo García Rojas C, Chris Pressey & Jeroen Ruigrok van der Werven --- diff --git a/crypto/openssh-3.9p1/CREDITS b/crypto/openssh-3.9p1/CREDITS new file mode 100644 index 0000000000..2a77b8729e --- /dev/null +++ b/crypto/openssh-3.9p1/CREDITS @@ -0,0 +1,102 @@ +Tatu Ylonen - Creator of SSH + +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt, and Dug Song - Creators of OpenSSH + +Alain St-Denis - Irix fix +Alexandre Oliva - AIX fixes +Andre Lucas - new login code, many fixes +Andreas Steinmetz - Shadow password expiry support +Andrew McGill - SCO fixes +Andrew Morgan - PAM bugfixes +Andrew Stribblehill - Bugfixes +Andy Sloane - bugfixes +Aran Cox - SCO bugfixes +Arkadiusz Miskiewicz - IPv6 compat fixes +Ben Lindstrom - NeXT support +Ben Taylor - Solaris debugging and fixes +Bratislav ILICH - Configure fix +Charles Levert - SunOS 4 & bug fixes +Chip Salzenberg - Assorted patches +Chris Adams - OSF SIA support +Chris Saia - SuSE packaging +Chris, the Young One - Password auth fixes +Christos Zoulas - Autoconf fixes +Chun-Chung Chen - RPM fixes +Corinna Vinschen - Cygwin support +Dan Brosemer - Autoconf support, build fixes +Darren Hall - AIX patches +Darren Tucker - AIX BFF package scripts +David Agraz - Build fixes +David Del Piero - bug fixes +David Hesprich - Configure fixes +David Rankin - libwrap, AIX, NetBSD fixes +Dag-Erling Smørgrav - Challenge-Response PAM code. +Ed Eden - configure fixes +Garrick James - configure fixes +Gary E. Miller - SCO support +Ged Lodder - HPUX fixes and enhancements +Gert Doering - bug and portability fixes +HARUYAMA Seigo - Translations & doc fixes +Hideaki YOSHIFUJI - IPv6 and bug fixes +Hiroshi Takekawa - Configure fixes +Holger Trapp - KRB4/AFS config patch +IWAMURO Motonori - bugfixes +Jani Hakala - Patches +Jarno Huuskonen - Bugfixes +Jim Knoble - Many patches +Jonchen (email unknown) - the original author of PAM support of SSH +Juergen Keil - scp bugfixing +KAMAHARA Junzo - Configure fixes +Kees Cook - scp fixes +Kenji Miyake - Configure fixes +Kevin Cawlfield - AIX fixes. +Kevin O'Connor - RSAless operation +Kevin Steves - HP support, bugfixes, improvements +Kiyokazu SUTO - Bugfixes +Larry Jones - Bugfixes +Lutz Jaenicke - Bugfixes +Marc G. Fournier - Solaris patches +Mark D. Baushke - bug fixes +Martin Johansson - Linux fixes +Mark D. Roth - Features, bug fixes +Mark Miller - Bugfixes +Matt Richards - AIX patches +Michael Steffens - HP-UX fixes +Michael Stone - Irix enhancements +Nakaji Hiroyuki - Sony News-OS patch +Nalin Dahyabhai - PAM environment patch +Nate Itkin - SunOS 4.1.x fixes +Niels Kristian Bech Jensen - Assorted patches +Pavel Kankovsky - Security fixes +Pavel Troller - Bugfixes +Pekka Savola - Bugfixes +Peter Kocks - Makefile fixes +Peter Stuge - mdoc2man.awk script +Phil Hands - Debian scripts, assorted patches +Phil Karn - Autoconf fixes +Philippe WILLEM - Bugfixes +Phill Camp - login code fix +Rip Loomis - Solaris package support, fixes +Robert Dahlem - Reliant Unix fixes +Roumen Petrov - Compile & configure fixes +SAKAI Kiyotaka - Multiple bugfixes +Simon Wilkinson - PAM fixes, Compat with MIT KrbV +Solar Designer - many patches and technical assistance +Svante Signell - Bugfixes +Thomas Neumann - Shadow passwords +Tim Rice - Portability & SCO fixes +Tobias Oetiker - Bugfixes +Tom Bertelson's - AIX auth fixes +Tor-Ake Fransson - AIX support +Tudor Bosman - MD5 password support +Udo Schweigert - ReliantUNIX support +Wendy Palm - Cray support. +Zack Weinberg - GNOME askpass enhancement + +Apologies to anyone I have missed. + +Damien Miller + +$Id: CREDITS,v 1.79 2004/05/26 23:59:31 dtucker Exp $ + diff --git a/crypto/openssh-3.9p1/INSTALL b/crypto/openssh-3.9p1/INSTALL new file mode 100644 index 0000000000..dae1bb159c --- /dev/null +++ b/crypto/openssh-3.9p1/INSTALL @@ -0,0 +1,203 @@ +1. Prerequisites +---------------- + +You will need working installations of Zlib and OpenSSL. + +Zlib 1.1.4 or greater: +http://www.gzip.org/zlib/ + +OpenSSL 0.9.6 or greater: +http://www.openssl.org/ + +(OpenSSL 0.9.5a is partially supported, but some ciphers (SSH protocol 1 +Blowfish) do not work correctly.) + +OpenSSH can utilise Pluggable Authentication Modules (PAM) if your system +supports it. PAM is standard on Redhat and Debian Linux, Solaris and +HP-UX 11. + +NB. If you operating system supports /dev/random, you should configure +OpenSSL to use it. OpenSSH relies on OpenSSL's direct support of +/dev/random. If you don't you will have to rely on ssh-rand-helper, which +is inferior to a good kernel-based solution. + +PAM: +http://www.kernel.org/pub/linux/libs/pam/ + +If you wish to build the GNOME passphrase requester, you will need the GNOME +libraries and headers. + +GNOME: +http://www.gnome.org/ + +Alternatively, Jim Knoble has written an excellent X11 +passphrase requester. This is maintained separately at: + +http://www.jmknoble.net/software/x11-ssh-askpass/ + +PRNGD: + +If your system lacks Kernel based random collection, the use of Lutz +Jaenicke's PRNGd is recommended. + +http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html + +EGD: + +The Entropy Gathering Daemon (EGD) is supported if you have a system which +lacks /dev/random and don't want to use OpenSSH's internal entropy collection. + +http://www.lothar.com/tech/crypto/ + +S/Key Libraries: +http://www.sparc.spb.su/solaris/skey/ + +If you wish to use --with-skey then you will need the above library +installed. No other current S/Key library is currently known to be +supported. + +2. Building / Installation +-------------------------- + +To install OpenSSH with default options: + +./configure +make +make install + +This will install the OpenSSH binaries in /usr/local/bin, configuration files +in /usr/local/etc, the server in /usr/local/sbin, etc. To specify a different +installation prefix, use the --prefix option to configure: + +./configure --prefix=/opt +make +make install + +Will install OpenSSH in /opt/{bin,etc,lib,sbin}. You can also override +specific paths, for example: + +./configure --prefix=/opt --sysconfdir=/etc/ssh +make +make install + +This will install the binaries in /opt/{bin,lib,sbin}, but will place the +configuration files in /etc/ssh. + +If you are using PAM, you may need to manually install a PAM control +file as "/etc/pam.d/sshd" (or wherever your system prefers to keep +them). Note that the service name used to start PAM is __progname, +which is the basename of the path of your sshd (e.g., the service name +for /usr/sbin/osshd will be osshd). If you have renamed your sshd +executable, your PAM configuration may need to be modified. + +A generic PAM configuration is included as "contrib/sshd.pam.generic", +you may need to edit it before using it on your system. If you are +using a recent version of Red Hat Linux, the config file in +contrib/redhat/sshd.pam should be more useful. Failure to install a +valid PAM file may result in an inability to use password +authentication. On HP-UX 11 and Solaris, the standard /etc/pam.conf +configuration will work with sshd (sshd will match the other service +name). + +There are a few other options to the configure script: + +--with-pam enables PAM support. If PAM support is compiled in, it must +also be enabled in sshd_config (refer to the UsePAM directive). + +--with-prngd-socket=/some/file allows you to enable EGD or PRNGD +support and to specify a PRNGd socket. Use this if your Unix lacks +/dev/random and you don't want to use OpenSSH's builtin entropy +collection support. + +--with-prngd-port=portnum allows you to enable EGD or PRNGD support +and to specify a EGD localhost TCP port. Use this if your Unix lacks +/dev/random and you don't want to use OpenSSH's builtin entropy +collection support. + +--with-lastlog=FILE will specify the location of the lastlog file. +./configure searches a few locations for lastlog, but may not find +it if lastlog is installed in a different place. + +--without-lastlog will disable lastlog support entirely. + +--with-osfsia, --without-osfsia will enable or disable OSF1's Security +Integration Architecture. The default for OSF1 machines is enable. + +--with-skey=PATH will enable S/Key one time password support. You will +need the S/Key libraries and header files installed for this to work. + +--with-tcp-wrappers will enable TCP Wrappers (/etc/hosts.allow|deny) +support. You will need libwrap.a and tcpd.h installed. + +--with-md5-passwords will enable the use of MD5 passwords. Enable this +if your operating system uses MD5 passwords and the system crypt() does +not support them directly (see the crypt(3/3c) man page). If enabled, the +resulting binary will support both MD5 and traditional crypt passwords. + +--with-utmpx enables utmpx support. utmpx support is automatic for +some platforms. + +--without-shadow disables shadow password support. + +--with-ipaddr-display forces the use of a numeric IP address in the +$DISPLAY environment variable. Some broken systems need this. + +--with-default-path=PATH allows you to specify a default $PATH for sessions +started by sshd. This replaces the standard path entirely. + +--with-pid-dir=PATH specifies the directory in which the ssh.pid file is +created. + +--with-xauth=PATH specifies the location of the xauth binary + +--with-ssl-dir=DIR allows you to specify where your OpenSSL libraries +are installed. + +--with-4in6 Check for IPv4 in IPv6 mapped addresses and convert them to +real (AF_INET) IPv4 addresses. Works around some quirks on Linux. + +--with-opensc=DIR +--with-sectok=DIR allows for OpenSC or sectok smartcard libraries to +be used with OpenSSH. See 'README.smartcard' for more details. + +If you need to pass special options to the compiler or linker, you +can specify these as environment variables before running ./configure. +For example: + +CFLAGS="-O -m486" LDFLAGS="-s" LIBS="-lrubbish" LD="/usr/foo/ld" ./configure + +3. Configuration +---------------- + +The runtime configuration files are installed by in ${prefix}/etc or +whatever you specified as your --sysconfdir (/usr/local/etc by default). + +The default configuration should be instantly usable, though you should +review it to ensure that it matches your security requirements. + +To generate a host key, run "make host-key". Alternately you can do so +manually using the following commands: + + ssh-keygen -t rsa1 -f /etc/ssh/ssh_host_key -N "" + ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N "" + ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N "" + +Replacing /etc/ssh with the correct path to the configuration directory. +(${prefix}/etc or whatever you specified with --sysconfdir during +configuration) + +If you have configured OpenSSH with EGD support, ensure that EGD is +running and has collected some Entropy. + +For more information on configuration, please refer to the manual pages +for sshd, ssh and ssh-agent. + +4. Problems? +------------ + +If you experience problems compiling, installing or running OpenSSH. +Please refer to the "reporting bugs" section of the webpage at +http://www.openssh.com/ + + +$Id: INSTALL,v 1.64 2004/05/26 23:59:31 dtucker Exp $ diff --git a/crypto/openssh-3.9p1/LICENCE b/crypto/openssh-3.9p1/LICENCE new file mode 100644 index 0000000000..d8c157304d --- /dev/null +++ b/crypto/openssh-3.9p1/LICENCE @@ -0,0 +1,332 @@ +This file is part of the OpenSSH software. + +The licences which components of this software fall under are as +follows. First, we will summarize and say that all components +are under a BSD licence, or a licence more free than that. + +OpenSSH contains no GPL code. + +1) + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + + [Tatu continues] + * 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. + + [However, none of that term is relevant at this point in time. All of + these restrictively licenced software components which he talks about + have been removed from OpenSSH, i.e., + + - RSA is no longer included, found in the OpenSSL library + - IDEA is no longer included, its use is deprecated + - DES is now external, in the OpenSSL library + - GMP is no longer used, and instead we call BN code from OpenSSL + - Zlib is now external, in a library + - The make-ssh-known-hosts script is no longer included + - TSS has been removed + - MD5 is now external, in the OpenSSL library + - RC4 support has been replaced with ARC4 support from OpenSSL + - Blowfish is now external, in the OpenSSL library + + [The licence continues] + + 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. + +2) + The 32-bit CRC compensation attack detector in deattack.c was + contributed by CORE SDI S.A. under a BSD-style license. + + * Cryptographic attack detector for ssh - source code + * + * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina. + * + * All rights reserved. Redistribution and use in source and binary + * forms, with or without modification, are permitted provided that + * this copyright notice is retained. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR + * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS + * SOFTWARE. + * + * Ariel Futoransky + * + +3) + ssh-keygen was contributed by David Mazieres under a BSD-style + license. + + * Copyright 1995, 1996 by David Mazieres . + * + * Modification and redistribution in source and binary forms is + * permitted provided that due credit is given to the author and the + * OpenBSD project by leaving this copyright notice intact. + +4) + The Rijndael implementation by Vincent Rijmen, Antoon Bosselaers + and Paulo Barreto is in the public domain and distributed + with the following license: + + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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. + +5) + One component of the ssh source code is under a 3-clause BSD license, + held by the University of California, since we pulled these parts from + original Berkeley code. + + * 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. 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. + +6) + Remaining components of the software are provided under a standard + 2-term BSD licence with the following names as copyright holders: + + Markus Friedl + Theo de Raadt + Niels Provos + Dug Song + Aaron Campbell + Damien Miller + Kevin Steves + Daniel Kouril + Wesley Griffin + Per Allansson + Nils Nordman + Simon Wilkinson + + Portable OpenSSH additionally includes code from the following copyright + holders, also under the 2-term BSD license: + + Ben Lindstrom + Tim Rice + Andre Lucas + Chris Adams + Corinna Vinschen + Cray Inc. + Denis Parker + Gert Doering + Jakob Schlyter + Jason Downs + Juha Yrjölä + Michael Stone + Networks Associates Technology, Inc. + Solar Designer + Todd C. Miller + Wayne Schroeder + William Jones + Darren Tucker + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +8) Portable OpenSSH contains the following additional licenses: + + a) md5crypt.c, md5crypt.h + + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this + * notice you can do whatever you want with this stuff. If we meet + * some day, and you think this stuff is worth it, you can buy me a + * beer in return. Poul-Henning Kamp + + b) snprintf replacement + + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell + * (papowell@astart.com) It may be used for any purpose as long as this + * notice remains intact on all source code distributions + + c) Compatibility code (openbsd-compat) + + Apart from the previously mentioned licenses, various pieces of code + in the openbsd-compat/ subdirectory are licensed as follows: + + Some code is licensed under a 3-term BSD license, to the following + copyright holders: + + Todd C. Miller + Theo de Raadt + Damien Miller + Eric P. Allman + The Regents of the University of California + + * 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. 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. + + Some code is licensed under an ISC-style license, to the following + copyright holders: + + Internet Software Consortium. + Todd C. Miller + + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + Some code is licensed under a MIT-style license to the following + copyright holders: + + Free Software Foundation, Inc. + + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + + +------ +$OpenBSD: LICENCE,v 1.18 2003/11/21 11:57:02 djm Exp $ diff --git a/crypto/openssh-3.9p1/README b/crypto/openssh-3.9p1/README new file mode 100644 index 0000000000..8724d8b5a8 --- /dev/null +++ b/crypto/openssh-3.9p1/README @@ -0,0 +1,64 @@ +See http://www.openssh.com/txt/release-3.8.1 for the release notes. + +- A Japanese translation of this document and of the OpenSSH FAQ is +- available at http://www.unixuser.org/~haruyama/security/openssh/index.html +- Thanks to HARUYAMA Seigo + +This is the port of OpenBSD's excellent OpenSSH[0] to Linux and other +Unices. + +OpenSSH is based on the last free version of Tatu Ylonen's sample +implementation with all patent-encumbered algorithms removed (to +external libraries), all known security bugs fixed, new features +reintroduced and many other clean-ups. OpenSSH has been created by +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, Theo de Raadt, +and Dug Song. It has a homepage at http://www.openssh.com/ + +This port consists of the re-introduction of autoconf support, PAM +support, EGD[1]/PRNGD[2] support and replacements for OpenBSD library +functions that are (regrettably) absent from other unices. This port +has been best tested on AIX, Cygwin, HP-UX, Linux, MacOS/X, +NetBSD, OpenBSD, OpenServer, Solaris, Unicos, and UnixWare. + +This version actively tracks changes in the OpenBSD CVS repository. + +The PAM support is now more functional than the popular packages of +commercial ssh-1.2.x. It checks "account" and "session" modules for +all logins, not just when using password authentication. + +OpenSSH depends on Zlib[3], OpenSSL[4] and optionally PAM[5]. + +There is now several mailing lists for this port of OpenSSH. Please +refer to http://www.openssh.com/list.html for details on how to join. + +Please send bug reports and patches to the mailing list +openssh-unix-dev@mindrot.org. The list is open to posting by +unsubscribed users.Code contribution are welcomed, but please follow the +OpenBSD style guidelines[6]. + +Please refer to the INSTALL document for information on how to install +OpenSSH on your system. There are a number of differences between this +port of OpenSSH and F-Secure SSH 1.x, please refer to the OpenSSH FAQ[7] +for details and general tips. + +Damien Miller + +Miscellania - + +This version of OpenSSH is based upon code retrieved from the OpenBSD +CVS repository which in turn was based on the last free sample +implementation released by Tatu Ylonen. + +References - + +[0] http://www.openssh.com/faq.html +[1] http://www.lothar.com/tech/crypto/ +[2] http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html +[3] http://www.gzip.org/zlib/ +[4] http://www.openssl.org/ +[5] http://www.kernel.org/pub/linux/libs/pam/ (PAM is standard on Solaris + and HP-UX 11) +[6] http://www.openbsd.org/cgi-bin/man.cgi?query=style&sektion=9 +[7] http://www.openssh.com/faq.html + +$Id: README,v 1.56 2004/08/14 00:26:30 djm Exp $ diff --git a/crypto/openssh-3.9p1/README.DELETED b/crypto/openssh-3.9p1/README.DELETED new file mode 100644 index 0000000000..a54fe8218d --- /dev/null +++ b/crypto/openssh-3.9p1/README.DELETED @@ -0,0 +1,141 @@ +.cvsignore +ChangeLog +Makefile.in +OVERVIEW +README.DELETED +README.platform +RFC.nroff +WARNING.RNG +acconfig.h +aclocal.m4 +config.guess +config.h.in +config.sub +configure +configure.ac +contrib +contrib/Makefile +contrib/README +contrib/aix +contrib/aix/README +contrib/aix/buildbff.sh +contrib/aix/inventory.sh +contrib/aix/pam.conf +contrib/caldera +contrib/caldera/openssh.spec +contrib/caldera/ssh-host-keygen +contrib/caldera/sshd.init +contrib/caldera/sshd.pam +contrib/cygwin +contrib/cygwin/Makefile +contrib/cygwin/README +contrib/cygwin/ssh-host-config +contrib/cygwin/ssh-user-config +contrib/findssl.sh +contrib/gnome-ssh-askpass1.c +contrib/gnome-ssh-askpass2.c +contrib/hpux +contrib/hpux/README +contrib/hpux/egd +contrib/hpux/egd.rc +contrib/hpux/sshd +contrib/hpux/sshd.rc +contrib/redhat +contrib/redhat/gnome-ssh-askpass.csh +contrib/redhat/gnome-ssh-askpass.sh +contrib/redhat/openssh.spec +contrib/redhat/sshd.init +contrib/redhat/sshd.init.old +contrib/redhat/sshd.pam +contrib/redhat/sshd.pam.old +contrib/solaris +contrib/solaris/README +contrib/solaris/buildpkg.sh +contrib/solaris/opensshd.in +contrib/ssh-copy-id +contrib/ssh-copy-id.1 +contrib/sshd.pam.freebsd +contrib/sshd.pam.generic +contrib/suse +contrib/suse/openssh.spec +contrib/suse/rc.config.sshd +contrib/suse/rc.sshd +fixpaths +fixprogs +install-sh +mdoc2man.awk +mkinstalldirs +nchan.ms +nchan2.ms +openbsd-compat/.cvsignore +openbsd-compat/Makefile.in +regress +regress/Makefile +regress/README.regress +regress/agent-getpeereid.sh +regress/agent-ptrace.sh +regress/agent-timeout.sh +regress/agent.sh +regress/banner.sh +regress/broken-pipe.sh +regress/bsd.regress.mk +regress/connect-privsep.sh +regress/connect.sh +regress/dsa_ssh2.prv +regress/dsa_ssh2.pub +regress/dynamic-forward.sh +regress/exit-status.sh +regress/forwarding.sh +regress/keygen-change.sh +regress/keyscan.sh +regress/login-timeout.sh +regress/proto-mismatch.sh +regress/proto-version.sh +regress/proxy-connect.sh +regress/reconfigure.sh +regress/rekey.sh +regress/rsa_openssh.prv +regress/rsa_openssh.pub +regress/rsa_ssh2.prv +regress/runtests.sh +regress/sftp-badcmds.sh +regress/sftp-batch.sh +regress/sftp-cmds.sh +regress/sftp.sh +regress/ssh-com-client.sh +regress/ssh-com-keygen.sh +regress/ssh-com-sftp.sh +regress/ssh-com.sh +regress/stderr-after-eof.sh +regress/stderr-data.sh +regress/t4.ok +regress/t5.ok +regress/test-exec.sh +regress/transfer.sh +regress/try-ciphers.sh +regress/yes-head.sh +scard +scard/.cvsignore +scard/Makefile.in +scard/Ssh.bin +scard/Ssh.bin.uu +scard/Ssh.java +scp.0 +sftp-server.0 +sftp.0 +ssh-add.0 +ssh-agent.0 +ssh-keygen.0 +ssh-keyscan.0 +ssh-keysign.0 +ssh-rand-helper.0 +ssh-rand-helper.8 +ssh-rand-helper.c +ssh.0 +ssh_config.0 +ssh_prng_cmds.in +sshd.0 +sshd_config.0 +stamp-h.in +version.h + diff --git a/crypto/openssh-3.9p1/README.DRAGONFLY b/crypto/openssh-3.9p1/README.DRAGONFLY new file mode 100644 index 0000000000..6f768a87c2 --- /dev/null +++ b/crypto/openssh-3.9p1/README.DRAGONFLY @@ -0,0 +1,5 @@ +Original source can be downloaded from OpenBSD at +ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-3.9p1.tar.gz + +A list of deleted files is in README.DELETED + diff --git a/crypto/openssh-3.9p1/README.dns b/crypto/openssh-3.9p1/README.dns new file mode 100644 index 0000000000..97879183e3 --- /dev/null +++ b/crypto/openssh-3.9p1/README.dns @@ -0,0 +1,47 @@ +How to verify host keys using OpenSSH and DNS +--------------------------------------------- + +OpenSSH contains support for verifying host keys using DNS as described in +draft-ietf-secsh-dns-05.txt. The document contains very brief instructions +on how to use this feature. Configuring DNS is out of the scope of this +document. + + +(1) Server: Generate and publish the DNS RR + +To create a DNS resource record (RR) containing a fingerprint of the +public host key, use the following command: + + ssh-keygen -r hostname -f keyfile -g + +where "hostname" is your fully qualified hostname and "keyfile" is the +file containing the public host key file. If you have multiple keys, +you should generate one RR for each key. + +In the example above, ssh-keygen will print the fingerprint in a +generic DNS RR format parsable by most modern name server +implementations. If your nameserver has support for the SSHFP RR +you can omit the -g flag and ssh-keygen will print a standard SSHFP RR. + +To publish the fingerprint using the DNS you must add the generated RR +to your DNS zone file and sign your zone. + + +(2) Client: Enable ssh to verify host keys using DNS + +To enable the ssh client to verify host keys using DNS, you have to +add the following option to the ssh configuration file +($HOME/.ssh/config or /etc/ssh/ssh_config): + + VerifyHostKeyDNS yes + +Upon connection the client will try to look up the fingerprint RR +using DNS. If the fingerprint received from the DNS server matches +the remote host key, the user will be notified. + + + Jakob Schlyter + Wesley Griffin + + +$OpenBSD: README.dns,v 1.2 2003/10/14 19:43:23 jakob Exp $ diff --git a/crypto/openssh-3.9p1/README.privsep b/crypto/openssh-3.9p1/README.privsep new file mode 100644 index 0000000000..32403770d2 --- /dev/null +++ b/crypto/openssh-3.9p1/README.privsep @@ -0,0 +1,64 @@ +Privilege separation, or privsep, is method in OpenSSH by which +operations that require root privilege are performed by a separate +privileged monitor process. Its purpose is to prevent privilege +escalation by containing corruption to an unprivileged process. +More information is available at: + http://www.citi.umich.edu/u/provos/ssh/privsep.html + +Privilege separation is now enabled by default; see the +UsePrivilegeSeparation option in sshd_config(5). + +On systems which lack mmap or anonymous (MAP_ANON) memory mapping, +compression must be disabled in order for privilege separation to +function. + +When privsep is enabled, during the pre-authentication phase sshd will +chroot(2) to "/var/empty" and change its privileges to the "sshd" user +and its primary group. sshd is a pseudo-account that should not be +used by other daemons, and must be locked and should contain a +"nologin" or invalid shell. + +You should do something like the following to prepare the privsep +preauth environment: + + # mkdir /var/empty + # chown root:sys /var/empty + # chmod 755 /var/empty + # groupadd sshd + # useradd -g sshd -c 'sshd privsep' -d /var/empty -s /bin/false sshd + +/var/empty should not contain any files. + +configure supports the following options to change the default +privsep user and chroot directory: + + --with-privsep-path=xxx Path for privilege separation chroot + --with-privsep-user=user Specify non-privileged user for privilege separation + +Privsep requires operating system support for file descriptor passing. +Compression will be disabled on systems without a working mmap MAP_ANON. + +PAM-enabled OpenSSH is known to function with privsep on Linux. +It does not function on HP-UX with a trusted system +configuration. + +On Cygwin, Tru64 Unix, OpenServer, and Unicos only the pre-authentication +part of privsep is supported. Post-authentication privsep is disabled +automatically (so you won't see the additional process mentioned below). + +Note that for a normal interactive login with a shell, enabling privsep +will require 1 additional process per login session. + +Given the following process listing (from HP-UX): + + UID PID PPID C STIME TTY TIME COMMAND + root 1005 1 0 10:45:17 ? 0:08 /opt/openssh/sbin/sshd -u0 + root 6917 1005 0 15:19:16 ? 0:00 sshd: stevesk [priv] + stevesk 6919 6917 0 15:19:17 ? 0:03 sshd: stevesk@2 + stevesk 6921 6919 0 15:19:17 pts/2 0:00 -bash + +process 1005 is the sshd process listening for new connections. +process 6917 is the privileged monitor process, 6919 is the user owned +sshd process and 6921 is the shell process. + +$Id: README.privsep,v 1.14 2004/06/28 03:50:36 tim Exp $ diff --git a/crypto/openssh-3.9p1/README.smartcard b/crypto/openssh-3.9p1/README.smartcard new file mode 100644 index 0000000000..fdf83ecab4 --- /dev/null +++ b/crypto/openssh-3.9p1/README.smartcard @@ -0,0 +1,93 @@ +How to use smartcards with OpenSSH? + +OpenSSH contains experimental support for authentication using +Cyberflex smartcards and TODOS card readers, in addition to the cards +with PKCS#15 structure supported by OpenSC. To enable this you +need to: + +Using libsectok: + +(1) enable sectok support in OpenSSH: + + $ ./configure --with-sectok + +(2) If you have used a previous version of ssh with your card, you + must remove the old applet and keys. + + $ sectok + sectok> login -d + sectok> junload Ssh.bin + sectok> delete 0012 + sectok> delete sh + sectok> quit + +(3) load the Java Cardlet to the Cyberflex card and set card passphrase: + + $ sectok + sectok> login -d + sectok> jload /usr/libdata/ssh/Ssh.bin + sectok> setpass + Enter new AUT0 passphrase: + Re-enter passphrase: + sectok> quit + + Do not forget the passphrase. There is no way to + recover if you do. + + IMPORTANT WARNING: If you attempt to login with the + wrong passphrase three times in a row, you will + destroy your card. + +(4) load a RSA key to the card: + + $ ssh-keygen -f /path/to/rsakey -U 1 + (where 1 is the reader number, you can also try 0) + + In spite of the name, this does not generate a key. + It just loads an already existing key on to the card. + +(5) Optional: If you don't want to use a card passphrase, change the + acl on the private key file: + + $ sectok + sectok> login -d + sectok> acl 0012 world: w + world: w + AUT0: w inval + sectok> quit + + If you do this, anyone who has access to your card + can assume your identity. This is not recommended. + + +Using OpenSC: + +(1) install OpenSC: + + Sources and instructions are available from + http://www.opensc.org/ + +(2) enable OpenSC support in OpenSSH: + + $ ./configure --with-opensc[=/path/to/opensc] [options] + +(3) load a RSA key to the card: + + Not supported yet. + + +Common operations: + +(1) tell the ssh client to use the card reader: + + $ ssh -I 1 otherhost + +(2) or tell the agent (don't forget to restart) to use the smartcard: + + $ ssh-add -s 1 + + +-markus, +Tue Jul 17 23:54:51 CEST 2001 + +$OpenBSD: README.smartcard,v 1.9 2003/11/21 11:57:02 djm Exp $ diff --git a/crypto/openssh-3.9p1/TODO b/crypto/openssh-3.9p1/TODO new file mode 100644 index 0000000000..1b1d03c430 --- /dev/null +++ b/crypto/openssh-3.9p1/TODO @@ -0,0 +1,97 @@ +Documentation: + +- Update the docs + - Update README + - Update INSTALL + - Merge INSTALL & README.privsep + +- Install FAQ? + +- General FAQ on S/Key, TIS, RSA, RSA2, DSA, etc and suggestions on when it + would be best to use them. + +- Create a Documentation/ directory? + +Programming: + +- Grep for 'XXX' comments and fix + +- Link order is incorrect for some systems using Kerberos 4 and AFS. Result + is multiple inclusion of DES symbols. Holger Trapp + reports that changing the configure + generated link order from: + -lresolv -lkrb -lz -lnsl -lutil -lkafs -lkrb -ldes -lcrypto + to: + -lresolv -lkrb -lz -lnsl -lutil -lcrypto -lkafs -lkrb -ldes + fixing the problem. + +- Write a test program that calls stat() to search for EGD/PRNGd socket + rather than use the (non-portable) "test -S". + +- More platforms for for setproctitle() emulation (testing needed) + +- Improve PAM support (a pam_lastlog module will cause sshd to exit) + and maybe support alternate forms of authentications like OPIE via + pam? + +- Improve PAM ChallengeResponseAuthentication + - Informational messages + - chauthtok + - Use different PAM service name for kbdint vs regular auth (suggest from + Solar Designer) + - Ability to select which ChallengeResponseAuthentications may be used + and order to try them in e.g. "ChallengeResponseAuthentication skey, pam" + +- Complete Tru64 SIA support + - It looks like we could merge it into the password auth code to cut down + on diff size. Maybe PAM password auth too? + +- Finish integrating kernel-level auditing code for IRIX and SOLARIS + (Gilbert.r.loomis@saic.com) + +- 64-bit builds on HP-UX 11.X (stevesk@pobox.com): + - utmp/wtmp get corrupted (something in loginrec?) + - can't build with PAM (no 64-bit libpam yet) + +Clean up configure/makefiles: +- Clean up configure.ac - There are a few double #defined variables + left to do. HAVE_LOGIN is one of them. Consider NOT looking for + information in wtmpx or utmpx or any of that stuff if it's not detected + from the start + +- Fails to compile when cross compile. (vinschen@redhat.com) + +- Replace the whole u_intXX_t evilness in acconfig.h with something better??? + - Do it in configure.ac + +- Consider splitting the u_intXX_t test for sys/bitype.h into seperate test + to allow people to (right/wrongfully) link against Bind directly. + +- Consider splitting configure.ac into seperate files which do logically + similar tests. E.g move all the type detection stuff into one file, + entropy related stuff into another. + +Packaging: +- Solaris: Update packaging scripts and build new sysv startup scripts + Ideally the package metadata should be generated by autoconf. + (gilbert.r.loomis@saic.com) + +- HP-UX: Provide DEPOT package scripts. + (gilbert.r.loomis@saic.com) + +PrivSep Issues: +- mmap() issues. + + /dev/zero solution (Solaris) + + No/broken MAP_ANON (Irix) + + broken /dev/zero parse (Linux) +- PAM + + See above PAM notes +- AIX + + usrinfo() does not set TTY, but only required for legacy systems. Works + with PrivSep. +- OSF + + SIA is broken +- Cygwin + + Privsep for Pre-auth only (no fd passing) + +$Id: TODO,v 1.57 2004/02/11 09:44:13 dtucker Exp $ diff --git a/crypto/openssh-3.9p1/acss.c b/crypto/openssh-3.9p1/acss.c new file mode 100644 index 0000000000..9364ba9fe3 --- /dev/null +++ b/crypto/openssh-3.9p1/acss.c @@ -0,0 +1,264 @@ +/* $Id: acss.c,v 1.2 2004/02/06 04:22:43 dtucker Exp $ */ +/* + * Copyright (c) 2004 The OpenBSD project + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" +#include + +#if !defined(EVP_CTRL_SET_ACSS_MODE) && (OPENSSL_VERSION_NUMBER >= 0x00906000L) + +#include "acss.h" + +/* decryption sbox */ +static unsigned char sboxdec[] = { + 0x33, 0x73, 0x3b, 0x26, 0x63, 0x23, 0x6b, 0x76, + 0x3e, 0x7e, 0x36, 0x2b, 0x6e, 0x2e, 0x66, 0x7b, + 0xd3, 0x93, 0xdb, 0x06, 0x43, 0x03, 0x4b, 0x96, + 0xde, 0x9e, 0xd6, 0x0b, 0x4e, 0x0e, 0x46, 0x9b, + 0x57, 0x17, 0x5f, 0x82, 0xc7, 0x87, 0xcf, 0x12, + 0x5a, 0x1a, 0x52, 0x8f, 0xca, 0x8a, 0xc2, 0x1f, + 0xd9, 0x99, 0xd1, 0x00, 0x49, 0x09, 0x41, 0x90, + 0xd8, 0x98, 0xd0, 0x01, 0x48, 0x08, 0x40, 0x91, + 0x3d, 0x7d, 0x35, 0x24, 0x6d, 0x2d, 0x65, 0x74, + 0x3c, 0x7c, 0x34, 0x25, 0x6c, 0x2c, 0x64, 0x75, + 0xdd, 0x9d, 0xd5, 0x04, 0x4d, 0x0d, 0x45, 0x94, + 0xdc, 0x9c, 0xd4, 0x05, 0x4c, 0x0c, 0x44, 0x95, + 0x59, 0x19, 0x51, 0x80, 0xc9, 0x89, 0xc1, 0x10, + 0x58, 0x18, 0x50, 0x81, 0xc8, 0x88, 0xc0, 0x11, + 0xd7, 0x97, 0xdf, 0x02, 0x47, 0x07, 0x4f, 0x92, + 0xda, 0x9a, 0xd2, 0x0f, 0x4a, 0x0a, 0x42, 0x9f, + 0x53, 0x13, 0x5b, 0x86, 0xc3, 0x83, 0xcb, 0x16, + 0x5e, 0x1e, 0x56, 0x8b, 0xce, 0x8e, 0xc6, 0x1b, + 0xb3, 0xf3, 0xbb, 0xa6, 0xe3, 0xa3, 0xeb, 0xf6, + 0xbe, 0xfe, 0xb6, 0xab, 0xee, 0xae, 0xe6, 0xfb, + 0x37, 0x77, 0x3f, 0x22, 0x67, 0x27, 0x6f, 0x72, + 0x3a, 0x7a, 0x32, 0x2f, 0x6a, 0x2a, 0x62, 0x7f, + 0xb9, 0xf9, 0xb1, 0xa0, 0xe9, 0xa9, 0xe1, 0xf0, + 0xb8, 0xf8, 0xb0, 0xa1, 0xe8, 0xa8, 0xe0, 0xf1, + 0x5d, 0x1d, 0x55, 0x84, 0xcd, 0x8d, 0xc5, 0x14, + 0x5c, 0x1c, 0x54, 0x85, 0xcc, 0x8c, 0xc4, 0x15, + 0xbd, 0xfd, 0xb5, 0xa4, 0xed, 0xad, 0xe5, 0xf4, + 0xbc, 0xfc, 0xb4, 0xa5, 0xec, 0xac, 0xe4, 0xf5, + 0x39, 0x79, 0x31, 0x20, 0x69, 0x29, 0x61, 0x70, + 0x38, 0x78, 0x30, 0x21, 0x68, 0x28, 0x60, 0x71, + 0xb7, 0xf7, 0xbf, 0xa2, 0xe7, 0xa7, 0xef, 0xf2, + 0xba, 0xfa, 0xb2, 0xaf, 0xea, 0xaa, 0xe2, 0xff +}; + +/* encryption sbox */ +static unsigned char sboxenc[] = { + 0x33, 0x3b, 0x73, 0x15, 0x53, 0x5b, 0x13, 0x75, + 0x3d, 0x35, 0x7d, 0x1b, 0x5d, 0x55, 0x1d, 0x7b, + 0x67, 0x6f, 0x27, 0x81, 0xc7, 0xcf, 0x87, 0x21, + 0x69, 0x61, 0x29, 0x8f, 0xc9, 0xc1, 0x89, 0x2f, + 0xe3, 0xeb, 0xa3, 0x05, 0x43, 0x4b, 0x03, 0xa5, + 0xed, 0xe5, 0xad, 0x0b, 0x4d, 0x45, 0x0d, 0xab, + 0xea, 0xe2, 0xaa, 0x00, 0x4a, 0x42, 0x0a, 0xa0, + 0xe8, 0xe0, 0xa8, 0x02, 0x48, 0x40, 0x08, 0xa2, + 0x3e, 0x36, 0x7e, 0x14, 0x5e, 0x56, 0x1e, 0x74, + 0x3c, 0x34, 0x7c, 0x16, 0x5c, 0x54, 0x1c, 0x76, + 0x6a, 0x62, 0x2a, 0x80, 0xca, 0xc2, 0x8a, 0x20, + 0x68, 0x60, 0x28, 0x82, 0xc8, 0xc0, 0x88, 0x22, + 0xee, 0xe6, 0xae, 0x04, 0x4e, 0x46, 0x0e, 0xa4, + 0xec, 0xe4, 0xac, 0x06, 0x4c, 0x44, 0x0c, 0xa6, + 0xe7, 0xef, 0xa7, 0x01, 0x47, 0x4f, 0x07, 0xa1, + 0xe9, 0xe1, 0xa9, 0x0f, 0x49, 0x41, 0x09, 0xaf, + 0x63, 0x6b, 0x23, 0x85, 0xc3, 0xcb, 0x83, 0x25, + 0x6d, 0x65, 0x2d, 0x8b, 0xcd, 0xc5, 0x8d, 0x2b, + 0x37, 0x3f, 0x77, 0x11, 0x57, 0x5f, 0x17, 0x71, + 0x39, 0x31, 0x79, 0x1f, 0x59, 0x51, 0x19, 0x7f, + 0xb3, 0xbb, 0xf3, 0x95, 0xd3, 0xdb, 0x93, 0xf5, + 0xbd, 0xb5, 0xfd, 0x9b, 0xdd, 0xd5, 0x9d, 0xfb, + 0xba, 0xb2, 0xfa, 0x90, 0xda, 0xd2, 0x9a, 0xf0, + 0xb8, 0xb0, 0xf8, 0x92, 0xd8, 0xd0, 0x98, 0xf2, + 0x6e, 0x66, 0x2e, 0x84, 0xce, 0xc6, 0x8e, 0x24, + 0x6c, 0x64, 0x2c, 0x86, 0xcc, 0xc4, 0x8c, 0x26, + 0x3a, 0x32, 0x7a, 0x10, 0x5a, 0x52, 0x1a, 0x70, + 0x38, 0x30, 0x78, 0x12, 0x58, 0x50, 0x18, 0x72, + 0xbe, 0xb6, 0xfe, 0x94, 0xde, 0xd6, 0x9e, 0xf4, + 0xbc, 0xb4, 0xfc, 0x96, 0xdc, 0xd4, 0x9c, 0xf6, + 0xb7, 0xbf, 0xf7, 0x91, 0xd7, 0xdf, 0x97, 0xf1, + 0xb9, 0xb1, 0xf9, 0x9f, 0xd9, 0xd1, 0x99, 0xff +}; + +static unsigned char reverse[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +/* + * Two linear feedback shift registers are used: + * + * lfsr17: polynomial of degree 17, primitive modulo 2 (listed in Schneier) + * x^15 + x + 1 + * lfsr25: polynomial of degree 25, not know if primitive modulo 2 + * x^13 + x^5 + x^4 + x^1 + 1 + * + * Output bits are discarded, instead the feedback bits are added to produce + * the cipher stream. Depending on the mode, feedback bytes may be inverted + * bit-wise before addition. + * + * The lfsrs are seeded with bytes from the raw key: + * + * lfsr17: byte 0[0:7] at bit 9 + * byte 1[0:7] at bit 0 + * + * lfsr25: byte 2[0:4] at bit 16 + * byte 2[5:7] at bit 22 + * byte 3[0:7] at bit 8 + * byte 4[0:7] at bit 0 + * + * To prevent 0 cycles, 1's are inject at bit 8 in lfrs17 and bit 21 in + * lfsr25. + * + */ + +int +acss(ACSS_KEY *key, unsigned long len, const unsigned char *in, + unsigned char *out) +{ + unsigned long i; + unsigned long lfsr17tmp, lfsr25tmp, lfsrsumtmp; + + lfsrsumtmp = lfsr17tmp = lfsr25tmp = 0; + + /* keystream is sum of lfsrs */ + for (i = 0; i < len; i++) { + lfsr17tmp = key->lfsr17 ^ (key->lfsr17 >> 14); + key->lfsr17 = (key->lfsr17 >> 8) + ^ (lfsr17tmp << 9) + ^ (lfsr17tmp << 12) + ^ (lfsr17tmp << 15); + key->lfsr17 &= 0x1ffff; /* 17 bit LFSR */ + + lfsr25tmp = key->lfsr25 + ^ (key->lfsr25 >> 3) + ^ (key->lfsr25 >> 4) + ^ (key->lfsr25 >> 12); + key->lfsr25 = (key->lfsr25 >> 8) ^ (lfsr25tmp << 17); + key->lfsr25 &= 0x1ffffff; /* 25 bit LFSR */ + + lfsrsumtmp = key->lfsrsum; + + /* addition */ + switch (key->mode) { + case ACSS_AUTHENTICATE: + case ACSS_DATA: + key->lfsrsum = 0xff & ~(key->lfsr17 >> 9); + key->lfsrsum += key->lfsr25 >> 17; + break; + case ACSS_SESSIONKEY: + key->lfsrsum = key->lfsr17 >> 9; + key->lfsrsum += key->lfsr25 >> 17; + break; + case ACSS_TITLEKEY: + key->lfsrsum = key->lfsr17 >> 9; + key->lfsrsum += 0xff & ~(key->lfsr25 >> 17); + break; + default: + return 1; + } + key->lfsrsum += (lfsrsumtmp >> 8); + + if (key->encrypt) { + out[i] = sboxenc[(in[i] ^ key->lfsrsum) & 0xff]; + } else { + out[i] = (sboxdec[in[i]] ^ key->lfsrsum) & 0xff; + } + } + + return 0; +} + +static void +acss_seed(ACSS_KEY *key) +{ + int i; + + /* if available, mangle with subkey */ + if (key->subkey_avilable) { + for (i = 0; i < ACSS_KEYSIZE; i++) + key->seed[i] = reverse[key->data[i] ^ key->subkey[i]]; + } else { + for (i = 0; i < ACSS_KEYSIZE; i++) + key->seed[i] = reverse[key->data[i]]; + } + + /* seed lfsrs */ + key->lfsr17 = key->seed[1] + | (key->seed[0] << 9) + | (1 << 8); /* inject 1 at bit 9 */ + key->lfsr25 = key->seed[4] + | (key->seed[3] << 8) + | ((key->seed[2] & 0x1f) << 16) + | ((key->seed[2] & 0xe0) << 17) + | (1 << 21); /* inject 1 at bit 22 */ + + key->lfsrsum = 0; +} + +void +acss_setkey(ACSS_KEY *key, const unsigned char *data, int enc, int mode) +{ + memcpy(key->data, data, sizeof(key->data)); + memset(key->subkey, 0, sizeof(key->subkey)); + + if (enc != -1) + key->encrypt = enc; + key->mode = mode; + key->subkey_avilable = 0; + + acss_seed(key); +} + +void +acss_setsubkey(ACSS_KEY *key, const unsigned char *subkey) +{ + memcpy(key->subkey, subkey, sizeof(key->subkey)); + key->subkey_avilable = 1; + acss_seed(key); +} +#endif diff --git a/crypto/openssh-3.9p1/acss.h b/crypto/openssh-3.9p1/acss.h new file mode 100644 index 0000000000..91b4895423 --- /dev/null +++ b/crypto/openssh-3.9p1/acss.h @@ -0,0 +1,47 @@ +/* $Id: acss.h,v 1.2 2004/02/06 04:22:43 dtucker Exp $ */ +/* + * Copyright (c) 2004 The OpenBSD project + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _ACSS_H_ +#define _ACSS_H_ + +/* 40bit key */ +#define ACSS_KEYSIZE 5 + +/* modes of acss */ +#define ACSS_AUTHENTICATE 0 +#define ACSS_SESSIONKEY 1 +#define ACSS_TITLEKEY 2 +#define ACSS_DATA 3 + +typedef struct acss_key_st { + unsigned int lfsr17; /* current state of lfsrs */ + unsigned int lfsr25; + unsigned int lfsrsum; + unsigned char seed[ACSS_KEYSIZE]; + unsigned char data[ACSS_KEYSIZE]; + unsigned char subkey[ACSS_KEYSIZE]; + int encrypt; /* XXX make these bit flags? */ + int mode; + int seeded; + int subkey_avilable; +} ACSS_KEY; + +void acss_setkey(ACSS_KEY *, const unsigned char *, int, int); +void acss_setsubkey(ACSS_KEY *, const unsigned char *); +int acss(ACSS_KEY *, unsigned long, const unsigned char *, unsigned char *); + +#endif /* ifndef _ACSS_H_ */ diff --git a/crypto/openssh-3.9p1/atomicio.c b/crypto/openssh-3.9p1/atomicio.c new file mode 100644 index 0000000000..7637e16719 --- /dev/null +++ b/crypto/openssh-3.9p1/atomicio.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: atomicio.c,v 1.12 2003/07/31 15:50:16 avsm Exp $"); + +#include "atomicio.h" + +/* + * ensure all of data on socket comes through. f==read || f==vwrite + */ +ssize_t +atomicio(f, fd, _s, n) + ssize_t (*f) (int, void *, size_t); + int fd; + void *_s; + size_t n; +{ + char *s = _s; + ssize_t res, pos = 0; + + while (n > pos) { + res = (f) (fd, s + pos, n - pos); + switch (res) { + case -1: +#ifdef EWOULDBLOCK + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) +#else + if (errno == EINTR || errno == EAGAIN) +#endif + continue; + case 0: + return (res); + default: + pos += res; + } + } + return (pos); +} diff --git a/crypto/openssh-3.9p1/atomicio.h b/crypto/openssh-3.9p1/atomicio.h new file mode 100644 index 0000000000..5c0f392eff --- /dev/null +++ b/crypto/openssh-3.9p1/atomicio.h @@ -0,0 +1,33 @@ +/* $OpenBSD: atomicio.h,v 1.5 2003/06/28 16:23:06 deraadt Exp $ */ + +/* + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Ensure all of data on socket comes through. f==read || f==vwrite + */ +ssize_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); + +#define vwrite (ssize_t (*)(int, void *, size_t))write diff --git a/crypto/openssh-3.9p1/auth-bsdauth.c b/crypto/openssh-3.9p1/auth-bsdauth.c new file mode 100644 index 0000000000..2ac27a7a20 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-bsdauth.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: auth-bsdauth.c,v 1.5 2002/06/30 21:59:45 deraadt Exp $"); + +#ifdef BSD_AUTH +#include "xmalloc.h" +#include "auth.h" +#include "log.h" +#include "monitor_wrap.h" + +static void * +bsdauth_init_ctx(Authctxt *authctxt) +{ + return authctxt; +} + +int +bsdauth_query(void *ctx, char **name, char **infotxt, + u_int *numprompts, char ***prompts, u_int **echo_on) +{ + Authctxt *authctxt = ctx; + char *challenge = NULL; + + if (authctxt->as != NULL) { + debug2("bsdauth_query: try reuse session"); + challenge = auth_getitem(authctxt->as, AUTHV_CHALLENGE); + if (challenge == NULL) { + auth_close(authctxt->as); + authctxt->as = NULL; + } + } + + if (challenge == NULL) { + debug2("bsdauth_query: new bsd auth session"); + debug3("bsdauth_query: style %s", + authctxt->style ? authctxt->style : ""); + authctxt->as = auth_userchallenge(authctxt->user, + authctxt->style, "auth-ssh", &challenge); + if (authctxt->as == NULL) + challenge = NULL; + debug2("bsdauth_query: <%s>", challenge ? challenge : "empty"); + } + + if (challenge == NULL) + return -1; + + *name = xstrdup(""); + *infotxt = xstrdup(""); + *numprompts = 1; + *prompts = xmalloc(*numprompts * sizeof(char *)); + *echo_on = xmalloc(*numprompts * sizeof(u_int)); + (*echo_on)[0] = 0; + (*prompts)[0] = xstrdup(challenge); + + return 0; +} + +int +bsdauth_respond(void *ctx, u_int numresponses, char **responses) +{ + Authctxt *authctxt = ctx; + int authok; + + if (authctxt->as == 0) + error("bsdauth_respond: no bsd auth session"); + + if (numresponses != 1) + return -1; + + authok = auth_userresponse(authctxt->as, responses[0], 0); + authctxt->as = NULL; + debug3("bsdauth_respond: <%s> = <%d>", responses[0], authok); + + return (authok == 0) ? -1 : 0; +} + +static void +bsdauth_free_ctx(void *ctx) +{ + Authctxt *authctxt = ctx; + + if (authctxt && authctxt->as) { + auth_close(authctxt->as); + authctxt->as = NULL; + } +} + +KbdintDevice bsdauth_device = { + "bsdauth", + bsdauth_init_ctx, + bsdauth_query, + bsdauth_respond, + bsdauth_free_ctx +}; + +KbdintDevice mm_bsdauth_device = { + "bsdauth", + bsdauth_init_ctx, + mm_bsdauth_query, + mm_bsdauth_respond, + bsdauth_free_ctx +}; +#endif diff --git a/crypto/openssh-3.9p1/auth-chall.c b/crypto/openssh-3.9p1/auth-chall.c new file mode 100644 index 0000000000..a9d314dd2a --- /dev/null +++ b/crypto/openssh-3.9p1/auth-chall.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth-chall.c,v 1.9 2003/11/03 09:03:37 djm Exp $"); + +#include "auth.h" +#include "log.h" +#include "xmalloc.h" + +/* limited protocol v1 interface to kbd-interactive authentication */ + +extern KbdintDevice *devices[]; +static KbdintDevice *device; + +char * +get_challenge(Authctxt *authctxt) +{ + char *challenge, *name, *info, **prompts; + u_int i, numprompts; + u_int *echo_on; + + device = devices[0]; /* we always use the 1st device for protocol 1 */ + if (device == NULL) + return NULL; + if ((authctxt->kbdintctxt = device->init_ctx(authctxt)) == NULL) + return NULL; + if (device->query(authctxt->kbdintctxt, &name, &info, + &numprompts, &prompts, &echo_on)) { + device->free_ctx(authctxt->kbdintctxt); + authctxt->kbdintctxt = NULL; + return NULL; + } + if (numprompts < 1) + fatal("get_challenge: numprompts < 1"); + challenge = xstrdup(prompts[0]); + for (i = 0; i < numprompts; i++) + xfree(prompts[i]); + xfree(prompts); + xfree(name); + xfree(echo_on); + xfree(info); + + return (challenge); +} +int +verify_response(Authctxt *authctxt, const char *response) +{ + char *resp[1], *name, *info, **prompts; + u_int i, numprompts, *echo_on; + int authenticated = 0; + + if (device == NULL) + return 0; + if (authctxt->kbdintctxt == NULL) + return 0; + resp[0] = (char *)response; + switch (device->respond(authctxt->kbdintctxt, 1, resp)) { + case 0: /* Success */ + authenticated = 1; + break; + case 1: /* Postponed - retry with empty query for PAM */ + if ((device->query(authctxt->kbdintctxt, &name, &info, + &numprompts, &prompts, &echo_on)) != 0) + break; + if (numprompts == 0 && + device->respond(authctxt->kbdintctxt, 0, resp) == 0) + authenticated = 1; + + for (i = 0; i < numprompts; i++) + xfree(prompts[i]); + xfree(prompts); + xfree(name); + xfree(echo_on); + xfree(info); + break; + } + device->free_ctx(authctxt->kbdintctxt); + authctxt->kbdintctxt = NULL; + return authenticated; +} +void +abandon_challenge_response(Authctxt *authctxt) +{ + if (authctxt->kbdintctxt != NULL) { + device->free_ctx(authctxt->kbdintctxt); + authctxt->kbdintctxt = NULL; + } +} diff --git a/crypto/openssh-3.9p1/auth-krb5.c b/crypto/openssh-3.9p1/auth-krb5.c new file mode 100644 index 0000000000..a324ff15c0 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-krb5.c @@ -0,0 +1,232 @@ +/* + * Kerberos v5 authentication and ticket-passing routines. + * + * $FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar Exp $ + */ +/* + * Copyright (c) 2002 Daniel Kouril. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth-krb5.c,v 1.15 2003/11/21 11:57:02 djm Exp $"); + +#include "ssh.h" +#include "ssh1.h" +#include "packet.h" +#include "xmalloc.h" +#include "log.h" +#include "servconf.h" +#include "uidswap.h" +#include "auth.h" + +#ifdef KRB5 +#include + +extern ServerOptions options; + +static int +krb5_init(void *context) +{ + Authctxt *authctxt = (Authctxt *)context; + krb5_error_code problem; + + if (authctxt->krb5_ctx == NULL) { + problem = krb5_init_context(&authctxt->krb5_ctx); + if (problem) + return (problem); +#ifdef KRB5_INIT_ETS + krb5_init_ets(authctxt->krb5_ctx); +#endif + } + return (0); +} + +int +auth_krb5_password(Authctxt *authctxt, const char *password) +{ +#ifndef HEIMDAL + krb5_creds creds; + krb5_principal server; + char ccname[40]; + int tmpfd; + mode_t old_umask; +#endif + krb5_error_code problem; + krb5_ccache ccache = NULL; + int len; + + if (!authctxt->valid) + return (0); + + temporarily_use_uid(authctxt->pw); + + problem = krb5_init(authctxt); + if (problem) + goto out; + + problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, + &authctxt->krb5_user); + if (problem) + goto out; + +#ifdef HEIMDAL + problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); + if (problem) + goto out; + + problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, + authctxt->krb5_user); + if (problem) + goto out; + + restore_uid(); + + problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, + ccache, password, 1, NULL); + + temporarily_use_uid(authctxt->pw); + + if (problem) + goto out; + + problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, + &authctxt->krb5_fwd_ccache); + if (problem) + goto out; + + problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, + authctxt->krb5_fwd_ccache); + krb5_cc_destroy(authctxt->krb5_ctx, ccache); + ccache = NULL; + if (problem) + goto out; + +#else + problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, + authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL); + if (problem) + goto out; + + problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, + KRB5_NT_SRV_HST, &server); + if (problem) + goto out; + + restore_uid(); + problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, + NULL, NULL, NULL); + krb5_free_principal(authctxt->krb5_ctx, server); + temporarily_use_uid(authctxt->pw); + if (problem) + goto out; + + if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, + authctxt->pw->pw_name)) { + problem = -1; + goto out; + } + + snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid()); + + old_umask = umask(0177); + tmpfd = mkstemp(ccname + strlen("FILE:")); + umask(old_umask); + if (tmpfd == -1) { + logit("mkstemp(): %.100s", strerror(errno)); + problem = errno; + goto out; + } + + if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { + logit("fchmod(): %.100s", strerror(errno)); + close(tmpfd); + problem = errno; + goto out; + } + close(tmpfd); + + problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &authctxt->krb5_fwd_ccache); + if (problem) + goto out; + + problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, + authctxt->krb5_user); + if (problem) + goto out; + + problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, + &creds); + if (problem) + goto out; +#endif + + authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); + + len = strlen(authctxt->krb5_ticket_file) + 6; + authctxt->krb5_ccname = xmalloc(len); + snprintf(authctxt->krb5_ccname, len, "FILE:%s", + authctxt->krb5_ticket_file); + + out: + restore_uid(); + + if (problem) { + if (ccache) + krb5_cc_destroy(authctxt->krb5_ctx, ccache); + + if (authctxt->krb5_ctx != NULL && problem!=-1) + debug("Kerberos password authentication failed: %s", + krb5_get_err_text(authctxt->krb5_ctx, problem)); + else + debug("Kerberos password authentication failed: %d", + problem); + + krb5_cleanup_proc(authctxt); + + if (options.kerberos_or_local_passwd) + return (-1); + else + return (0); + } + return (1); +} + +void +krb5_cleanup_proc(Authctxt *authctxt) +{ + debug("krb5_cleanup_proc called"); + if (authctxt->krb5_fwd_ccache) { + krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); + authctxt->krb5_fwd_ccache = NULL; + } + if (authctxt->krb5_user) { + krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); + authctxt->krb5_user = NULL; + } + if (authctxt->krb5_ctx) { + krb5_free_context(authctxt->krb5_ctx); + authctxt->krb5_ctx = NULL; + } +} + +#endif /* KRB5 */ diff --git a/crypto/openssh-3.9p1/auth-options.c b/crypto/openssh-3.9p1/auth-options.c new file mode 100644 index 0000000000..0e146ab158 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-options.c @@ -0,0 +1,300 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: auth-options.c,v 1.28 2003/06/02 09:17:34 markus Exp $"); + +#include "xmalloc.h" +#include "match.h" +#include "log.h" +#include "canohost.h" +#include "channels.h" +#include "auth-options.h" +#include "servconf.h" +#include "misc.h" +#include "monitor_wrap.h" +#include "auth.h" + +/* Flags set authorized_keys flags */ +int no_port_forwarding_flag = 0; +int no_agent_forwarding_flag = 0; +int no_x11_forwarding_flag = 0; +int no_pty_flag = 0; + +/* "command=" option. */ +char *forced_command = NULL; + +/* "environment=" options. */ +struct envstring *custom_environment = NULL; + +extern ServerOptions options; + +void +auth_clear_options(void) +{ + no_agent_forwarding_flag = 0; + no_port_forwarding_flag = 0; + no_pty_flag = 0; + no_x11_forwarding_flag = 0; + while (custom_environment) { + struct envstring *ce = custom_environment; + custom_environment = ce->next; + xfree(ce->s); + xfree(ce); + } + if (forced_command) { + xfree(forced_command); + forced_command = NULL; + } + channel_clear_permitted_opens(); + auth_debug_reset(); +} + +/* + * return 1 if access is granted, 0 if not. + * side effect: sets key option flags + */ +int +auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum) +{ + const char *cp; + int i; + + /* reset options */ + auth_clear_options(); + + if (!opts) + return 1; + + while (*opts && *opts != ' ' && *opts != '\t') { + cp = "no-port-forwarding"; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + auth_debug_add("Port forwarding disabled."); + no_port_forwarding_flag = 1; + opts += strlen(cp); + goto next_option; + } + cp = "no-agent-forwarding"; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + auth_debug_add("Agent forwarding disabled."); + no_agent_forwarding_flag = 1; + opts += strlen(cp); + goto next_option; + } + cp = "no-X11-forwarding"; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + auth_debug_add("X11 forwarding disabled."); + no_x11_forwarding_flag = 1; + opts += strlen(cp); + goto next_option; + } + cp = "no-pty"; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + auth_debug_add("Pty allocation disabled."); + no_pty_flag = 1; + opts += strlen(cp); + goto next_option; + } + cp = "command=\""; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + opts += strlen(cp); + forced_command = xmalloc(strlen(opts) + 1); + i = 0; + while (*opts) { + if (*opts == '"') + break; + if (*opts == '\\' && opts[1] == '"') { + opts += 2; + forced_command[i++] = '"'; + continue; + } + forced_command[i++] = *opts++; + } + if (!*opts) { + debug("%.100s, line %lu: missing end quote", + file, linenum); + auth_debug_add("%.100s, line %lu: missing end quote", + file, linenum); + xfree(forced_command); + forced_command = NULL; + goto bad_option; + } + forced_command[i] = 0; + auth_debug_add("Forced command: %.900s", forced_command); + opts++; + goto next_option; + } + cp = "environment=\""; + if (options.permit_user_env && + strncasecmp(opts, cp, strlen(cp)) == 0) { + char *s; + struct envstring *new_envstring; + + opts += strlen(cp); + s = xmalloc(strlen(opts) + 1); + i = 0; + while (*opts) { + if (*opts == '"') + break; + if (*opts == '\\' && opts[1] == '"') { + opts += 2; + s[i++] = '"'; + continue; + } + s[i++] = *opts++; + } + if (!*opts) { + debug("%.100s, line %lu: missing end quote", + file, linenum); + auth_debug_add("%.100s, line %lu: missing end quote", + file, linenum); + xfree(s); + goto bad_option; + } + s[i] = 0; + auth_debug_add("Adding to environment: %.900s", s); + debug("Adding to environment: %.900s", s); + opts++; + new_envstring = xmalloc(sizeof(struct envstring)); + new_envstring->s = s; + new_envstring->next = custom_environment; + custom_environment = new_envstring; + goto next_option; + } + cp = "from=\""; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + const char *remote_ip = get_remote_ipaddr(); + const char *remote_host = get_canonical_hostname( + options.use_dns); + char *patterns = xmalloc(strlen(opts) + 1); + + opts += strlen(cp); + i = 0; + while (*opts) { + if (*opts == '"') + break; + if (*opts == '\\' && opts[1] == '"') { + opts += 2; + patterns[i++] = '"'; + continue; + } + patterns[i++] = *opts++; + } + if (!*opts) { + debug("%.100s, line %lu: missing end quote", + file, linenum); + auth_debug_add("%.100s, line %lu: missing end quote", + file, linenum); + xfree(patterns); + goto bad_option; + } + patterns[i] = 0; + opts++; + if (match_host_and_ip(remote_host, remote_ip, + patterns) != 1) { + xfree(patterns); + logit("Authentication tried for %.100s with " + "correct key but not from a permitted " + "host (host=%.200s, ip=%.200s).", + pw->pw_name, remote_host, remote_ip); + auth_debug_add("Your host '%.200s' is not " + "permitted to use this key for login.", + remote_host); + /* deny access */ + return 0; + } + xfree(patterns); + /* Host name matches. */ + goto next_option; + } + cp = "permitopen=\""; + if (strncasecmp(opts, cp, strlen(cp)) == 0) { + char host[256], sport[6]; + u_short port; + char *patterns = xmalloc(strlen(opts) + 1); + + opts += strlen(cp); + i = 0; + while (*opts) { + if (*opts == '"') + break; + if (*opts == '\\' && opts[1] == '"') { + opts += 2; + patterns[i++] = '"'; + continue; + } + patterns[i++] = *opts++; + } + if (!*opts) { + debug("%.100s, line %lu: missing end quote", + file, linenum); + auth_debug_add("%.100s, line %lu: missing end quote", + file, linenum); + xfree(patterns); + goto bad_option; + } + patterns[i] = 0; + opts++; + if (sscanf(patterns, "%255[^:]:%5[0-9]", host, sport) != 2 && + sscanf(patterns, "%255[^/]/%5[0-9]", host, sport) != 2) { + debug("%.100s, line %lu: Bad permitopen specification " + "<%.100s>", file, linenum, patterns); + auth_debug_add("%.100s, line %lu: " + "Bad permitopen specification", file, linenum); + xfree(patterns); + goto bad_option; + } + if ((port = a2port(sport)) == 0) { + debug("%.100s, line %lu: Bad permitopen port <%.100s>", + file, linenum, sport); + auth_debug_add("%.100s, line %lu: " + "Bad permitopen port", file, linenum); + xfree(patterns); + goto bad_option; + } + if (options.allow_tcp_forwarding) + channel_add_permitted_opens(host, port); + xfree(patterns); + goto next_option; + } +next_option: + /* + * Skip the comma, and move to the next option + * (or break out if there are no more). + */ + if (!*opts) + fatal("Bugs in auth-options.c option processing."); + if (*opts == ' ' || *opts == '\t') + break; /* End of options. */ + if (*opts != ',') + goto bad_option; + opts++; + /* Process the next option. */ + } + + if (!use_privsep) + auth_debug_send(); + + /* grant access */ + return 1; + +bad_option: + logit("Bad options in %.100s file, line %lu: %.50s", + file, linenum, opts); + auth_debug_add("Bad options in %.100s file, line %lu: %.50s", + file, linenum, opts); + + if (!use_privsep) + auth_debug_send(); + + /* deny access */ + return 0; +} diff --git a/crypto/openssh-3.9p1/auth-options.h b/crypto/openssh-3.9p1/auth-options.h new file mode 100644 index 0000000000..15fb21255e --- /dev/null +++ b/crypto/openssh-3.9p1/auth-options.h @@ -0,0 +1,35 @@ +/* $OpenBSD: auth-options.h,v 1.12 2002/07/21 18:34:43 stevesk Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#ifndef AUTH_OPTIONS_H +#define AUTH_OPTIONS_H + +/* Linked list of custom environment strings */ +struct envstring { + struct envstring *next; + char *s; +}; + +/* Flags that may be set in authorized_keys options. */ +extern int no_port_forwarding_flag; +extern int no_agent_forwarding_flag; +extern int no_x11_forwarding_flag; +extern int no_pty_flag; +extern char *forced_command; +extern struct envstring *custom_environment; + +int auth_parse_options(struct passwd *, char *, char *, u_long); +void auth_clear_options(void); + +#endif diff --git a/crypto/openssh-3.9p1/auth-pam.c b/crypto/openssh-3.9p1/auth-pam.c new file mode 100644 index 0000000000..b93241f489 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-pam.c @@ -0,0 +1,1115 @@ +/*- + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by ThinkSec AS and + * NAI Labs, the Security Research Division of Network Associates, Inc. + * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the + * DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + */ +/* + * Copyright (c) 2003,2004 Damien Miller + * Copyright (c) 2003,2004 Darren Tucker + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Based on $FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */ +#include "includes.h" +RCSID("$Id: auth-pam.c,v 1.114 2004/08/16 13:12:06 dtucker Exp $"); + +#ifdef USE_PAM +#if defined(HAVE_SECURITY_PAM_APPL_H) +#include +#elif defined (HAVE_PAM_PAM_APPL_H) +#include +#endif + +#include "auth.h" +#include "auth-pam.h" +#include "buffer.h" +#include "bufaux.h" +#include "canohost.h" +#include "log.h" +#include "monitor_wrap.h" +#include "msg.h" +#include "packet.h" +#include "misc.h" +#include "servconf.h" +#include "ssh2.h" +#include "xmalloc.h" +#include "auth-options.h" + +extern ServerOptions options; +extern Buffer loginmsg; +extern int compat20; +extern u_int utmp_len; + +#ifdef USE_POSIX_THREADS +#include +/* + * Avoid namespace clash when *not* using pthreads for systems *with* + * pthreads, which unconditionally define pthread_t via sys/types.h + * (e.g. Linux) + */ +typedef pthread_t sp_pthread_t; +#else +typedef pid_t sp_pthread_t; +#endif + +struct pam_ctxt { + sp_pthread_t pam_thread; + int pam_psock; + int pam_csock; + int pam_done; +}; + +static void sshpam_free_ctx(void *); +static struct pam_ctxt *cleanup_ctxt; + +#ifndef USE_POSIX_THREADS +/* + * Simulate threads with processes. + */ + +static int sshpam_thread_status = -1; +static mysig_t sshpam_oldsig; + +static void +sshpam_sigchld_handler(int sig) +{ + signal(SIGCHLD, SIG_DFL); + if (cleanup_ctxt == NULL) + return; /* handler called after PAM cleanup, shouldn't happen */ + if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG) + <= 0) { + /* PAM thread has not exitted, privsep slave must have */ + kill(cleanup_ctxt->pam_thread, SIGTERM); + if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0) + <= 0) + return; /* could not wait */ + } + if (WIFSIGNALED(sshpam_thread_status) && + WTERMSIG(sshpam_thread_status) == SIGTERM) + return; /* terminated by pthread_cancel */ + if (!WIFEXITED(sshpam_thread_status)) + fatal("PAM: authentication thread exited unexpectedly"); + if (WEXITSTATUS(sshpam_thread_status) != 0) + fatal("PAM: authentication thread exited uncleanly"); +} + +static void +pthread_exit(void *value __unused) +{ + _exit(0); +} + +static int +pthread_create(sp_pthread_t *thread, const void *attr __unused, + void *(*thread_start)(void *), void *arg) +{ + pid_t pid; + + sshpam_thread_status = -1; + switch ((pid = fork())) { + case -1: + error("fork(): %s", strerror(errno)); + return (-1); + case 0: + thread_start(arg); + _exit(1); + default: + *thread = pid; + sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler); + return (0); + } +} + +static int +pthread_cancel(sp_pthread_t thread) +{ + signal(SIGCHLD, sshpam_oldsig); + return (kill(thread, SIGTERM)); +} + +static int +pthread_join(sp_pthread_t thread, void **value __unused) +{ + int status; + + if (sshpam_thread_status != -1) + return (sshpam_thread_status); + signal(SIGCHLD, sshpam_oldsig); + waitpid(thread, &status, 0); + return (status); +} +#endif + + +static pam_handle_t *sshpam_handle = NULL; +static int sshpam_err = 0; +static int sshpam_authenticated = 0; +static int sshpam_session_open = 0; +static int sshpam_cred_established = 0; +static int sshpam_account_status = -1; +static char **sshpam_env = NULL; +static Authctxt *sshpam_authctxt = NULL; +static const char *sshpam_password = NULL; + +/* Some PAM implementations don't implement this */ +#ifndef HAVE_PAM_GETENVLIST +static char ** +pam_getenvlist(pam_handle_t *pamh) +{ + /* + * XXX - If necessary, we can still support envrionment passing + * for platforms without pam_getenvlist by searching for known + * env vars (e.g. KRB5CCNAME) from the PAM environment. + */ + return NULL; +} +#endif + +/* + * Some platforms, notably Solaris, do not enforce password complexity + * rules during pam_chauthtok() if the real uid of the calling process + * is 0, on the assumption that it's being called by "passwd" run by root. + * This wraps pam_chauthtok and sets/restore the real uid so PAM will do + * the right thing. + */ +#ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID +static int +sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags) +{ + int result; + + if (sshpam_authctxt == NULL) + fatal("PAM: sshpam_authctxt not initialized"); + if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1) + fatal("%s: setreuid failed: %s", __func__, strerror(errno)); + result = pam_chauthtok(pamh, flags); + if (setreuid(0, -1) == -1) + fatal("%s: setreuid failed: %s", __func__, strerror(errno)); + return result; +} +# define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b))) +#endif + +void +sshpam_password_change_required(int reqd) +{ + debug3("%s %d", __func__, reqd); + if (sshpam_authctxt == NULL) + fatal("%s: PAM authctxt not initialized", __func__); + sshpam_authctxt->force_pwchange = reqd; + if (reqd) { + no_port_forwarding_flag |= 2; + no_agent_forwarding_flag |= 2; + no_x11_forwarding_flag |= 2; + } else { + no_port_forwarding_flag &= ~2; + no_agent_forwarding_flag &= ~2; + no_x11_forwarding_flag &= ~2; + } +} + +/* Import regular and PAM environment from subprocess */ +static void +import_environments(Buffer *b) +{ + char *env; + u_int i, num_env; + int err; + + debug3("PAM: %s entering", __func__); + +#ifndef USE_POSIX_THREADS + /* Import variables set by do_pam_account */ + sshpam_account_status = buffer_get_int(b); + sshpam_password_change_required(buffer_get_int(b)); + + /* Import environment from subprocess */ + num_env = buffer_get_int(b); + sshpam_env = xmalloc((num_env + 1) * sizeof(*sshpam_env)); + debug3("PAM: num env strings %d", num_env); + for(i = 0; i < num_env; i++) + sshpam_env[i] = buffer_get_string(b, NULL); + + sshpam_env[num_env] = NULL; + + /* Import PAM environment from subprocess */ + num_env = buffer_get_int(b); + debug("PAM: num PAM env strings %d", num_env); + for(i = 0; i < num_env; i++) { + env = buffer_get_string(b, NULL); + +#ifdef HAVE_PAM_PUTENV + /* Errors are not fatal here */ + if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) { + error("PAM: pam_putenv: %s", + pam_strerror(sshpam_handle, sshpam_err)); + } +#endif + } +#endif +} + +/* + * Conversation function for authentication thread. + */ +static int +sshpam_thread_conv(int n, struct pam_message **msg, + struct pam_response **resp, void *data) +{ + Buffer buffer; + struct pam_ctxt *ctxt; + struct pam_response *reply; + int i; + + debug3("PAM: %s entering, %d messages", __func__, n); + *resp = NULL; + + if (data == NULL) { + error("PAM: conversation function passed a null context"); + return (PAM_CONV_ERR); + } + ctxt = data; + if (n <= 0 || n > PAM_MAX_NUM_MSG) + return (PAM_CONV_ERR); + + if ((reply = malloc(n * sizeof(*reply))) == NULL) + return (PAM_CONV_ERR); + memset(reply, 0, n * sizeof(*reply)); + + buffer_init(&buffer); + for (i = 0; i < n; ++i) { + switch (PAM_MSG_MEMBER(msg, i, msg_style)) { + case PAM_PROMPT_ECHO_OFF: + buffer_put_cstring(&buffer, + PAM_MSG_MEMBER(msg, i, msg)); + if (ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) + goto fail; + if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) + goto fail; + if (buffer_get_char(&buffer) != PAM_AUTHTOK) + goto fail; + reply[i].resp = buffer_get_string(&buffer, NULL); + break; + case PAM_PROMPT_ECHO_ON: + buffer_put_cstring(&buffer, + PAM_MSG_MEMBER(msg, i, msg)); + if (ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) + goto fail; + if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) + goto fail; + if (buffer_get_char(&buffer) != PAM_AUTHTOK) + goto fail; + reply[i].resp = buffer_get_string(&buffer, NULL); + break; + case PAM_ERROR_MSG: + buffer_put_cstring(&buffer, + PAM_MSG_MEMBER(msg, i, msg)); + if (ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) + goto fail; + break; + case PAM_TEXT_INFO: + buffer_put_cstring(&buffer, + PAM_MSG_MEMBER(msg, i, msg)); + if (ssh_msg_send(ctxt->pam_csock, + PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) + goto fail; + break; + default: + goto fail; + } + buffer_clear(&buffer); + } + buffer_free(&buffer); + *resp = reply; + return (PAM_SUCCESS); + + fail: + for(i = 0; i < n; i++) { + if (reply[i].resp != NULL) + xfree(reply[i].resp); + } + xfree(reply); + buffer_free(&buffer); + return (PAM_CONV_ERR); +} + +/* + * Authentication thread. + */ +static void * +sshpam_thread(void *ctxtp) +{ + struct pam_ctxt *ctxt = ctxtp; + Buffer buffer; + struct pam_conv sshpam_conv; + int flags = (options.permit_empty_passwd == 0 ? + PAM_DISALLOW_NULL_AUTHTOK : 0); +#ifndef USE_POSIX_THREADS + extern char **environ; + char **env_from_pam; + u_int i; + const char *pam_user; + + pam_get_item(sshpam_handle, PAM_USER, (void **)&pam_user); + environ[0] = NULL; + + if (sshpam_authctxt != NULL) { + setproctitle("%s [pam]", + sshpam_authctxt->valid ? pam_user : "unknown"); + } +#endif + + sshpam_conv.conv = sshpam_thread_conv; + sshpam_conv.appdata_ptr = ctxt; + + if (sshpam_authctxt == NULL) + fatal("%s: PAM authctxt not initialized", __func__); + + buffer_init(&buffer); + sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, + (const void *)&sshpam_conv); + if (sshpam_err != PAM_SUCCESS) + goto auth_fail; + sshpam_err = pam_authenticate(sshpam_handle, flags); + if (sshpam_err != PAM_SUCCESS) + goto auth_fail; + + if (compat20) { + if (!do_pam_account()) + goto auth_fail; + if (sshpam_authctxt->force_pwchange) { + sshpam_err = pam_chauthtok(sshpam_handle, + PAM_CHANGE_EXPIRED_AUTHTOK); + if (sshpam_err != PAM_SUCCESS) + goto auth_fail; + sshpam_password_change_required(0); + } + } + + buffer_put_cstring(&buffer, "OK"); + +#ifndef USE_POSIX_THREADS + /* Export variables set by do_pam_account */ + buffer_put_int(&buffer, sshpam_account_status); + buffer_put_int(&buffer, sshpam_authctxt->force_pwchange); + + /* Export any environment strings set in child */ + for(i = 0; environ[i] != NULL; i++) + ; /* Count */ + buffer_put_int(&buffer, i); + for(i = 0; environ[i] != NULL; i++) + buffer_put_cstring(&buffer, environ[i]); + + /* Export any environment strings set by PAM in child */ + env_from_pam = pam_getenvlist(sshpam_handle); + for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) + ; /* Count */ + buffer_put_int(&buffer, i); + for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) + buffer_put_cstring(&buffer, env_from_pam[i]); +#endif /* USE_POSIX_THREADS */ + + /* XXX - can't do much about an error here */ + ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer); + buffer_free(&buffer); + pthread_exit(NULL); + + auth_fail: + buffer_put_cstring(&buffer, + pam_strerror(sshpam_handle, sshpam_err)); + /* XXX - can't do much about an error here */ + ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); + buffer_free(&buffer); + pthread_exit(NULL); + + return (NULL); /* Avoid warning for non-pthread case */ +} + +void +sshpam_thread_cleanup(void) +{ + struct pam_ctxt *ctxt = cleanup_ctxt; + + debug3("PAM: %s entering", __func__); + if (ctxt != NULL && ctxt->pam_thread != 0) { + pthread_cancel(ctxt->pam_thread); + pthread_join(ctxt->pam_thread, NULL); + close(ctxt->pam_psock); + close(ctxt->pam_csock); + memset(ctxt, 0, sizeof(*ctxt)); + cleanup_ctxt = NULL; + } +} + +static int +sshpam_null_conv(int n, struct pam_message **msg, + struct pam_response **resp, void *data) +{ + debug3("PAM: %s entering, %d messages", __func__, n); + return (PAM_CONV_ERR); +} + +static struct pam_conv null_conv = { sshpam_null_conv, NULL }; + +void +sshpam_cleanup(void) +{ + debug("PAM: cleanup"); + if (sshpam_handle == NULL) + return; + pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv); + if (sshpam_cred_established) { + pam_setcred(sshpam_handle, PAM_DELETE_CRED); + sshpam_cred_established = 0; + } + if (sshpam_session_open) { + pam_close_session(sshpam_handle, PAM_SILENT); + sshpam_session_open = 0; + } + sshpam_authenticated = 0; + pam_end(sshpam_handle, sshpam_err); + sshpam_handle = NULL; +} + +static int +sshpam_init(Authctxt *authctxt) +{ + extern char *__progname; + const char *pam_rhost, *pam_user, *user = authctxt->user; + + if (sshpam_handle != NULL) { + /* We already have a PAM context; check if the user matches */ + sshpam_err = pam_get_item(sshpam_handle, + PAM_USER, (void **)&pam_user); + if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) + return (0); + pam_end(sshpam_handle, sshpam_err); + sshpam_handle = NULL; + } + debug("PAM: initializing for \"%s\"", user); + sshpam_err = + pam_start(SSHD_PAM_SERVICE, user, &null_conv, &sshpam_handle); + sshpam_authctxt = authctxt; + + if (sshpam_err != PAM_SUCCESS) { + pam_end(sshpam_handle, sshpam_err); + sshpam_handle = NULL; + return (-1); + } + pam_rhost = get_remote_name_or_ip(utmp_len, options.use_dns); + debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost); + sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost); + if (sshpam_err != PAM_SUCCESS) { + pam_end(sshpam_handle, sshpam_err); + sshpam_handle = NULL; + return (-1); + } +#ifdef PAM_TTY_KLUDGE + /* + * Some silly PAM modules (e.g. pam_time) require a TTY to operate. + * sshd doesn't set the tty until too late in the auth process and + * may not even set one (for tty-less connections) + */ + debug("PAM: setting PAM_TTY to \"ssh\""); + sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh"); + if (sshpam_err != PAM_SUCCESS) { + pam_end(sshpam_handle, sshpam_err); + sshpam_handle = NULL; + return (-1); + } +#endif + return (0); +} + +static void * +sshpam_init_ctx(Authctxt *authctxt) +{ + struct pam_ctxt *ctxt; + int socks[2]; + + debug3("PAM: %s entering", __func__); + /* Refuse to start if we don't have PAM enabled */ + if (!options.use_pam) + return NULL; + + /* Initialize PAM */ + if (sshpam_init(authctxt) == -1) { + error("PAM: initialization failed"); + return (NULL); + } + + ctxt = xmalloc(sizeof *ctxt); + memset(ctxt, 0, sizeof(*ctxt)); + + /* Start the authentication thread */ + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { + error("PAM: failed create sockets: %s", strerror(errno)); + xfree(ctxt); + return (NULL); + } + ctxt->pam_psock = socks[0]; + ctxt->pam_csock = socks[1]; + if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) { + error("PAM: failed to start authentication thread: %s", + strerror(errno)); + close(socks[0]); + close(socks[1]); + xfree(ctxt); + return (NULL); + } + cleanup_ctxt = ctxt; + return (ctxt); +} + +static int +sshpam_query(void *ctx, char **name, char **info, + u_int *num, char ***prompts, u_int **echo_on) +{ + Buffer buffer; + struct pam_ctxt *ctxt = ctx; + size_t plen; + u_char type; + char *msg; + size_t len; + + debug3("PAM: %s entering", __func__); + buffer_init(&buffer); + *name = xstrdup(""); + *info = xstrdup(""); + *prompts = xmalloc(sizeof(char *)); + **prompts = NULL; + plen = 0; + *echo_on = xmalloc(sizeof(u_int)); + while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) { + type = buffer_get_char(&buffer); + msg = buffer_get_string(&buffer, NULL); + switch (type) { + case PAM_PROMPT_ECHO_ON: + case PAM_PROMPT_ECHO_OFF: + *num = 1; + len = plen + strlen(msg) + 1; + **prompts = xrealloc(**prompts, len); + plen += snprintf(**prompts + plen, len, "%s", msg); + **echo_on = (type == PAM_PROMPT_ECHO_ON); + xfree(msg); + return (0); + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + /* accumulate messages */ + len = plen + strlen(msg) + 2; + **prompts = xrealloc(**prompts, len); + plen += snprintf(**prompts + plen, len, "%s\n", msg); + xfree(msg); + break; + case PAM_SUCCESS: + case PAM_AUTH_ERR: + if (**prompts != NULL) { + /* drain any accumulated messages */ + debug("PAM: %s", **prompts); + buffer_append(&loginmsg, **prompts, + strlen(**prompts)); + xfree(**prompts); + **prompts = NULL; + } + if (type == PAM_SUCCESS) { + import_environments(&buffer); + *num = 0; + **echo_on = 0; + ctxt->pam_done = 1; + xfree(msg); + return (0); + } + error("PAM: %s for %s%.100s from %.100s", msg, + sshpam_authctxt->valid ? "" : "illegal user ", + sshpam_authctxt->user, + get_remote_name_or_ip(utmp_len, options.use_dns)); + /* FALLTHROUGH */ + default: + *num = 0; + **echo_on = 0; + xfree(msg); + ctxt->pam_done = -1; + return (-1); + } + } + return (-1); +} + +/* XXX - see also comment in auth-chall.c:verify_response */ +static int +sshpam_respond(void *ctx, u_int num, char **resp) +{ + Buffer buffer; + struct pam_ctxt *ctxt = ctx; + + debug2("PAM: %s entering, %d responses", __func__, num); + switch (ctxt->pam_done) { + case 1: + sshpam_authenticated = 1; + return (0); + case 0: + break; + default: + return (-1); + } + if (num != 1) { + error("PAM: expected one response, got %u", num); + return (-1); + } + buffer_init(&buffer); + buffer_put_cstring(&buffer, *resp); + if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { + buffer_free(&buffer); + return (-1); + } + buffer_free(&buffer); + return (1); +} + +static void +sshpam_free_ctx(void *ctxtp) +{ + struct pam_ctxt *ctxt = ctxtp; + + debug3("PAM: %s entering", __func__); + sshpam_thread_cleanup(); + xfree(ctxt); + /* + * We don't call sshpam_cleanup() here because we may need the PAM + * handle at a later stage, e.g. when setting up a session. It's + * still on the cleanup list, so pam_end() *will* be called before + * the server process terminates. + */ +} + +KbdintDevice sshpam_device = { + "pam", + sshpam_init_ctx, + sshpam_query, + sshpam_respond, + sshpam_free_ctx +}; + +KbdintDevice mm_sshpam_device = { + "pam", + mm_sshpam_init_ctx, + mm_sshpam_query, + mm_sshpam_respond, + mm_sshpam_free_ctx +}; + +/* + * This replaces auth-pam.c + */ +void +start_pam(Authctxt *authctxt) +{ + if (!options.use_pam) + fatal("PAM: initialisation requested when UsePAM=no"); + + if (sshpam_init(authctxt) == -1) + fatal("PAM: initialisation failed"); +} + +void +finish_pam(void) +{ + sshpam_cleanup(); +} + +u_int +do_pam_account(void) +{ + if (sshpam_account_status != -1) + return (sshpam_account_status); + + sshpam_err = pam_acct_mgmt(sshpam_handle, 0); + debug3("PAM: %s pam_acct_mgmt = %d", __func__, sshpam_err); + + if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { + sshpam_account_status = 0; + return (sshpam_account_status); + } + + if (sshpam_err == PAM_NEW_AUTHTOK_REQD) + sshpam_password_change_required(1); + + sshpam_account_status = 1; + return (sshpam_account_status); +} + +void +do_pam_set_tty(const char *tty) +{ + if (tty != NULL) { + debug("PAM: setting PAM_TTY to \"%s\"", tty); + sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: failed to set PAM_TTY: %s", + pam_strerror(sshpam_handle, sshpam_err)); + } +} + +void +do_pam_setcred(int init) +{ + sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, + (const void *)&null_conv); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: failed to set PAM_CONV: %s", + pam_strerror(sshpam_handle, sshpam_err)); + if (init) { + debug("PAM: establishing credentials"); + sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED); + } else { + debug("PAM: reinitializing credentials"); + sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED); + } + if (sshpam_err == PAM_SUCCESS) { + sshpam_cred_established = 1; + return; + } + if (sshpam_authenticated) + fatal("PAM: pam_setcred(): %s", + pam_strerror(sshpam_handle, sshpam_err)); + else + debug("PAM: pam_setcred(): %s", + pam_strerror(sshpam_handle, sshpam_err)); +} + +static int +sshpam_tty_conv(int n, struct pam_message **msg, + struct pam_response **resp, void *data) +{ + char input[PAM_MAX_MSG_SIZE]; + struct pam_response *reply; + int i; + + debug3("PAM: %s called with %d messages", __func__, n); + + *resp = NULL; + + if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO)) + return (PAM_CONV_ERR); + + if ((reply = malloc(n * sizeof(*reply))) == NULL) + return (PAM_CONV_ERR); + memset(reply, 0, n * sizeof(*reply)); + + for (i = 0; i < n; ++i) { + switch (PAM_MSG_MEMBER(msg, i, msg_style)) { + case PAM_PROMPT_ECHO_OFF: + reply[i].resp = + read_passphrase(PAM_MSG_MEMBER(msg, i, msg), + RP_ALLOW_STDIN); + reply[i].resp_retcode = PAM_SUCCESS; + break; + case PAM_PROMPT_ECHO_ON: + fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); + fgets(input, sizeof input, stdin); + if ((reply[i].resp = strdup(input)) == NULL) + goto fail; + reply[i].resp_retcode = PAM_SUCCESS; + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); + reply[i].resp_retcode = PAM_SUCCESS; + break; + default: + goto fail; + } + } + *resp = reply; + return (PAM_SUCCESS); + + fail: + for(i = 0; i < n; i++) { + if (reply[i].resp != NULL) + xfree(reply[i].resp); + } + xfree(reply); + return (PAM_CONV_ERR); +} + +static struct pam_conv tty_conv = { sshpam_tty_conv, NULL }; + +/* + * XXX this should be done in the authentication phase, but ssh1 doesn't + * support that + */ +void +do_pam_chauthtok(void) +{ + if (use_privsep) + fatal("Password expired (unable to change with privsep)"); + sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, + (const void *)&tty_conv); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: failed to set PAM_CONV: %s", + pam_strerror(sshpam_handle, sshpam_err)); + debug("PAM: changing password"); + sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: pam_chauthtok(): %s", + pam_strerror(sshpam_handle, sshpam_err)); +} + +static int +sshpam_store_conv(int n, struct pam_message **msg, + struct pam_response **resp, void *data) +{ + struct pam_response *reply; + int i; + size_t len; + + debug3("PAM: %s called with %d messages", __func__, n); + *resp = NULL; + + if (n <= 0 || n > PAM_MAX_NUM_MSG) + return (PAM_CONV_ERR); + + if ((reply = malloc(n * sizeof(*reply))) == NULL) + return (PAM_CONV_ERR); + memset(reply, 0, n * sizeof(*reply)); + + for (i = 0; i < n; ++i) { + switch (PAM_MSG_MEMBER(msg, i, msg_style)) { + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + len = strlen(PAM_MSG_MEMBER(msg, i, msg)); + buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len); + buffer_append(&loginmsg, "\n", 1 ); + reply[i].resp_retcode = PAM_SUCCESS; + break; + default: + goto fail; + } + } + *resp = reply; + return (PAM_SUCCESS); + + fail: + for(i = 0; i < n; i++) { + if (reply[i].resp != NULL) + xfree(reply[i].resp); + } + xfree(reply); + return (PAM_CONV_ERR); +} + +static struct pam_conv store_conv = { sshpam_store_conv, NULL }; + +void +do_pam_session(void) +{ + debug3("PAM: opening session"); + sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, + (const void *)&store_conv); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: failed to set PAM_CONV: %s", + pam_strerror(sshpam_handle, sshpam_err)); + sshpam_err = pam_open_session(sshpam_handle, 0); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: pam_open_session(): %s", + pam_strerror(sshpam_handle, sshpam_err)); + sshpam_session_open = 1; +} + +/* + * Set a PAM environment string. We need to do this so that the session + * modules can handle things like Kerberos/GSI credentials that appear + * during the ssh authentication process. + */ +int +do_pam_putenv(char *name, char *value) +{ + int ret = 1; +#ifdef HAVE_PAM_PUTENV + char *compound; + size_t len; + + len = strlen(name) + strlen(value) + 2; + compound = xmalloc(len); + + snprintf(compound, len, "%s=%s", name, value); + ret = pam_putenv(sshpam_handle, compound); + xfree(compound); +#endif + + return (ret); +} + +char ** +fetch_pam_child_environment(void) +{ + return sshpam_env; +} + +char ** +fetch_pam_environment(void) +{ + return (pam_getenvlist(sshpam_handle)); +} + +void +free_pam_environment(char **env) +{ + char **envp; + + if (env == NULL) + return; + + for (envp = env; *envp; envp++) + xfree(*envp); + xfree(env); +} + +/* + * "Blind" conversation function for password authentication. Assumes that + * echo-off prompts are for the password and stores messages for later + * display. + */ +static int +sshpam_passwd_conv(int n, struct pam_message **msg, + struct pam_response **resp, void *data) +{ + struct pam_response *reply; + int i; + size_t len; + + debug3("PAM: %s called with %d messages", __func__, n); + + *resp = NULL; + + if (n <= 0 || n > PAM_MAX_NUM_MSG) + return (PAM_CONV_ERR); + + if ((reply = malloc(n * sizeof(*reply))) == NULL) + return (PAM_CONV_ERR); + memset(reply, 0, n * sizeof(*reply)); + + for (i = 0; i < n; ++i) { + switch (PAM_MSG_MEMBER(msg, i, msg_style)) { + case PAM_PROMPT_ECHO_OFF: + if (sshpam_password == NULL) + goto fail; + if ((reply[i].resp = strdup(sshpam_password)) == NULL) + goto fail; + reply[i].resp_retcode = PAM_SUCCESS; + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + len = strlen(PAM_MSG_MEMBER(msg, i, msg)); + if (len > 0) { + buffer_append(&loginmsg, + PAM_MSG_MEMBER(msg, i, msg), len); + buffer_append(&loginmsg, "\n", 1); + } + if ((reply[i].resp = strdup("")) == NULL) + goto fail; + reply[i].resp_retcode = PAM_SUCCESS; + break; + default: + goto fail; + } + } + *resp = reply; + return (PAM_SUCCESS); + + fail: + for(i = 0; i < n; i++) { + if (reply[i].resp != NULL) + xfree(reply[i].resp); + } + xfree(reply); + return (PAM_CONV_ERR); +} + +static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL }; + +/* + * Attempt password authentication via PAM + */ +int +sshpam_auth_passwd(Authctxt *authctxt, const char *password) +{ + int flags = (options.permit_empty_passwd == 0 ? + PAM_DISALLOW_NULL_AUTHTOK : 0); + static char badpw[] = "\b\n\r\177INCORRECT"; + + if (!options.use_pam || sshpam_handle == NULL) + fatal("PAM: %s called when PAM disabled or failed to " + "initialise.", __func__); + + sshpam_password = password; + sshpam_authctxt = authctxt; + + /* + * If the user logging in is invalid, or is root but is not permitted + * by PermitRootLogin, use an invalid password to prevent leaking + * information via timing (eg if the PAM config has a delay on fail). + */ + if (!authctxt->valid || (authctxt->pw->pw_uid == 0 && + options.permit_root_login != PERMIT_YES)) + sshpam_password = badpw; + + sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, + (const void *)&passwd_conv); + if (sshpam_err != PAM_SUCCESS) + fatal("PAM: %s: failed to set PAM_CONV: %s", __func__, + pam_strerror(sshpam_handle, sshpam_err)); + + sshpam_err = pam_authenticate(sshpam_handle, flags); + sshpam_password = NULL; + if (sshpam_err == PAM_SUCCESS && authctxt->valid) { + debug("PAM: password authentication accepted for %.100s", + authctxt->user); + return 1; + } else { + debug("PAM: password authentication failed for %.100s: %s", + authctxt->valid ? authctxt->user : "an illegal user", + pam_strerror(sshpam_handle, sshpam_err)); + return 0; + } +} +#endif /* USE_PAM */ diff --git a/crypto/openssh-3.9p1/auth-pam.h b/crypto/openssh-3.9p1/auth-pam.h new file mode 100644 index 0000000000..f479413d77 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-pam.h @@ -0,0 +1,49 @@ +/* $Id: auth-pam.h,v 1.26 2004/05/30 10:43:59 dtucker Exp $ */ + +/* + * Copyright (c) 2000 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +#ifdef USE_PAM + +#if !defined(SSHD_PAM_SERVICE) +# define SSHD_PAM_SERVICE __progname +#endif + +void start_pam(Authctxt *); +void finish_pam(void); +u_int do_pam_account(void); +void do_pam_session(void); +void do_pam_set_tty(const char *); +void do_pam_setcred(int ); +void do_pam_chauthtok(void); +int do_pam_putenv(char *, char *); +char ** fetch_pam_environment(void); +char ** fetch_pam_child_environment(void); +void free_pam_environment(char **); +void sshpam_thread_cleanup(void); +void sshpam_cleanup(void); +int sshpam_auth_passwd(Authctxt *, const char *); + +#endif /* USE_PAM */ diff --git a/crypto/openssh-3.9p1/auth-passwd.c b/crypto/openssh-3.9p1/auth-passwd.c new file mode 100644 index 0000000000..7a68e05628 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-passwd.c @@ -0,0 +1,155 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Password authentication. This file contains the functions to check whether + * the password is valid for the user. + * + * 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". + * + * Copyright (c) 1999 Dug Song. All rights reserved. + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth-passwd.c,v 1.31 2004/01/30 09:48:57 markus Exp $"); + +#include "packet.h" +#include "log.h" +#include "servconf.h" +#include "auth.h" +#include "auth-options.h" + +extern ServerOptions options; +int sys_auth_passwd(Authctxt *, const char *); + +void +disable_forwarding(void) +{ + no_port_forwarding_flag = 1; + no_agent_forwarding_flag = 1; + no_x11_forwarding_flag = 1; +} + +/* + * Tries to authenticate the user using password. Returns true if + * authentication succeeds. + */ +int +auth_password(Authctxt *authctxt, const char *password) +{ + struct passwd * pw = authctxt->pw; + int ok = authctxt->valid; +#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE) + static int expire_checked = 0; +#endif + +#ifndef HAVE_CYGWIN + if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES) + ok = 0; +#endif + if (*password == '\0' && options.permit_empty_passwd == 0) + return 0; + +#ifdef KRB5 + if (options.kerberos_authentication == 1) { + int ret = auth_krb5_password(authctxt, password); + if (ret == 1 || ret == 0) + return ret && ok; + /* Fall back to ordinary passwd authentication. */ + } +#endif +#ifdef HAVE_CYGWIN + if (is_winnt) { + HANDLE hToken = cygwin_logon_user(pw, password); + + if (hToken == INVALID_HANDLE_VALUE) + return 0; + cygwin_set_impersonation_token(hToken); + return ok; + } +#endif +#ifdef USE_PAM + if (options.use_pam) + return (sshpam_auth_passwd(authctxt, password) && ok); +#endif +#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE) + if (!expire_checked) { + expire_checked = 1; + if (auth_shadow_pwexpired(authctxt)) { + disable_forwarding(); + authctxt->force_pwchange = 1; + } + } +#endif + + return (sys_auth_passwd(authctxt, password) && ok); +} + +#ifdef BSD_AUTH +int +sys_auth_passwd(Authctxt *authctxt, const char *password) +{ + struct passwd *pw = authctxt->pw; + auth_session_t *as; + + as = auth_usercheck(pw->pw_name, authctxt->style, "auth-ssh", + (char *)password); + if (auth_getstate(as) & AUTH_PWEXPIRED) { + auth_close(as); + disable_forwarding(); + authctxt->force_pwchange = 1; + return (1); + } else { + return (auth_close(as)); + } +} +#elif !defined(CUSTOM_SYS_AUTH_PASSWD) +int +sys_auth_passwd(Authctxt *authctxt, const char *password) +{ + struct passwd *pw = authctxt->pw; + char *encrypted_password; + + /* Just use the supplied fake password if authctxt is invalid */ + char *pw_password = authctxt->valid ? shadow_pw(pw) : pw->pw_passwd; + + /* Check for users with no password. */ + if (strcmp(pw_password, "") == 0 && strcmp(password, "") == 0) + return (1); + + /* Encrypt the candidate password using the proper salt. */ + encrypted_password = xcrypt(password, + (pw_password[0] && pw_password[1]) ? pw_password : "xx"); + + /* + * Authentication is accepted if the encrypted passwords + * are identical. + */ + return (strcmp(encrypted_password, pw_password) == 0); +} +#endif diff --git a/crypto/openssh-3.9p1/auth-rh-rsa.c b/crypto/openssh-3.9p1/auth-rh-rsa.c new file mode 100644 index 0000000000..29eb538ec9 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-rh-rsa.c @@ -0,0 +1,92 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Rhosts or /etc/hosts.equiv authentication combined with RSA host + * authentication. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: auth-rh-rsa.c,v 1.37 2003/11/04 08:54:09 djm Exp $"); + +#include "packet.h" +#include "uidswap.h" +#include "log.h" +#include "servconf.h" +#include "key.h" +#include "hostfile.h" +#include "pathnames.h" +#include "auth.h" +#include "canohost.h" + +#include "monitor_wrap.h" + +/* import */ +extern ServerOptions options; + +int +auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost, + Key *client_host_key) +{ + HostStatus host_status; + + /* Check if we would accept it using rhosts authentication. */ + if (!auth_rhosts(pw, cuser)) + return 0; + + host_status = check_key_in_hostfiles(pw, client_host_key, + chost, _PATH_SSH_SYSTEM_HOSTFILE, + options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); + + return (host_status == HOST_OK); +} + +/* + * Tries to authenticate the user using the .rhosts file and the host using + * its host key. Returns true if authentication succeeds. + */ +int +auth_rhosts_rsa(Authctxt *authctxt, char *cuser, Key *client_host_key) +{ + char *chost; + struct passwd *pw = authctxt->pw; + + debug("Trying rhosts with RSA host authentication for client user %.100s", + cuser); + + if (!authctxt->valid || client_host_key == NULL || + client_host_key->rsa == NULL) + return 0; + + chost = (char *)get_canonical_hostname(options.use_dns); + debug("Rhosts RSA authentication: canonical host %.900s", chost); + + if (!PRIVSEP(auth_rhosts_rsa_key_allowed(pw, cuser, chost, client_host_key))) { + debug("Rhosts with RSA host authentication denied: unknown or invalid host key"); + packet_send_debug("Your host key cannot be verified: unknown or invalid host key."); + return 0; + } + /* A matching host key was found and is known. */ + + /* Perform the challenge-response dialog with the client for the host key. */ + if (!auth_rsa_challenge_dialog(client_host_key)) { + logit("Client on %.800s failed to respond correctly to host authentication.", + chost); + return 0; + } + /* + * We have authenticated the user using .rhosts or /etc/hosts.equiv, + * and the host using RSA. We accept the authentication. + */ + + verbose("Rhosts with RSA host authentication accepted for %.100s, %.100s on %.700s.", + pw->pw_name, cuser, chost); + packet_send_debug("Rhosts with RSA host authentication accepted."); + return 1; +} diff --git a/crypto/openssh-3.9p1/auth-rhosts.c b/crypto/openssh-3.9p1/auth-rhosts.c new file mode 100644 index 0000000000..585246e822 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-rhosts.c @@ -0,0 +1,295 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Rhosts authentication. This file contains code to check whether to admit + * the login based on rhosts authentication. This file also processes + * /etc/hosts.equiv. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: auth-rhosts.c,v 1.32 2003/11/04 08:54:09 djm Exp $"); + +#include "packet.h" +#include "uidswap.h" +#include "pathnames.h" +#include "log.h" +#include "servconf.h" +#include "canohost.h" +#include "auth.h" + +/* import */ +extern ServerOptions options; +extern int use_privsep; + +/* + * 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. + */ + +static 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, deny if unreadable */ + f = fopen(filename, "r"); + if (!f) + return 0; + + while (fgets(buf, sizeof(buf), f)) { + /* All three must be at least as big as buf to avoid overflows. */ + char hostbuf[1024], userbuf[1024], dummy[1024], *host, *user, *cp; + int negated; + + for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) + ; + if (*cp == '#' || *cp == '\n' || !*cp) + continue; + + /* + * NO_PLUS is supported at least on OSF/1. We skip it (we + * don't ever support the plus syntax). + */ + if (strncmp(cp, "NO_PLUS", 7) == 0) + continue; + + /* + * This should be safe because each buffer is as big as the + * whole string, and thus cannot be overwritten. + */ + switch (sscanf(buf, "%1023s %1023s %1023s", hostbuf, userbuf, + dummy)) { + case 0: + auth_debug_add("Found empty line in %.100s.", filename); + continue; + case 1: + /* Host name only. */ + strlcpy(userbuf, server_user, sizeof(userbuf)); + break; + case 2: + /* Got both host and user name. */ + break; + case 3: + auth_debug_add("Found garbage in %.100s.", filename); + continue; + default: + /* Weird... */ + continue; + } + + host = hostbuf; + user = userbuf; + negated = 0; + + /* Process negated host names, or positive netgroups. */ + if (host[0] == '-') { + negated = 1; + host++; + } else if (host[0] == '+') + host++; + + if (user[0] == '-') { + negated = 1; + user++; + } else if (user[0] == '+') + user++; + + /* Check for empty host/user names (particularly '+'). */ + if (!host[0] || !user[0]) { + /* We come here if either was '+' or '-'. */ + auth_debug_add("Ignoring wild host/user names in %.100s.", + filename); + continue; + } + /* Verify that host name matches. */ + if (host[0] == '@') { + if (!innetgr(host + 1, hostname, NULL, NULL) && + !innetgr(host + 1, ipaddr, NULL, NULL)) + continue; + } else if (strcasecmp(host, hostname) && strcmp(host, ipaddr) != 0) + continue; /* Different hostname. */ + + /* Verify that user name matches. */ + if (user[0] == '@') { + if (!innetgr(user + 1, NULL, client_user, NULL)) + continue; + } else if (strcmp(user, client_user) != 0) + continue; /* Different username. */ + + /* Found the user and host. */ + fclose(f); + + /* If the entry was negated, deny access. */ + if (negated) { + auth_debug_add("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) +{ + const char *hostname, *ipaddr; + + hostname = get_canonical_hostname(options.use_dns); + ipaddr = get_remote_ipaddr(); + return auth_rhosts2(pw, client_user, hostname, ipaddr); +} + +static int +auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostname, + const char *ipaddr) +{ + char buf[1024]; + struct stat st; + static const char *rhosts_files[] = {".shosts", ".rhosts", NULL}; + u_int rhosts_file_index; + + debug2("auth_rhosts2: clientuser %s hostname %s ipaddr %s", + client_user, hostname, ipaddr); + + /* Switch to the user's uid. */ + temporarily_use_uid(pw); + /* + * Quick check: if the user has no .shosts or .rhosts files, return + * failure immediately without doing costly lookups from name + * servers. + */ + for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; + rhosts_file_index++) { + /* Check users .rhosts or .shosts. */ + snprintf(buf, sizeof buf, "%.500s/%.100s", + pw->pw_dir, rhosts_files[rhosts_file_index]); + if (stat(buf, &st) >= 0) + break; + } + /* Switch back to privileged uid. */ + restore_uid(); + + /* Deny if The user has no .shosts or .rhosts file and there are no system-wide files. */ + if (!rhosts_files[rhosts_file_index] && + stat(_PATH_RHOSTS_EQUIV, &st) < 0 && + stat(_PATH_SSH_HOSTS_EQUIV, &st) < 0) + return 0; + + /* If not logging in as superuser, try /etc/hosts.equiv and shosts.equiv. */ + if (pw->pw_uid != 0) { + if (check_rhosts_file(_PATH_RHOSTS_EQUIV, hostname, ipaddr, + client_user, pw->pw_name)) { + auth_debug_add("Accepted for %.100s [%.100s] by /etc/hosts.equiv.", + hostname, ipaddr); + return 1; + } + if (check_rhosts_file(_PATH_SSH_HOSTS_EQUIV, hostname, ipaddr, + client_user, pw->pw_name)) { + auth_debug_add("Accepted for %.100s [%.100s] by %.100s.", + hostname, ipaddr, _PATH_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) { + logit("Rhosts authentication refused for %.100s: " + "no home directory %.200s", pw->pw_name, pw->pw_dir); + auth_debug_add("Rhosts authentication refused for %.100s: " + "no home directory %.200s", pw->pw_name, pw->pw_dir); + return 0; + } + if (options.strict_modes && + ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || + (st.st_mode & 022) != 0)) { + logit("Rhosts authentication refused for %.100s: " + "bad ownership or modes for home directory.", pw->pw_name); + auth_debug_add("Rhosts authentication refused for %.100s: " + "bad ownership or modes for home directory.", pw->pw_name); + return 0; + } + /* Temporarily use the user's uid. */ + temporarily_use_uid(pw); + + /* Check all .rhosts files (currently .shosts and .rhosts). */ + for (rhosts_file_index = 0; rhosts_files[rhosts_file_index]; + rhosts_file_index++) { + /* Check users .rhosts or .shosts. */ + snprintf(buf, sizeof buf, "%.500s/%.100s", + pw->pw_dir, rhosts_files[rhosts_file_index]); + if (stat(buf, &st) < 0) + continue; + + /* + * Make sure that the file is either owned by the user or by + * root, and make sure it is not writable by anyone but the + * owner. This is to help avoid novices accidentally + * allowing access to their account by anyone. + */ + if (options.strict_modes && + ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || + (st.st_mode & 022) != 0)) { + logit("Rhosts authentication refused for %.100s: bad modes for %.200s", + pw->pw_name, buf); + auth_debug_add("Bad file modes for %.200s", buf); + continue; + } + /* Check if we have been configured to ignore .rhosts and .shosts files. */ + if (options.ignore_rhosts) { + auth_debug_add("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)) { + auth_debug_add("Accepted by %.100s.", + rhosts_files[rhosts_file_index]); + /* Restore the privileged uid. */ + restore_uid(); + auth_debug_add("Accepted host %s ip %s client_user %s server_user %s", + hostname, ipaddr, client_user, pw->pw_name); + return 1; + } + } + + /* Restore the privileged uid. */ + restore_uid(); + return 0; +} + +int +auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname, + const char *ipaddr) +{ + int ret; + + auth_debug_reset(); + ret = auth_rhosts2_raw(pw, client_user, hostname, ipaddr); + if (!use_privsep) + auth_debug_send(); + return ret; +} diff --git a/crypto/openssh-3.9p1/auth-rsa.c b/crypto/openssh-3.9p1/auth-rsa.c new file mode 100644 index 0000000000..16369d47c8 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-rsa.c @@ -0,0 +1,327 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * RSA-based authentication. This code determines whether to admit a login + * based on RSA authentication. This file also contains functions to check + * validity of the host key. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: auth-rsa.c,v 1.60 2004/06/21 17:36:31 avsm Exp $"); + +#include +#include + +#include "rsa.h" +#include "packet.h" +#include "xmalloc.h" +#include "ssh1.h" +#include "uidswap.h" +#include "match.h" +#include "auth-options.h" +#include "pathnames.h" +#include "log.h" +#include "servconf.h" +#include "auth.h" +#include "hostfile.h" +#include "monitor_wrap.h" +#include "ssh.h" + +/* import */ +extern ServerOptions options; + +/* + * Session identifier that is used to bind key exchange and authentication + * responses to a particular session. + */ +extern u_char session_id[16]; + +/* + * The .ssh/authorized_keys file contains public keys, one per line, in the + * following format: + * options bits e n comment + * where bits, e and n are decimal numbers, + * and comment is any string of characters up to newline. The maximum + * length of a line is 8000 characters. See the documentation for a + * description of the options. + */ + +BIGNUM * +auth_rsa_generate_challenge(Key *key) +{ + BIGNUM *challenge; + BN_CTX *ctx; + + if ((challenge = BN_new()) == NULL) + fatal("auth_rsa_generate_challenge: BN_new() failed"); + /* Generate a random challenge. */ + BN_rand(challenge, 256, 0, 0); + if ((ctx = BN_CTX_new()) == NULL) + fatal("auth_rsa_generate_challenge: BN_CTX_new() failed"); + BN_mod(challenge, challenge, key->rsa->n, ctx); + BN_CTX_free(ctx); + + return challenge; +} + +int +auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) +{ + u_char buf[32], mdbuf[16]; + MD5_CTX md; + int len; + + /* don't allow short keys */ + if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits", + BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); + return (0); + } + + /* The response is MD5 of decrypted challenge plus session id. */ + len = BN_num_bytes(challenge); + if (len <= 0 || len > 32) + fatal("auth_rsa_verify_response: bad challenge length %d", len); + memset(buf, 0, 32); + BN_bn2bin(challenge, buf + 32 - len); + MD5_Init(&md); + MD5_Update(&md, buf, 32); + MD5_Update(&md, session_id, 16); + MD5_Final(mdbuf, &md); + + /* Verify that the response is the original challenge. */ + if (memcmp(response, mdbuf, 16) != 0) { + /* Wrong answer. */ + return (0); + } + /* Correct answer. */ + return (1); +} + +/* + * Performs the RSA authentication challenge-response dialog with the client, + * and returns true (non-zero) if the client gave the correct answer to + * our challenge; returns zero if the client gives a wrong answer. + */ + +int +auth_rsa_challenge_dialog(Key *key) +{ + BIGNUM *challenge, *encrypted_challenge; + u_char response[16]; + int i, success; + + if ((encrypted_challenge = BN_new()) == NULL) + fatal("auth_rsa_challenge_dialog: BN_new() failed"); + + challenge = PRIVSEP(auth_rsa_generate_challenge(key)); + + /* Encrypt the challenge with the public key. */ + rsa_public_encrypt(encrypted_challenge, challenge, key->rsa); + + /* Send the encrypted challenge to the client. */ + packet_start(SSH_SMSG_AUTH_RSA_CHALLENGE); + packet_put_bignum(encrypted_challenge); + packet_send(); + BN_clear_free(encrypted_challenge); + packet_write_wait(); + + /* Wait for a response. */ + packet_read_expect(SSH_CMSG_AUTH_RSA_RESPONSE); + for (i = 0; i < 16; i++) + response[i] = packet_get_char(); + packet_check_eom(); + + success = PRIVSEP(auth_rsa_verify_response(key, challenge, response)); + BN_clear_free(challenge); + return (success); +} + +/* + * check if there's user key matching client_n, + * return key if login is allowed, NULL otherwise + */ + +int +auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) +{ + char line[8192], *file; + int allowed = 0; + u_int bits; + FILE *f; + u_long linenum = 0; + struct stat st; + Key *key; + + /* Temporarily use the user's uid. */ + temporarily_use_uid(pw); + + /* The authorized keys. */ + file = authorized_keys_file(pw); + debug("trying public RSA key file %s", file); + + /* Fail quietly if file does not exist */ + if (stat(file, &st) < 0) { + /* Restore the privileged uid. */ + restore_uid(); + xfree(file); + return (0); + } + /* Open the file containing the authorized keys. */ + f = fopen(file, "r"); + if (!f) { + /* Restore the privileged uid. */ + restore_uid(); + xfree(file); + return (0); + } + if (options.strict_modes && + secure_filename(f, file, pw, line, sizeof(line)) != 0) { + xfree(file); + fclose(f); + logit("Authentication refused: %s", line); + restore_uid(); + return (0); + } + + /* Flag indicating whether the key is allowed. */ + allowed = 0; + + key = key_new(KEY_RSA1); + + /* + * Go though the accepted keys, looking for the current key. If + * found, perform a challenge-response dialog to verify that the + * user really has the corresponding private key. + */ + while (fgets(line, sizeof(line), f)) { + char *cp; + char *key_options; + + linenum++; + + /* Skip leading whitespace, empty and comment lines. */ + for (cp = line; *cp == ' ' || *cp == '\t'; cp++) + ; + if (!*cp || *cp == '\n' || *cp == '#') + continue; + + /* + * Check if there are options for this key, and if so, + * save their starting address and skip the option part + * for now. If there are no options, set the starting + * address to NULL. + */ + if (*cp < '0' || *cp > '9') { + int quoted = 0; + key_options = cp; + for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { + if (*cp == '\\' && cp[1] == '"') + cp++; /* Skip both */ + else if (*cp == '"') + quoted = !quoted; + } + } else + key_options = NULL; + + /* Parse the key from the line. */ + if (hostfile_read_key(&cp, &bits, key) == 0) { + debug("%.100s, line %lu: non ssh1 key syntax", + file, linenum); + continue; + } + /* cp now points to the comment part. */ + + /* Check if the we have found the desired key (identified by its modulus). */ + if (BN_cmp(key->rsa->n, client_n) != 0) + continue; + + /* check the real bits */ + if (bits != BN_num_bits(key->rsa->n)) + logit("Warning: %s, line %lu: keysize mismatch: " + "actual %d vs. announced %d.", + file, linenum, BN_num_bits(key->rsa->n), bits); + + /* We have found the desired key. */ + /* + * If our options do not allow this key to be used, + * do not send challenge. + */ + if (!auth_parse_options(pw, key_options, file, linenum)) + continue; + + /* break out, this key is allowed */ + allowed = 1; + break; + } + + /* Restore the privileged uid. */ + restore_uid(); + + /* Close the file. */ + xfree(file); + fclose(f); + + /* return key if allowed */ + if (allowed && rkey != NULL) + *rkey = key; + else + key_free(key); + return (allowed); +} + +/* + * Performs the RSA authentication dialog with the client. This returns + * 0 if the client could not be authenticated, and 1 if authentication was + * successful. This may exit if there is a serious protocol violation. + */ +int +auth_rsa(Authctxt *authctxt, BIGNUM *client_n) +{ + Key *key; + char *fp; + struct passwd *pw = authctxt->pw; + + /* no user given */ + if (!authctxt->valid) + return 0; + + if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) { + auth_clear_options(); + return (0); + } + + /* Perform the challenge-response dialog for this key. */ + if (!auth_rsa_challenge_dialog(key)) { + /* Wrong response. */ + verbose("Wrong response to RSA authentication challenge."); + packet_send_debug("Wrong response to RSA authentication challenge."); + /* + * Break out of the loop. Otherwise we might send + * another challenge and break the protocol. + */ + key_free(key); + return (0); + } + /* + * Correct response. The client has been successfully + * authenticated. Note that we have not yet processed the + * options; this will be reset if the options cause the + * authentication to be rejected. + */ + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + verbose("Found matching %s key: %s", + key_type(key), fp); + xfree(fp); + key_free(key); + + packet_send_debug("RSA authentication accepted."); + return (1); +} diff --git a/crypto/openssh-3.9p1/auth-shadow.c b/crypto/openssh-3.9p1/auth-shadow.c new file mode 100644 index 0000000000..a85442d72b --- /dev/null +++ b/crypto/openssh-3.9p1/auth-shadow.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2004 Darren Tucker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$Id: auth-shadow.c,v 1.5 2004/02/21 23:22:05 dtucker Exp $"); + +#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE) +#include + +#include "auth.h" +#include "buffer.h" +#include "log.h" + +#define DAY (24L * 60 * 60) /* 1 day in seconds */ + +extern Buffer loginmsg; + +/* + * For the account and password expiration functions, we assume the expiry + * occurs the day after the day specified. + */ + +/* + * Check if specified account is expired. Returns 1 if account is expired, + * 0 otherwise. + */ +int +auth_shadow_acctexpired(struct spwd *spw) +{ + time_t today; + int daysleft; + char buf[256]; + + today = time(NULL) / DAY; + daysleft = spw->sp_expire - today; + debug3("%s: today %d sp_expire %d days left %d", __func__, (int)today, + (int)spw->sp_expire, daysleft); + + if (spw->sp_expire == -1) { + debug3("account expiration disabled"); + } else if (daysleft < 0) { + logit("Account %.100s has expired", spw->sp_namp); + return 1; + } else if (daysleft <= spw->sp_warn) { + debug3("account will expire in %d days", daysleft); + snprintf(buf, sizeof(buf), + "Your account will expire in %d day%s.\n", daysleft, + daysleft == 1 ? "" : "s"); + buffer_append(&loginmsg, buf, strlen(buf)); + } + + return 0; +} + +/* + * Checks password expiry for platforms that use shadow passwd files. + * Returns: 1 = password expired, 0 = password not expired + */ +int +auth_shadow_pwexpired(Authctxt *ctxt) +{ + struct spwd *spw = NULL; + const char *user = ctxt->pw->pw_name; + char buf[256]; + time_t today; + int daysleft, disabled = 0; + + if ((spw = getspnam((char *)user)) == NULL) { + error("Could not get shadow information for %.100s", user); + return 0; + } + + today = time(NULL) / DAY; + debug3("%s: today %d sp_lstchg %d sp_max %d", __func__, (int)today, + (int)spw->sp_lstchg, (int)spw->sp_max); + +#if defined(__hpux) && !defined(HAVE_SECUREWARE) + if (iscomsec()) { + struct pr_passwd *pr; + + pr = getprpwnam((char *)user); + + /* Test for Trusted Mode expiry disabled */ + if (pr != NULL && pr->ufld.fd_min == 0 && + pr->ufld.fd_lifetime == 0 && pr->ufld.fd_expire == 0 && + pr->ufld.fd_pw_expire_warning == 0 && + pr->ufld.fd_schange != 0) + disabled = 1; + } +#endif + + /* TODO: check sp_inact */ + daysleft = spw->sp_lstchg + spw->sp_max - today; + if (disabled) { + debug3("password expiration disabled"); + } else if (spw->sp_lstchg == 0) { + logit("User %.100s password has expired (root forced)", user); + return 1; + } else if (spw->sp_max == -1) { + debug3("password expiration disabled"); + } else if (daysleft < 0) { + logit("User %.100s password has expired (password aged)", user); + return 1; + } else if (daysleft <= spw->sp_warn) { + debug3("password will expire in %d days", daysleft); + snprintf(buf, sizeof(buf), + "Your password will expire in %d day%s.\n", daysleft, + daysleft == 1 ? "" : "s"); + buffer_append(&loginmsg, buf, strlen(buf)); + } + + return 0; +} +#endif /* USE_SHADOW && HAS_SHADOW_EXPIRE */ diff --git a/crypto/openssh-3.9p1/auth-sia.c b/crypto/openssh-3.9p1/auth-sia.c new file mode 100644 index 0000000000..63f55d07f2 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-sia.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2002 Chris Adams. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#ifdef HAVE_OSF_SIA +#include "ssh.h" +#include "auth.h" +#include "auth-sia.h" +#include "log.h" +#include "servconf.h" +#include "canohost.h" +#include "uidswap.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +extern ServerOptions options; +extern int saved_argc; +extern char **saved_argv; + +int +sys_auth_passwd(Authctxt *authctxt, char *pass) +{ + int ret; + SIAENTITY *ent = NULL; + const char *host; + + host = get_canonical_hostname(options.use_dns); + + if (!authctxt->user || pass == NULL || pass[0] == '\0') + return (0); + + if (sia_ses_init(&ent, saved_argc, saved_argv, host, authctxt->user, + NULL, 0, NULL) != SIASUCCESS) + return (0); + + if ((ret = sia_ses_authent(NULL, pass, ent)) != SIASUCCESS) { + error("Couldn't authenticate %s from %s", + authctxt->user, host); + if (ret & SIASTOP) + sia_ses_release(&ent); + + return (0); + } + + sia_ses_release(&ent); + + return (1); +} + +void +session_setup_sia(struct passwd *pw, char *tty) +{ + SIAENTITY *ent = NULL; + const char *host; + + host = get_canonical_hostname(options.use_dns); + + if (sia_ses_init(&ent, saved_argc, saved_argv, host, pw->pw_name, + tty, 0, NULL) != SIASUCCESS) + fatal("sia_ses_init failed"); + + if (sia_make_entity_pwd(pw, ent) != SIASUCCESS) { + sia_ses_release(&ent); + fatal("sia_make_entity_pwd failed"); + } + + ent->authtype = SIA_A_NONE; + if (sia_ses_estab(sia_collect_trm, ent) != SIASUCCESS) + fatal("Couldn't establish session for %s from %s", + pw->pw_name, host); + + if (sia_ses_launch(sia_collect_trm, ent) != SIASUCCESS) + fatal("Couldn't launch session for %s from %s", + pw->pw_name, host); + + sia_ses_release(&ent); + + setuid(0); + permanently_set_uid(pw); +} + +#endif /* HAVE_OSF_SIA */ diff --git a/crypto/openssh-3.9p1/auth-sia.h b/crypto/openssh-3.9p1/auth-sia.h new file mode 100644 index 0000000000..ca55e913ed --- /dev/null +++ b/crypto/openssh-3.9p1/auth-sia.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2002 Chris Adams. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#ifdef HAVE_OSF_SIA + +int sys_auth_passwd(Authctxt *, char *); +void session_setup_sia(struct passwd *, char *); + +#endif /* HAVE_OSF_SIA */ diff --git a/crypto/openssh-3.9p1/auth-skey.c b/crypto/openssh-3.9p1/auth-skey.c new file mode 100644 index 0000000000..ac1af69ed9 --- /dev/null +++ b/crypto/openssh-3.9p1/auth-skey.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: auth-skey.c,v 1.20 2002/06/30 21:59:45 deraadt Exp $"); + +#ifdef SKEY + +#include + +#include "xmalloc.h" +#include "auth.h" +#include "monitor_wrap.h" + +static void * +skey_init_ctx(Authctxt *authctxt) +{ + return authctxt; +} + +int +skey_query(void *ctx, char **name, char **infotxt, + u_int* numprompts, char ***prompts, u_int **echo_on) +{ + Authctxt *authctxt = ctx; + char challenge[1024], *p; + int len; + struct skey skey; + + if (_compat_skeychallenge(&skey, authctxt->user, challenge, + sizeof(challenge)) == -1) + return -1; + + *name = xstrdup(""); + *infotxt = xstrdup(""); + *numprompts = 1; + *prompts = xmalloc(*numprompts * sizeof(char *)); + *echo_on = xmalloc(*numprompts * sizeof(u_int)); + (*echo_on)[0] = 0; + + len = strlen(challenge) + strlen(SKEY_PROMPT) + 1; + p = xmalloc(len); + strlcpy(p, challenge, len); + strlcat(p, SKEY_PROMPT, len); + (*prompts)[0] = p; + + return 0; +} + +int +skey_respond(void *ctx, u_int numresponses, char **responses) +{ + Authctxt *authctxt = ctx; + + if (authctxt->valid && + numresponses == 1 && + skey_haskey(authctxt->pw->pw_name) == 0 && + skey_passcheck(authctxt->pw->pw_name, responses[0]) != -1) + return 0; + return -1; +} + +static void +skey_free_ctx(void *ctx) +{ + /* we don't have a special context */ +} + +KbdintDevice skey_device = { + "skey", + skey_init_ctx, + skey_query, + skey_respond, + skey_free_ctx +}; + +KbdintDevice mm_skey_device = { + "skey", + skey_init_ctx, + mm_skey_query, + mm_skey_respond, + skey_free_ctx +}; +#endif /* SKEY */ diff --git a/crypto/openssh-3.9p1/auth.c b/crypto/openssh-3.9p1/auth.c new file mode 100644 index 0000000000..0956b0b19c --- /dev/null +++ b/crypto/openssh-3.9p1/auth.c @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth.c,v 1.56 2004/07/28 09:40:29 markus Exp $"); + +#ifdef HAVE_LOGIN_H +#include +#endif +#ifdef USE_SHADOW +#include +#endif + +#ifdef HAVE_LIBGEN_H +#include +#endif + +#include "xmalloc.h" +#include "match.h" +#include "groupaccess.h" +#include "log.h" +#include "servconf.h" +#include "auth.h" +#include "auth-options.h" +#include "canohost.h" +#include "buffer.h" +#include "bufaux.h" +#include "uidswap.h" +#include "misc.h" +#include "bufaux.h" +#include "packet.h" + +/* import */ +extern ServerOptions options; +extern Buffer loginmsg; + +/* Debugging messages */ +Buffer auth_debug; +int auth_debug_init; + +/* + * Check if the user is allowed to log in via ssh. If user is listed + * in DenyUsers or one of user's groups is listed in DenyGroups, false + * will be returned. If AllowUsers isn't empty and user isn't listed + * there, or if AllowGroups isn't empty and one of user's groups isn't + * listed there, false will be returned. + * If the user's shell is not executable, false will be returned. + * Otherwise true is returned. + */ +int +allowed_user(struct passwd * pw) +{ + struct stat st; + const char *hostname = NULL, *ipaddr = NULL, *passwd = NULL; + char *shell; + int i; +#ifdef USE_SHADOW + struct spwd *spw = NULL; +#endif + + /* Shouldn't be called if pw is NULL, but better safe than sorry... */ + if (!pw || !pw->pw_name) + return 0; + +#ifdef USE_SHADOW + if (!options.use_pam) + spw = getspnam(pw->pw_name); +#ifdef HAS_SHADOW_EXPIRE + if (!options.use_pam && spw != NULL && auth_shadow_acctexpired(spw)) + return 0; +#endif /* HAS_SHADOW_EXPIRE */ +#endif /* USE_SHADOW */ + + /* grab passwd field for locked account check */ +#ifdef USE_SHADOW + if (spw != NULL) + passwd = spw->sp_pwdp; +#else + passwd = pw->pw_passwd; +#endif + + /* check for locked account */ + if (!options.use_pam && passwd && *passwd) { + int locked = 0; + +#ifdef LOCKED_PASSWD_STRING + if (strcmp(passwd, LOCKED_PASSWD_STRING) == 0) + locked = 1; +#endif +#ifdef LOCKED_PASSWD_PREFIX + if (strncmp(passwd, LOCKED_PASSWD_PREFIX, + strlen(LOCKED_PASSWD_PREFIX)) == 0) + locked = 1; +#endif +#ifdef LOCKED_PASSWD_SUBSTR + if (strstr(passwd, LOCKED_PASSWD_SUBSTR)) + locked = 1; +#endif + if (locked) { + logit("User %.100s not allowed because account is locked", + pw->pw_name); + return 0; + } + } + + /* + * Get the shell from the password data. An empty shell field is + * legal, and means /bin/sh. + */ + shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; + + /* deny if shell does not exists or is not executable */ + if (stat(shell, &st) != 0) { + logit("User %.100s not allowed because shell %.100s does not exist", + pw->pw_name, shell); + return 0; + } + if (S_ISREG(st.st_mode) == 0 || + (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) { + logit("User %.100s not allowed because shell %.100s is not executable", + pw->pw_name, shell); + return 0; + } + + if (options.num_deny_users > 0 || options.num_allow_users > 0) { + hostname = get_canonical_hostname(options.use_dns); + ipaddr = get_remote_ipaddr(); + } + + /* Return false if user is listed in DenyUsers */ + if (options.num_deny_users > 0) { + for (i = 0; i < options.num_deny_users; i++) + if (match_user(pw->pw_name, hostname, ipaddr, + options.deny_users[i])) { + logit("User %.100s not allowed because listed in DenyUsers", + pw->pw_name); + return 0; + } + } + /* Return false if AllowUsers isn't empty and user isn't listed there */ + if (options.num_allow_users > 0) { + for (i = 0; i < options.num_allow_users; i++) + if (match_user(pw->pw_name, hostname, ipaddr, + options.allow_users[i])) + break; + /* i < options.num_allow_users iff we break for loop */ + if (i >= options.num_allow_users) { + logit("User %.100s not allowed because not listed in AllowUsers", + pw->pw_name); + return 0; + } + } + if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { + /* Get the user's group access list (primary and supplementary) */ + if (ga_init(pw->pw_name, pw->pw_gid) == 0) { + logit("User %.100s not allowed because not in any group", + pw->pw_name); + return 0; + } + + /* Return false if one of user's groups is listed in DenyGroups */ + if (options.num_deny_groups > 0) + if (ga_match(options.deny_groups, + options.num_deny_groups)) { + ga_free(); + logit("User %.100s not allowed because a group is listed in DenyGroups", + pw->pw_name); + return 0; + } + /* + * Return false if AllowGroups isn't empty and one of user's groups + * isn't listed there + */ + if (options.num_allow_groups > 0) + if (!ga_match(options.allow_groups, + options.num_allow_groups)) { + ga_free(); + logit("User %.100s not allowed because none of user's groups are listed in AllowGroups", + pw->pw_name); + return 0; + } + ga_free(); + } + +#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER + if (!sys_auth_allowed_user(pw)) + return 0; +#endif + + /* We found no reason not to let this user try to log on... */ + return 1; +} + +void +auth_log(Authctxt *authctxt, int authenticated, char *method, char *info) +{ + void (*authlog) (const char *fmt,...) = verbose; + char *authmsg; + + /* Raise logging level */ + if (authenticated == 1 || + !authctxt->valid || + authctxt->failures >= options.max_authtries / 2 || + strcmp(method, "password") == 0) + authlog = logit; + + if (authctxt->postponed) + authmsg = "Postponed"; + else + authmsg = authenticated ? "Accepted" : "Failed"; + + authlog("%s %s for %s%.100s from %.200s port %d%s", + authmsg, + method, + authctxt->valid ? "" : "invalid user ", + authctxt->user, + get_remote_ipaddr(), + get_remote_port(), + info); + +#ifdef CUSTOM_FAILED_LOGIN + if (authenticated == 0 && strcmp(method, "password") == 0) + record_failed_login(authctxt->user, "ssh"); +#endif +} + +/* + * Check whether root logins are disallowed. + */ +int +auth_root_allowed(char *method) +{ + switch (options.permit_root_login) { + case PERMIT_YES: + return 1; + break; + case PERMIT_NO_PASSWD: + if (strcmp(method, "password") != 0) + return 1; + break; + case PERMIT_FORCED_ONLY: + if (forced_command) { + logit("Root login accepted for forced command."); + return 1; + } + break; + } + logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); + return 0; +} + + +/* + * Given a template and a passwd structure, build a filename + * by substituting % tokenised options. Currently, %% becomes '%', + * %h becomes the home directory and %u the username. + * + * This returns a buffer allocated by xmalloc. + */ +char * +expand_filename(const char *filename, struct passwd *pw) +{ + Buffer buffer; + char *file; + const char *cp; + + /* + * Build the filename string in the buffer by making the appropriate + * substitutions to the given file name. + */ + buffer_init(&buffer); + for (cp = filename; *cp; cp++) { + if (cp[0] == '%' && cp[1] == '%') { + buffer_append(&buffer, "%", 1); + cp++; + continue; + } + if (cp[0] == '%' && cp[1] == 'h') { + buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir)); + cp++; + continue; + } + if (cp[0] == '%' && cp[1] == 'u') { + buffer_append(&buffer, pw->pw_name, + strlen(pw->pw_name)); + cp++; + continue; + } + buffer_append(&buffer, cp, 1); + } + buffer_append(&buffer, "\0", 1); + + /* + * Ensure that filename starts anchored. If not, be backward + * compatible and prepend the '%h/' + */ + file = xmalloc(MAXPATHLEN); + cp = buffer_ptr(&buffer); + if (*cp != '/') + snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp); + else + strlcpy(file, cp, MAXPATHLEN); + + buffer_free(&buffer); + return file; +} + +char * +authorized_keys_file(struct passwd *pw) +{ + return expand_filename(options.authorized_keys_file, pw); +} + +char * +authorized_keys_file2(struct passwd *pw) +{ + return expand_filename(options.authorized_keys_file2, pw); +} + +/* return ok if key exists in sysfile or userfile */ +HostStatus +check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, + const char *sysfile, const char *userfile) +{ + Key *found; + char *user_hostfile; + struct stat st; + HostStatus host_status; + + /* Check if we know the host and its host key. */ + found = key_new(key->type); + host_status = check_host_in_hostfile(sysfile, host, key, found, NULL); + + if (host_status != HOST_OK && userfile != NULL) { + user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); + if (options.strict_modes && + (stat(user_hostfile, &st) == 0) && + ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || + (st.st_mode & 022) != 0)) { + logit("Authentication refused for %.100s: " + "bad owner or modes for %.200s", + pw->pw_name, user_hostfile); + } else { + temporarily_use_uid(pw); + host_status = check_host_in_hostfile(user_hostfile, + host, key, found, NULL); + restore_uid(); + } + xfree(user_hostfile); + } + key_free(found); + + debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ? + "ok" : "not found", host); + return host_status; +} + + +/* + * Check a given file for security. This is defined as all components + * of the path to the file must be owned by either the owner of + * of the file or root and no directories must be group or world writable. + * + * XXX Should any specific check be done for sym links ? + * + * Takes an open file descriptor, the file name, a uid and and + * error buffer plus max size as arguments. + * + * Returns 0 on success and -1 on failure + */ +int +secure_filename(FILE *f, const char *file, struct passwd *pw, + char *err, size_t errlen) +{ + uid_t uid = pw->pw_uid; + char buf[MAXPATHLEN], homedir[MAXPATHLEN]; + char *cp; + int comparehome = 0; + struct stat st; + + if (realpath(file, buf) == NULL) { + snprintf(err, errlen, "realpath %s failed: %s", file, + strerror(errno)); + return -1; + } + if (realpath(pw->pw_dir, homedir) != NULL) + comparehome = 1; + + /* check the open file to avoid races */ + if (fstat(fileno(f), &st) < 0 || + (st.st_uid != 0 && st.st_uid != uid) || + (st.st_mode & 022) != 0) { + snprintf(err, errlen, "bad ownership or modes for file %s", + buf); + return -1; + } + + /* for each component of the canonical path, walking upwards */ + for (;;) { + if ((cp = dirname(buf)) == NULL) { + snprintf(err, errlen, "dirname() failed"); + return -1; + } + strlcpy(buf, cp, sizeof(buf)); + + debug3("secure_filename: checking '%s'", buf); + if (stat(buf, &st) < 0 || + (st.st_uid != 0 && st.st_uid != uid) || + (st.st_mode & 022) != 0) { + snprintf(err, errlen, + "bad ownership or modes for directory %s", buf); + return -1; + } + + /* If are passed the homedir then we can stop */ + if (comparehome && strcmp(homedir, buf) == 0) { + debug3("secure_filename: terminating check at '%s'", + buf); + break; + } + /* + * dirname should always complete with a "/" path, + * but we can be paranoid and check for "." too + */ + if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) + break; + } + return 0; +} + +struct passwd * +getpwnamallow(const char *user) +{ +#ifdef HAVE_LOGIN_CAP + extern login_cap_t *lc; +#ifdef BSD_AUTH + auth_session_t *as; +#endif +#endif + struct passwd *pw; + + pw = getpwnam(user); + if (pw == NULL) { + logit("Invalid user %.100s from %.100s", + user, get_remote_ipaddr()); +#ifdef CUSTOM_FAILED_LOGIN + record_failed_login(user, "ssh"); +#endif + return (NULL); + } + if (!allowed_user(pw)) + return (NULL); +#ifdef HAVE_LOGIN_CAP + if ((lc = login_getclass(pw->pw_class)) == NULL) { + debug("unable to get login class: %s", user); + return (NULL); + } +#ifdef BSD_AUTH + if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 || + auth_approval(as, lc, pw->pw_name, "ssh") <= 0) { + debug("Approval failure for %s", user); + pw = NULL; + } + if (as != NULL) + auth_close(as); +#endif +#endif + if (pw != NULL) + return (pwcopy(pw)); + return (NULL); +} + +void +auth_debug_add(const char *fmt,...) +{ + char buf[1024]; + va_list args; + + if (!auth_debug_init) + return; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + buffer_put_cstring(&auth_debug, buf); +} + +void +auth_debug_send(void) +{ + char *msg; + + if (!auth_debug_init) + return; + while (buffer_len(&auth_debug)) { + msg = buffer_get_string(&auth_debug, NULL); + packet_send_debug("%s", msg); + xfree(msg); + } +} + +void +auth_debug_reset(void) +{ + if (auth_debug_init) + buffer_clear(&auth_debug); + else { + buffer_init(&auth_debug); + auth_debug_init = 1; + } +} + +struct passwd * +fakepw(void) +{ + static struct passwd fake; + + memset(&fake, 0, sizeof(fake)); + fake.pw_name = "NOUSER"; + fake.pw_passwd = + "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK"; + fake.pw_gecos = "NOUSER"; + fake.pw_uid = (uid_t)-1; + fake.pw_gid = (gid_t)-1; +#ifdef HAVE_PW_CLASS_IN_PASSWD + fake.pw_class = ""; +#endif + fake.pw_dir = "/nonexist"; + fake.pw_shell = "/nonexist"; + + return (&fake); +} diff --git a/crypto/openssh-3.9p1/auth.h b/crypto/openssh-3.9p1/auth.h new file mode 100644 index 0000000000..2f094403d6 --- /dev/null +++ b/crypto/openssh-3.9p1/auth.h @@ -0,0 +1,187 @@ +/* $OpenBSD: auth.h,v 1.50 2004/05/23 23:59:53 dtucker Exp $ */ + +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef AUTH_H +#define AUTH_H + +#include "key.h" +#include "hostfile.h" +#include + +#ifdef HAVE_LOGIN_CAP +#include +#endif +#ifdef BSD_AUTH +#include +#endif +#ifdef KRB5 +#include +#endif + +typedef struct Authctxt Authctxt; +typedef struct Authmethod Authmethod; +typedef struct KbdintDevice KbdintDevice; + +struct Authctxt { + int success; + int postponed; /* authentication needs another step */ + int valid; /* user exists and is allowed to login */ + int attempt; + int failures; + int force_pwchange; + char *user; /* username sent by the client */ + char *service; + struct passwd *pw; /* set if 'valid' */ + char *style; + void *kbdintctxt; +#ifdef BSD_AUTH + auth_session_t *as; +#endif +#ifdef KRB5 + krb5_context krb5_ctx; + krb5_ccache krb5_fwd_ccache; + krb5_principal krb5_user; + char *krb5_ticket_file; + char *krb5_ccname; +#endif + void *methoddata; +}; +/* + * Every authentication method has to handle authentication requests for + * non-existing users, or for users that are not allowed to login. In this + * case 'valid' is set to 0, but 'user' points to the username requested by + * the client. + */ + +struct Authmethod { + char *name; + int (*userauth)(Authctxt *authctxt); + int *enabled; +}; + +/* + * Keyboard interactive device: + * init_ctx returns: non NULL upon success + * query returns: 0 - success, otherwise failure + * respond returns: 0 - success, 1 - need further interaction, + * otherwise - failure + */ +struct KbdintDevice +{ + const char *name; + void* (*init_ctx)(Authctxt*); + int (*query)(void *ctx, char **name, char **infotxt, + u_int *numprompts, char ***prompts, u_int **echo_on); + int (*respond)(void *ctx, u_int numresp, char **responses); + void (*free_ctx)(void *ctx); +}; + +int auth_rhosts(struct passwd *, const char *); +int +auth_rhosts2(struct passwd *, const char *, const char *, const char *); + +int auth_rhosts_rsa(Authctxt *, char *, Key *); +int auth_password(Authctxt *, const char *); +int auth_rsa(Authctxt *, BIGNUM *); +int auth_rsa_challenge_dialog(Key *); +BIGNUM *auth_rsa_generate_challenge(Key *); +int auth_rsa_verify_response(Key *, BIGNUM *, u_char[]); +int auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); + +int auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); +int hostbased_key_allowed(struct passwd *, const char *, char *, Key *); +int user_key_allowed(struct passwd *, Key *); + +#ifdef KRB5 +int auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *); +int auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt); +int auth_krb5_password(Authctxt *authctxt, const char *password); +void krb5_cleanup_proc(Authctxt *authctxt); +#endif /* KRB5 */ + +#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE) +#include +int auth_shadow_acctexpired(struct spwd *); +int auth_shadow_pwexpired(Authctxt *); +#endif + +#include "auth-pam.h" +void disable_forwarding(void); + +void do_authentication(Authctxt *); +void do_authentication2(Authctxt *); + +void auth_log(Authctxt *, int, char *, char *); +void userauth_finish(Authctxt *, int, char *); +int auth_root_allowed(char *); + +char *auth2_read_banner(void); + +void privsep_challenge_enable(void); + +int auth2_challenge(Authctxt *, char *); +void auth2_challenge_stop(Authctxt *); +int bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **); +int bsdauth_respond(void *, u_int, char **); +int skey_query(void *, char **, char **, u_int *, char ***, u_int **); +int skey_respond(void *, u_int, char **); + +int allowed_user(struct passwd *); +struct passwd * getpwnamallow(const char *user); + +char *get_challenge(Authctxt *); +int verify_response(Authctxt *, const char *); +void abandon_challenge_response(Authctxt *); + +char *expand_filename(const char *, struct passwd *); +char *authorized_keys_file(struct passwd *); +char *authorized_keys_file2(struct passwd *); + +int +secure_filename(FILE *, const char *, struct passwd *, char *, size_t); + +HostStatus +check_key_in_hostfiles(struct passwd *, Key *, const char *, + const char *, const char *); + +/* hostkey handling */ +Key *get_hostkey_by_index(int); +Key *get_hostkey_by_type(int); +int get_hostkey_index(Key *); +int ssh1_session_key(BIGNUM *); + +/* debug messages during authentication */ +void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void auth_debug_send(void); +void auth_debug_reset(void); + +struct passwd *fakepw(void); + +#define AUTH_FAIL_MSG "Too many authentication failures for %.100s" + +#define SKEY_PROMPT "\nS/Key Password: " +#endif diff --git a/crypto/openssh-3.9p1/auth1.c b/crypto/openssh-3.9p1/auth1.c new file mode 100644 index 0000000000..3f93b9869f --- /dev/null +++ b/crypto/openssh-3.9p1/auth1.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: auth1.c,v 1.59 2004/07/28 09:40:29 markus Exp $"); + +#include "xmalloc.h" +#include "rsa.h" +#include "ssh1.h" +#include "packet.h" +#include "buffer.h" +#include "log.h" +#include "servconf.h" +#include "compat.h" +#include "auth.h" +#include "channels.h" +#include "session.h" +#include "uidswap.h" +#include "monitor_wrap.h" + +/* import */ +extern ServerOptions options; + +/* + * convert ssh auth msg type into description + */ +static char * +get_authname(int type) +{ + static char buf[1024]; + switch (type) { + case SSH_CMSG_AUTH_PASSWORD: + return "password"; + case SSH_CMSG_AUTH_RSA: + return "rsa"; + case SSH_CMSG_AUTH_RHOSTS_RSA: + return "rhosts-rsa"; + case SSH_CMSG_AUTH_RHOSTS: + return "rhosts"; + case SSH_CMSG_AUTH_TIS: + case SSH_CMSG_AUTH_TIS_RESPONSE: + return "challenge-response"; + } + snprintf(buf, sizeof buf, "bad-auth-msg-%d", type); + return buf; +} + +/* + * read packets, try to authenticate the user and + * return only if authentication is successful + */ +static void +do_authloop(Authctxt *authctxt) +{ + int authenticated = 0; + u_int bits; + Key *client_host_key; + BIGNUM *n; + char *client_user, *password; + char info[1024]; + u_int dlen; + u_int ulen; + int prev, type = 0; + + debug("Attempting authentication for %s%.100s.", + authctxt->valid ? "" : "invalid user ", authctxt->user); + + /* If the user has no password, accept authentication immediately. */ + if (options.password_authentication && +#ifdef KRB5 + (!options.kerberos_authentication || options.kerberos_or_local_passwd) && +#endif + PRIVSEP(auth_password(authctxt, ""))) { +#ifdef USE_PAM + if (options.use_pam && (PRIVSEP(do_pam_account()))) +#endif + { + auth_log(authctxt, 1, "without authentication", ""); + return; + } + } + + /* Indicate that authentication is needed. */ + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + + client_user = NULL; + + for (;;) { + /* default to fail */ + authenticated = 0; + + info[0] = '\0'; + + /* Get a packet from the client. */ + prev = type; + type = packet_read(); + + /* + * If we started challenge-response authentication but the + * next packet is not a response to our challenge, release + * the resources allocated by get_challenge() (which would + * normally have been released by verify_response() had we + * received such a response) + */ + if (prev == SSH_CMSG_AUTH_TIS && + type != SSH_CMSG_AUTH_TIS_RESPONSE) + abandon_challenge_response(authctxt); + + /* Process the packet. */ + switch (type) { + case SSH_CMSG_AUTH_RHOSTS_RSA: + if (!options.rhosts_rsa_authentication) { + verbose("Rhosts with RSA authentication disabled."); + break; + } + /* + * 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. */ + client_host_key = key_new(KEY_RSA1); + bits = packet_get_int(); + packet_get_bignum(client_host_key->rsa->e); + packet_get_bignum(client_host_key->rsa->n); + + if (bits != BN_num_bits(client_host_key->rsa->n)) + verbose("Warning: keysize mismatch for client_host_key: " + "actual %d, announced %d", + BN_num_bits(client_host_key->rsa->n), bits); + packet_check_eom(); + + authenticated = auth_rhosts_rsa(authctxt, client_user, + client_host_key); + key_free(client_host_key); + + snprintf(info, sizeof info, " ruser %.100s", client_user); + break; + + case SSH_CMSG_AUTH_RSA: + if (!options.rsa_authentication) { + verbose("RSA authentication disabled."); + break; + } + /* RSA authentication requested. */ + if ((n = BN_new()) == NULL) + fatal("do_authloop: BN_new failed"); + packet_get_bignum(n); + packet_check_eom(); + authenticated = auth_rsa(authctxt, n); + BN_clear_free(n); + break; + + case SSH_CMSG_AUTH_PASSWORD: + if (!options.password_authentication) { + verbose("Password authentication disabled."); + break; + } + /* + * Read user password. It is in plain text, but was + * transmitted over the encrypted channel so it is + * not visible to an outside observer. + */ + password = packet_get_string(&dlen); + packet_check_eom(); + + /* Try authentication with the password. */ + authenticated = PRIVSEP(auth_password(authctxt, password)); + + memset(password, 0, strlen(password)); + xfree(password); + break; + + case SSH_CMSG_AUTH_TIS: + debug("rcvd SSH_CMSG_AUTH_TIS"); + if (options.challenge_response_authentication == 1) { + char *challenge = get_challenge(authctxt); + if (challenge != NULL) { + debug("sending challenge '%s'", challenge); + packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE); + packet_put_cstring(challenge); + xfree(challenge); + packet_send(); + packet_write_wait(); + continue; + } + } + break; + case SSH_CMSG_AUTH_TIS_RESPONSE: + debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE"); + if (options.challenge_response_authentication == 1) { + char *response = packet_get_string(&dlen); + packet_check_eom(); + authenticated = verify_response(authctxt, response); + memset(response, 'r', dlen); + xfree(response); + } + break; + + default: + /* + * Any unknown messages will be ignored (and failure + * returned) during authentication. + */ + logit("Unknown message during authentication: type %d", type); + break; + } +#ifdef BSD_AUTH + if (authctxt->as) { + auth_close(authctxt->as); + authctxt->as = NULL; + } +#endif + if (!authctxt->valid && authenticated) + fatal("INTERNAL ERROR: authenticated invalid user %s", + authctxt->user); + +#ifdef _UNICOS + if (authenticated && cray_access_denied(authctxt->user)) { + authenticated = 0; + fatal("Access denied for user %s.",authctxt->user); + } +#endif /* _UNICOS */ + +#ifdef HAVE_CYGWIN + if (authenticated && + !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, + authctxt->pw)) { + packet_disconnect("Authentication rejected for uid %d.", + authctxt->pw == NULL ? -1 : authctxt->pw->pw_uid); + authenticated = 0; + } +#else + /* Special handling for root */ + if (authenticated && authctxt->pw->pw_uid == 0 && + !auth_root_allowed(get_authname(type))) + authenticated = 0; +#endif + +#ifdef USE_PAM + if (options.use_pam && authenticated && + !PRIVSEP(do_pam_account())) + authenticated = 0; +#endif + + /* Log before sending the reply */ + auth_log(authctxt, authenticated, get_authname(type), info); + + if (client_user != NULL) { + xfree(client_user); + client_user = NULL; + } + + if (authenticated) + return; + + if (authctxt->failures++ > options.max_authtries) + packet_disconnect(AUTH_FAIL_MSG, authctxt->user); + + packet_start(SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + } +} + +/* + * Performs authentication of an incoming connection. Session key has already + * been exchanged and encryption is enabled. + */ +void +do_authentication(Authctxt *authctxt) +{ + u_int ulen; + char *user, *style = NULL; + + /* Get the name of the user that we wish to log in as. */ + packet_read_expect(SSH_CMSG_USER); + + /* Get the user name. */ + user = packet_get_string(&ulen); + packet_check_eom(); + + if ((style = strchr(user, ':')) != NULL) + *style++ = '\0'; + + authctxt->user = user; + authctxt->style = style; + + /* Verify that the user is a valid user. */ + if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL) + authctxt->valid = 1; + else { + debug("do_authentication: invalid user %s", user); + authctxt->pw = fakepw(); + } + + setproctitle("%s%s", authctxt->valid ? user : "unknown", + use_privsep ? " [net]" : ""); + +#ifdef USE_PAM + if (options.use_pam) + PRIVSEP(start_pam(authctxt)); +#endif + + /* + * If we are not running as root, the user must have the same uid as + * the server. (Unless you are running Windows) + */ +#ifndef HAVE_CYGWIN + if (!use_privsep && getuid() != 0 && authctxt->pw && + authctxt->pw->pw_uid != getuid()) + packet_disconnect("Cannot change user when server not running as root."); +#endif + + /* + * Loop until the user has been authenticated or the connection is + * closed, do_authloop() returns only if authentication is successful + */ + do_authloop(authctxt); + + /* The user has been authenticated and accepted. */ + packet_start(SSH_SMSG_SUCCESS); + packet_send(); + packet_write_wait(); +} diff --git a/crypto/openssh-3.9p1/auth2-chall.c b/crypto/openssh-3.9p1/auth2-chall.c new file mode 100644 index 0000000000..486baaaa33 --- /dev/null +++ b/crypto/openssh-3.9p1/auth2-chall.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Per Allansson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: auth2-chall.c,v 1.21 2004/06/01 14:20:45 dtucker Exp $"); + +#include "ssh2.h" +#include "auth.h" +#include "buffer.h" +#include "packet.h" +#include "xmalloc.h" +#include "dispatch.h" +#include "log.h" + +static int auth2_challenge_start(Authctxt *); +static int send_userauth_info_request(Authctxt *); +static void input_userauth_info_response(int, u_int32_t, void *); + +#ifdef BSD_AUTH +extern KbdintDevice bsdauth_device; +#else +#ifdef USE_PAM +extern KbdintDevice sshpam_device; +#endif +#ifdef SKEY +extern KbdintDevice skey_device; +#endif +#endif + +KbdintDevice *devices[] = { +#ifdef BSD_AUTH + &bsdauth_device, +#else +#ifdef USE_PAM + &sshpam_device, +#endif +#ifdef SKEY + &skey_device, +#endif +#endif + NULL +}; + +typedef struct KbdintAuthctxt KbdintAuthctxt; +struct KbdintAuthctxt +{ + char *devices; + void *ctxt; + KbdintDevice *device; + u_int nreq; +}; + +static KbdintAuthctxt * +kbdint_alloc(const char *devs) +{ + KbdintAuthctxt *kbdintctxt; + Buffer b; + int i; + + kbdintctxt = xmalloc(sizeof(KbdintAuthctxt)); + if (strcmp(devs, "") == 0) { + buffer_init(&b); + for (i = 0; devices[i]; i++) { + if (buffer_len(&b) > 0) + buffer_append(&b, ",", 1); + buffer_append(&b, devices[i]->name, + strlen(devices[i]->name)); + } + buffer_append(&b, "\0", 1); + kbdintctxt->devices = xstrdup(buffer_ptr(&b)); + buffer_free(&b); + } else { + kbdintctxt->devices = xstrdup(devs); + } + debug("kbdint_alloc: devices '%s'", kbdintctxt->devices); + kbdintctxt->ctxt = NULL; + kbdintctxt->device = NULL; + kbdintctxt->nreq = 0; + + return kbdintctxt; +} +static void +kbdint_reset_device(KbdintAuthctxt *kbdintctxt) +{ + if (kbdintctxt->ctxt) { + kbdintctxt->device->free_ctx(kbdintctxt->ctxt); + kbdintctxt->ctxt = NULL; + } + kbdintctxt->device = NULL; +} +static void +kbdint_free(KbdintAuthctxt *kbdintctxt) +{ + if (kbdintctxt->device) + kbdint_reset_device(kbdintctxt); + if (kbdintctxt->devices) { + xfree(kbdintctxt->devices); + kbdintctxt->devices = NULL; + } + xfree(kbdintctxt); +} +/* get next device */ +static int +kbdint_next_device(KbdintAuthctxt *kbdintctxt) +{ + size_t len; + char *t; + int i; + + if (kbdintctxt->device) + kbdint_reset_device(kbdintctxt); + do { + len = kbdintctxt->devices ? + strcspn(kbdintctxt->devices, ",") : 0; + + if (len == 0) + break; + for (i = 0; devices[i]; i++) + if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0) + kbdintctxt->device = devices[i]; + t = kbdintctxt->devices; + kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL; + xfree(t); + debug2("kbdint_next_device: devices %s", kbdintctxt->devices ? + kbdintctxt->devices : ""); + } while (kbdintctxt->devices && !kbdintctxt->device); + + return kbdintctxt->device ? 1 : 0; +} + +/* + * try challenge-response, set authctxt->postponed if we have to + * wait for the response. + */ +int +auth2_challenge(Authctxt *authctxt, char *devs) +{ + debug("auth2_challenge: user=%s devs=%s", + authctxt->user ? authctxt->user : "", + devs ? devs : ""); + + if (authctxt->user == NULL || !devs) + return 0; + if (authctxt->kbdintctxt == NULL) + authctxt->kbdintctxt = kbdint_alloc(devs); + return auth2_challenge_start(authctxt); +} + +/* unregister kbd-int callbacks and context */ +void +auth2_challenge_stop(Authctxt *authctxt) +{ + /* unregister callback */ + dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); + if (authctxt->kbdintctxt != NULL) { + kbdint_free(authctxt->kbdintctxt); + authctxt->kbdintctxt = NULL; + } +} + +/* side effect: sets authctxt->postponed if a reply was sent*/ +static int +auth2_challenge_start(Authctxt *authctxt) +{ + KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt; + + debug2("auth2_challenge_start: devices %s", + kbdintctxt->devices ? kbdintctxt->devices : ""); + + if (kbdint_next_device(kbdintctxt) == 0) { + auth2_challenge_stop(authctxt); + return 0; + } + debug("auth2_challenge_start: trying authentication method '%s'", + kbdintctxt->device->name); + + if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) { + auth2_challenge_stop(authctxt); + return 0; + } + if (send_userauth_info_request(authctxt) == 0) { + auth2_challenge_stop(authctxt); + return 0; + } + dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, + &input_userauth_info_response); + + authctxt->postponed = 1; + return 0; +} + +static int +send_userauth_info_request(Authctxt *authctxt) +{ + KbdintAuthctxt *kbdintctxt; + char *name, *instr, **prompts; + int i; + u_int *echo_on; + + kbdintctxt = authctxt->kbdintctxt; + if (kbdintctxt->device->query(kbdintctxt->ctxt, + &name, &instr, &kbdintctxt->nreq, &prompts, &echo_on)) + return 0; + + packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); + packet_put_cstring(name); + packet_put_cstring(instr); + packet_put_cstring(""); /* language not used */ + packet_put_int(kbdintctxt->nreq); + for (i = 0; i < kbdintctxt->nreq; i++) { + packet_put_cstring(prompts[i]); + packet_put_char(echo_on[i]); + } + packet_send(); + packet_write_wait(); + + for (i = 0; i < kbdintctxt->nreq; i++) + xfree(prompts[i]); + xfree(prompts); + xfree(echo_on); + xfree(name); + xfree(instr); + return 1; +} + +static void +input_userauth_info_response(int type, u_int32_t seq, void *ctxt) +{ + Authctxt *authctxt = ctxt; + KbdintAuthctxt *kbdintctxt; + int i, authenticated = 0, res, len; + u_int nresp; + char **response = NULL, *method; + + if (authctxt == NULL) + fatal("input_userauth_info_response: no authctxt"); + kbdintctxt = authctxt->kbdintctxt; + if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL) + fatal("input_userauth_info_response: no kbdintctxt"); + if (kbdintctxt->device == NULL) + fatal("input_userauth_info_response: no device"); + + authctxt->postponed = 0; /* reset */ + nresp = packet_get_int(); + if (nresp != kbdintctxt->nreq) + fatal("input_userauth_info_response: wrong number of replies"); + if (nresp > 100) + fatal("input_userauth_info_response: too many replies"); + if (nresp > 0) { + response = xmalloc(nresp * sizeof(char *)); + for (i = 0; i < nresp; i++) + response[i] = packet_get_string(NULL); + } + packet_check_eom(); + + if (authctxt->valid) { + res = kbdintctxt->device->respond(kbdintctxt->ctxt, + nresp, response); + } else { + res = -1; + } + + for (i = 0; i < nresp; i++) { + memset(response[i], 'r', strlen(response[i])); + xfree(response[i]); + } + if (response) + xfree(response); + + switch (res) { + case 0: + /* Success! */ + authenticated = 1; + break; + case 1: + /* Authentication needs further interaction */ + if (send_userauth_info_request(authctxt) == 1) + authctxt->postponed = 1; + break; + default: + /* Failure! */ + break; + } + + len = strlen("keyboard-interactive") + 2 + + strlen(kbdintctxt->device->name); + method = xmalloc(len); + snprintf(method, len, "keyboard-interactive/%s", + kbdintctxt->device->name); + + if (!authctxt->postponed) { + if (authenticated) { + auth2_challenge_stop(authctxt); + } else { + /* start next device */ + /* may set authctxt->postponed */ + auth2_challenge_start(authctxt); + } + } + userauth_finish(authctxt, authenticated, method); + xfree(method); +} + +void +privsep_challenge_enable(void) +{ +#if defined(BSD_AUTH) || defined(USE_PAM) || defined(SKEY) + int n = 0; +#endif +#ifdef BSD_AUTH + extern KbdintDevice mm_bsdauth_device; +#endif +#ifdef USE_PAM + extern KbdintDevice mm_sshpam_device; +#endif +#ifdef SKEY + extern KbdintDevice mm_skey_device; +#endif + +#ifdef BSD_AUTH + devices[n++] = &mm_bsdauth_device; +#else +#ifdef USE_PAM + devices[n++] = &mm_sshpam_device; +#endif +#ifdef SKEY + devices[n++] = &mm_skey_device; +#endif +#endif +} diff --git a/crypto/openssh-3.9p1/auth2-gss.c b/crypto/openssh-3.9p1/auth2-gss.c new file mode 100644 index 0000000000..3289ba18ee --- /dev/null +++ b/crypto/openssh-3.9p1/auth2-gss.c @@ -0,0 +1,295 @@ +/* $OpenBSD: auth2-gss.c,v 1.8 2004/06/21 17:36:31 avsm Exp $ */ + +/* + * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#ifdef GSSAPI + +#include "auth.h" +#include "ssh2.h" +#include "xmalloc.h" +#include "log.h" +#include "dispatch.h" +#include "servconf.h" +#include "compat.h" +#include "packet.h" +#include "monitor_wrap.h" + +#include "ssh-gss.h" + +extern ServerOptions options; + +static void input_gssapi_token(int type, u_int32_t plen, void *ctxt); +static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); +static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); +static void input_gssapi_errtok(int, u_int32_t, void *); + +/* + * We only support those mechanisms that we know about (ie ones that we know + * how to check local user kuserok and the like + */ +static int +userauth_gssapi(Authctxt *authctxt) +{ + gss_OID_desc goid = {0, NULL}; + Gssctxt *ctxt = NULL; + int mechs; + gss_OID_set supported; + int present; + OM_uint32 ms; + u_int len; + char *doid = NULL; + + if (!authctxt->valid || authctxt->user == NULL) + return (0); + + mechs = packet_get_int(); + if (mechs == 0) { + debug("Mechanism negotiation is not supported"); + return (0); + } + + ssh_gssapi_supported_oids(&supported); + do { + mechs--; + + if (doid) + xfree(doid); + + present = 0; + doid = packet_get_string(&len); + + if (len > 2 && + doid[0] == SSH_GSS_OIDTYPE && + doid[1] == len - 2) { + goid.elements = doid + 2; + goid.length = len - 2; + gss_test_oid_set_member(&ms, &goid, supported, + &present); + } else { + logit("Badly formed OID received"); + } + } while (mechs > 0 && !present); + + gss_release_oid_set(&ms, &supported); + + if (!present) { + xfree(doid); + return (0); + } + + if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) { + xfree(doid); + return (0); + } + + authctxt->methoddata=(void *)ctxt; + + packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE); + + /* Return the OID that we received */ + packet_put_string(doid, len); + + packet_send(); + xfree(doid); + + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); + authctxt->postponed = 1; + + return (0); +} + +static void +input_gssapi_token(int type, u_int32_t plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc recv_tok; + OM_uint32 maj_status, min_status, flags; + u_int len; + + if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) + fatal("No authentication or GSSAPI context"); + + gssctxt = authctxt->methoddata; + recv_tok.value = packet_get_string(&len); + recv_tok.length = len; /* u_int vs. size_t */ + + packet_check_eom(); + + maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, + &send_tok, &flags)); + + xfree(recv_tok.value); + + if (GSS_ERROR(maj_status)) { + if (send_tok.length != 0) { + packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); + packet_put_string(send_tok.value, send_tok.length); + packet_send(); + } + authctxt->postponed = 0; + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + userauth_finish(authctxt, 0, "gssapi-with-mic"); + } else { + if (send_tok.length != 0) { + packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); + packet_put_string(send_tok.value, send_tok.length); + packet_send(); + } + if (maj_status == GSS_S_COMPLETE) { + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + if (flags & GSS_C_INTEG_FLAG) + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, + &input_gssapi_mic); + else + dispatch_set( + SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, + &input_gssapi_exchange_complete); + } + } + + gss_release_buffer(&min_status, &send_tok); +} + +static void +input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc recv_tok; + OM_uint32 maj_status; + u_int len; + + if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) + fatal("No authentication or GSSAPI context"); + + gssctxt = authctxt->methoddata; + recv_tok.value = packet_get_string(&len); + recv_tok.length = len; + + packet_check_eom(); + + /* Push the error token into GSSAPI to see what it says */ + maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, + &send_tok, NULL)); + + xfree(recv_tok.value); + + /* We can't return anything to the client, even if we wanted to */ + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); + + /* The client will have already moved on to the next auth */ + + gss_release_buffer(&maj_status, &send_tok); +} + +/* + * This is called when the client thinks we've completed authentication. + * It should only be enabled in the dispatch handler by the function above, + * which only enables it once the GSSAPI exchange is complete. + */ + +static void +input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; + int authenticated; + + if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) + fatal("No authentication or GSSAPI context"); + + gssctxt = authctxt->methoddata; + + /* + * We don't need to check the status, because we're only enabled in + * the dispatcher once the exchange is complete + */ + + packet_check_eom(); + + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); + + authctxt->postponed = 0; + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); + userauth_finish(authctxt, authenticated, "gssapi-with-mic"); +} + +static void +input_gssapi_mic(int type, u_int32_t plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; + int authenticated = 0; + Buffer b; + gss_buffer_desc mic, gssbuf; + u_int len; + + if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) + fatal("No authentication or GSSAPI context"); + + gssctxt = authctxt->methoddata; + + mic.value = packet_get_string(&len); + mic.length = len; + + ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service, + "gssapi-with-mic"); + + gssbuf.value = buffer_ptr(&b); + gssbuf.length = buffer_len(&b); + + if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) + authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); + else + logit("GSSAPI MIC check failed"); + + buffer_free(&b); + xfree(mic.value); + + authctxt->postponed = 0; + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); + userauth_finish(authctxt, authenticated, "gssapi-with-mic"); +} + +Authmethod method_gssapi = { + "gssapi-with-mic", + userauth_gssapi, + &options.gss_authentication +}; + +#endif /* GSSAPI */ diff --git a/crypto/openssh-3.9p1/auth2-hostbased.c b/crypto/openssh-3.9p1/auth2-hostbased.c new file mode 100644 index 0000000000..1111ed67a6 --- /dev/null +++ b/crypto/openssh-3.9p1/auth2-hostbased.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth2-hostbased.c,v 1.6 2004/01/19 21:25:15 markus Exp $"); + +#include "ssh2.h" +#include "xmalloc.h" +#include "packet.h" +#include "buffer.h" +#include "log.h" +#include "servconf.h" +#include "compat.h" +#include "bufaux.h" +#include "auth.h" +#include "key.h" +#include "canohost.h" +#include "monitor_wrap.h" +#include "pathnames.h" + +/* import */ +extern ServerOptions options; +extern u_char *session_id2; +extern u_int session_id2_len; + +static int +userauth_hostbased(Authctxt *authctxt) +{ + Buffer b; + Key *key = NULL; + char *pkalg, *cuser, *chost, *service; + u_char *pkblob, *sig; + u_int alen, blen, slen; + int pktype; + int authenticated = 0; + + if (!authctxt->valid) { + debug2("userauth_hostbased: disabled because of invalid user"); + return 0; + } + pkalg = packet_get_string(&alen); + pkblob = packet_get_string(&blen); + chost = packet_get_string(NULL); + cuser = packet_get_string(NULL); + sig = packet_get_string(&slen); + + debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d", + cuser, chost, pkalg, slen); +#ifdef DEBUG_PK + debug("signature:"); + buffer_init(&b); + buffer_append(&b, sig, slen); + buffer_dump(&b); + buffer_free(&b); +#endif + pktype = key_type_from_name(pkalg); + if (pktype == KEY_UNSPEC) { + /* this is perfectly legal */ + logit("userauth_hostbased: unsupported " + "public key algorithm: %s", pkalg); + goto done; + } + key = key_from_blob(pkblob, blen); + if (key == NULL) { + error("userauth_hostbased: cannot decode key: %s", pkalg); + goto done; + } + if (key->type != pktype) { + error("userauth_hostbased: type mismatch for decoded key " + "(received %d, expected %d)", key->type, pktype); + goto done; + } + service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : + authctxt->service; + buffer_init(&b); + buffer_put_string(&b, session_id2, session_id2_len); + /* reconstruct packet */ + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(&b, authctxt->user); + buffer_put_cstring(&b, service); + buffer_put_cstring(&b, "hostbased"); + buffer_put_string(&b, pkalg, alen); + buffer_put_string(&b, pkblob, blen); + buffer_put_cstring(&b, chost); + buffer_put_cstring(&b, cuser); +#ifdef DEBUG_PK + buffer_dump(&b); +#endif + /* test for allowed key and correct signature */ + authenticated = 0; + if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && + PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b))) == 1) + authenticated = 1; + + buffer_free(&b); +done: + debug2("userauth_hostbased: authenticated %d", authenticated); + if (key != NULL) + key_free(key); + xfree(pkalg); + xfree(pkblob); + xfree(cuser); + xfree(chost); + xfree(sig); + return authenticated; +} + +/* return 1 if given hostkey is allowed */ +int +hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, + Key *key) +{ + const char *resolvedname, *ipaddr, *lookup; + HostStatus host_status; + int len; + + resolvedname = get_canonical_hostname(options.use_dns); + ipaddr = get_remote_ipaddr(); + + debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s", + chost, resolvedname, ipaddr); + + if (options.hostbased_uses_name_from_packet_only) { + if (auth_rhosts2(pw, cuser, chost, chost) == 0) + return 0; + lookup = chost; + } else { + if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') { + debug2("stripping trailing dot from chost %s", chost); + chost[len - 1] = '\0'; + } + if (strcasecmp(resolvedname, chost) != 0) + logit("userauth_hostbased mismatch: " + "client sends %s, but we resolve %s to %s", + chost, ipaddr, resolvedname); + if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0) + return 0; + lookup = resolvedname; + } + debug2("userauth_hostbased: access allowed by auth_rhosts2"); + + host_status = check_key_in_hostfiles(pw, key, lookup, + _PATH_SSH_SYSTEM_HOSTFILE, + options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); + + /* backward compat if no key has been found. */ + if (host_status == HOST_NEW) + host_status = check_key_in_hostfiles(pw, key, lookup, + _PATH_SSH_SYSTEM_HOSTFILE2, + options.ignore_user_known_hosts ? NULL : + _PATH_SSH_USER_HOSTFILE2); + + return (host_status == HOST_OK); +} + +Authmethod method_hostbased = { + "hostbased", + userauth_hostbased, + &options.hostbased_authentication +}; diff --git a/crypto/openssh-3.9p1/auth2-kbdint.c b/crypto/openssh-3.9p1/auth2-kbdint.c new file mode 100644 index 0000000000..1696ef4d3b --- /dev/null +++ b/crypto/openssh-3.9p1/auth2-kbdint.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth2-kbdint.c,v 1.2 2002/05/31 11:35:15 markus Exp $"); + +#include "packet.h" +#include "auth.h" +#include "log.h" +#include "servconf.h" +#include "xmalloc.h" + +/* import */ +extern ServerOptions options; + +static int +userauth_kbdint(Authctxt *authctxt) +{ + int authenticated = 0; + char *lang, *devs; + + lang = packet_get_string(NULL); + devs = packet_get_string(NULL); + packet_check_eom(); + + debug("keyboard-interactive devs %s", devs); + + if (options.challenge_response_authentication) + authenticated = auth2_challenge(authctxt, devs); + + xfree(devs); + xfree(lang); +#ifdef HAVE_CYGWIN + if (check_nt_auth(0, authctxt->pw) == 0) + return(0); +#endif + return authenticated; +} + +Authmethod method_kbdint = { + "keyboard-interactive", + userauth_kbdint, + &options.kbd_interactive_authentication +}; diff --git a/crypto/openssh-3.9p1/auth2-none.c b/crypto/openssh-3.9p1/auth2-none.c new file mode 100644 index 0000000000..2bf5b5c80c --- /dev/null +++ b/crypto/openssh-3.9p1/auth2-none.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth2-none.c,v 1.7 2004/05/11 19:01:43 deraadt Exp $"); + +#include "auth.h" +#include "xmalloc.h" +#include "packet.h" +#include "log.h" +#include "servconf.h" +#include "atomicio.h" +#include "compat.h" +#include "ssh2.h" +#include "monitor_wrap.h" + +/* import */ +extern ServerOptions options; + +/* "none" is allowed only one time */ +static int none_enabled = 1; + +char * +auth2_read_banner(void) +{ + struct stat st; + char *banner = NULL; + size_t len, n; + int fd; + + if ((fd = open(options.banner, O_RDONLY)) == -1) + return (NULL); + if (fstat(fd, &st) == -1) { + close(fd); + return (NULL); + } + if (st.st_size > 1*1024*1024) { + close(fd); + return (NULL); + } + + len = (size_t)st.st_size; /* truncate */ + banner = xmalloc(len + 1); + n = atomicio(read, fd, banner, len); + close(fd); + + if (n != len) { + xfree(banner); + return (NULL); + } + banner[n] = '\0'; + + return (banner); +} + +static void +userauth_banner(void) +{ + char *banner = NULL; + + if (options.banner == NULL || (datafellows & SSH_BUG_BANNER)) + return; + + if ((banner = PRIVSEP(auth2_read_banner())) == NULL) + goto done; + + packet_start(SSH2_MSG_USERAUTH_BANNER); + packet_put_cstring(banner); + packet_put_cstring(""); /* language, unused */ + packet_send(); + debug("userauth_banner: sent"); +done: + if (banner) + xfree(banner); +} + +static int +userauth_none(Authctxt *authctxt) +{ + none_enabled = 0; + packet_check_eom(); + userauth_banner(); +#ifdef HAVE_CYGWIN + if (check_nt_auth(1, authctxt->pw) == 0) + return(0); +#endif + if (options.password_authentication) + return (PRIVSEP(auth_password(authctxt, ""))); + return (0); +} + +Authmethod method_none = { + "none", + userauth_none, + &none_enabled +}; diff --git a/crypto/openssh-3.9p1/auth2-passwd.c b/crypto/openssh-3.9p1/auth2-passwd.c new file mode 100644 index 0000000000..a4f482d2e2 --- /dev/null +++ b/crypto/openssh-3.9p1/auth2-passwd.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth2-passwd.c,v 1.5 2003/12/31 00:24:50 dtucker Exp $"); + +#include "xmalloc.h" +#include "packet.h" +#include "log.h" +#include "auth.h" +#include "monitor_wrap.h" +#include "servconf.h" + +/* import */ +extern ServerOptions options; + +static int +userauth_passwd(Authctxt *authctxt) +{ + char *password, *newpass; + int authenticated = 0; + int change; + u_int len, newlen; + + change = packet_get_char(); + password = packet_get_string(&len); + if (change) { + /* discard new password from packet */ + newpass = packet_get_string(&newlen); + memset(newpass, 0, newlen); + xfree(newpass); + } + packet_check_eom(); + + if (change) + logit("password change not supported"); + else if (PRIVSEP(auth_password(authctxt, password)) == 1 +#ifdef HAVE_CYGWIN + && check_nt_auth(1, authctxt->pw) +#endif + ) + authenticated = 1; + memset(password, 0, len); + xfree(password); + return authenticated; +} + +Authmethod method_passwd = { + "password", + userauth_passwd, + &options.password_authentication +}; diff --git a/crypto/openssh-3.9p1/auth2-pubkey.c b/crypto/openssh-3.9p1/auth2-pubkey.c new file mode 100644 index 0000000000..9898d4a63b --- /dev/null +++ b/crypto/openssh-3.9p1/auth2-pubkey.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth2-pubkey.c,v 1.7 2004/06/21 17:36:31 avsm Exp $"); + +#include "ssh2.h" +#include "xmalloc.h" +#include "packet.h" +#include "buffer.h" +#include "log.h" +#include "servconf.h" +#include "compat.h" +#include "bufaux.h" +#include "auth.h" +#include "key.h" +#include "pathnames.h" +#include "uidswap.h" +#include "auth-options.h" +#include "canohost.h" +#include "monitor_wrap.h" + +/* import */ +extern ServerOptions options; +extern u_char *session_id2; +extern u_int session_id2_len; + +static int +userauth_pubkey(Authctxt *authctxt) +{ + Buffer b; + Key *key = NULL; + char *pkalg; + u_char *pkblob, *sig; + u_int alen, blen, slen; + int have_sig, pktype; + int authenticated = 0; + + if (!authctxt->valid) { + debug2("userauth_pubkey: disabled because of invalid user"); + return 0; + } + have_sig = packet_get_char(); + if (datafellows & SSH_BUG_PKAUTH) { + debug2("userauth_pubkey: SSH_BUG_PKAUTH"); + /* no explicit pkalg given */ + pkblob = packet_get_string(&blen); + buffer_init(&b); + buffer_append(&b, pkblob, blen); + /* so we have to extract the pkalg from the pkblob */ + pkalg = buffer_get_string(&b, &alen); + buffer_free(&b); + } else { + pkalg = packet_get_string(&alen); + pkblob = packet_get_string(&blen); + } + pktype = key_type_from_name(pkalg); + if (pktype == KEY_UNSPEC) { + /* this is perfectly legal */ + logit("userauth_pubkey: unsupported public key algorithm: %s", + pkalg); + goto done; + } + key = key_from_blob(pkblob, blen); + if (key == NULL) { + error("userauth_pubkey: cannot decode key: %s", pkalg); + goto done; + } + if (key->type != pktype) { + error("userauth_pubkey: type mismatch for decoded key " + "(received %d, expected %d)", key->type, pktype); + goto done; + } + if (have_sig) { + sig = packet_get_string(&slen); + packet_check_eom(); + buffer_init(&b); + if (datafellows & SSH_OLD_SESSIONID) { + buffer_append(&b, session_id2, session_id2_len); + } else { + buffer_put_string(&b, session_id2, session_id2_len); + } + /* reconstruct packet */ + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(&b, authctxt->user); + buffer_put_cstring(&b, + datafellows & SSH_BUG_PKSERVICE ? + "ssh-userauth" : + authctxt->service); + if (datafellows & SSH_BUG_PKAUTH) { + buffer_put_char(&b, have_sig); + } else { + buffer_put_cstring(&b, "publickey"); + buffer_put_char(&b, have_sig); + buffer_put_cstring(&b, pkalg); + } + buffer_put_string(&b, pkblob, blen); +#ifdef DEBUG_PK + buffer_dump(&b); +#endif + /* test for correct signature */ + authenticated = 0; + if (PRIVSEP(user_key_allowed(authctxt->pw, key)) && + PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), + buffer_len(&b))) == 1) + authenticated = 1; + buffer_free(&b); + xfree(sig); + } else { + debug("test whether pkalg/pkblob are acceptable"); + packet_check_eom(); + + /* XXX fake reply and always send PK_OK ? */ + /* + * XXX this allows testing whether a user is allowed + * to login: if you happen to have a valid pubkey this + * message is sent. the message is NEVER sent at all + * if a user is not allowed to login. is this an + * issue? -markus + */ + if (PRIVSEP(user_key_allowed(authctxt->pw, key))) { + packet_start(SSH2_MSG_USERAUTH_PK_OK); + packet_put_string(pkalg, alen); + packet_put_string(pkblob, blen); + packet_send(); + packet_write_wait(); + authctxt->postponed = 1; + } + } + if (authenticated != 1) + auth_clear_options(); +done: + debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); + if (key != NULL) + key_free(key); + xfree(pkalg); + xfree(pkblob); +#ifdef HAVE_CYGWIN + if (check_nt_auth(0, authctxt->pw) == 0) + return(0); +#endif + return authenticated; +} + +/* return 1 if user allows given key */ +static int +user_key_allowed2(struct passwd *pw, Key *key, char *file) +{ + char line[8192]; + int found_key = 0; + FILE *f; + u_long linenum = 0; + struct stat st; + Key *found; + char *fp; + + /* Temporarily use the user's uid. */ + temporarily_use_uid(pw); + + debug("trying public key file %s", file); + + /* Fail quietly if file does not exist */ + if (stat(file, &st) < 0) { + /* Restore the privileged uid. */ + restore_uid(); + return 0; + } + /* Open the file containing the authorized keys. */ + f = fopen(file, "r"); + if (!f) { + /* Restore the privileged uid. */ + restore_uid(); + return 0; + } + if (options.strict_modes && + secure_filename(f, file, pw, line, sizeof(line)) != 0) { + fclose(f); + logit("Authentication refused: %s", line); + restore_uid(); + return 0; + } + + found_key = 0; + found = key_new(key->type); + + while (fgets(line, sizeof(line), f)) { + char *cp, *key_options = NULL; + linenum++; + /* Skip leading whitespace, empty and comment lines. */ + for (cp = line; *cp == ' ' || *cp == '\t'; cp++) + ; + if (!*cp || *cp == '\n' || *cp == '#') + continue; + + if (key_read(found, &cp) != 1) { + /* no key? check if there are options for this key */ + int quoted = 0; + debug2("user_key_allowed: check options: '%s'", cp); + key_options = cp; + for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { + if (*cp == '\\' && cp[1] == '"') + cp++; /* Skip both */ + else if (*cp == '"') + quoted = !quoted; + } + /* Skip remaining whitespace. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + if (key_read(found, &cp) != 1) { + debug2("user_key_allowed: advance: '%s'", cp); + /* still no key? advance to next line*/ + continue; + } + } + if (key_equal(found, key) && + auth_parse_options(pw, key_options, file, linenum) == 1) { + found_key = 1; + debug("matching key found: file %s, line %lu", + file, linenum); + fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); + verbose("Found matching %s key: %s", + key_type(found), fp); + xfree(fp); + break; + } + } + restore_uid(); + fclose(f); + key_free(found); + if (!found_key) + debug2("key not found"); + return found_key; +} + +/* check whether given key is in .ssh/authorized_keys* */ +int +user_key_allowed(struct passwd *pw, Key *key) +{ + int success; + char *file; + + file = authorized_keys_file(pw); + success = user_key_allowed2(pw, key, file); + xfree(file); + if (success) + return success; + + /* try suffix "2" for backward compat, too */ + file = authorized_keys_file2(pw); + success = user_key_allowed2(pw, key, file); + xfree(file); + return success; +} + +Authmethod method_pubkey = { + "publickey", + userauth_pubkey, + &options.pubkey_authentication +}; diff --git a/crypto/openssh-3.9p1/auth2.c b/crypto/openssh-3.9p1/auth2.c new file mode 100644 index 0000000000..b983095765 --- /dev/null +++ b/crypto/openssh-3.9p1/auth2.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: auth2.c,v 1.107 2004/07/28 09:40:29 markus Exp $"); + +#include "ssh2.h" +#include "xmalloc.h" +#include "packet.h" +#include "log.h" +#include "servconf.h" +#include "compat.h" +#include "auth.h" +#include "dispatch.h" +#include "pathnames.h" +#include "monitor_wrap.h" + +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + +/* import */ +extern ServerOptions options; +extern u_char *session_id2; +extern u_int session_id2_len; + +/* methods */ + +extern Authmethod method_none; +extern Authmethod method_pubkey; +extern Authmethod method_passwd; +extern Authmethod method_kbdint; +extern Authmethod method_hostbased; +#ifdef GSSAPI +extern Authmethod method_gssapi; +#endif + +Authmethod *authmethods[] = { + &method_none, + &method_pubkey, +#ifdef GSSAPI + &method_gssapi, +#endif + &method_passwd, + &method_kbdint, + &method_hostbased, + NULL +}; + +/* protocol */ + +static void input_service_request(int, u_int32_t, void *); +static void input_userauth_request(int, u_int32_t, void *); + +/* helper */ +static Authmethod *authmethod_lookup(const char *); +static char *authmethods_get(void); +int user_key_allowed(struct passwd *, Key *); + +/* + * loop until authctxt->success == TRUE + */ + +void +do_authentication2(Authctxt *authctxt) +{ + /* challenge-response is implemented via keyboard interactive */ + if (options.challenge_response_authentication) + options.kbd_interactive_authentication = 1; + + dispatch_init(&dispatch_protocol_error); + dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request); + dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt); +} + +static void +input_service_request(int type, u_int32_t seq, void *ctxt) +{ + Authctxt *authctxt = ctxt; + u_int len; + int acceptit = 0; + char *service = packet_get_string(&len); + packet_check_eom(); + + if (authctxt == NULL) + fatal("input_service_request: no authctxt"); + + if (strcmp(service, "ssh-userauth") == 0) { + if (!authctxt->success) { + acceptit = 1; + /* now we can handle user-auth requests */ + dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request); + } + } + /* XXX all other service requests are denied */ + + if (acceptit) { + packet_start(SSH2_MSG_SERVICE_ACCEPT); + packet_put_cstring(service); + packet_send(); + packet_write_wait(); + } else { + debug("bad service request %s", service); + packet_disconnect("bad service request %s", service); + } + xfree(service); +} + +static void +input_userauth_request(int type, u_int32_t seq, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Authmethod *m = NULL; + char *user, *service, *method, *style = NULL; + int authenticated = 0; + + if (authctxt == NULL) + fatal("input_userauth_request: no authctxt"); + + user = packet_get_string(NULL); + service = packet_get_string(NULL); + method = packet_get_string(NULL); + debug("userauth-request for user %s service %s method %s", user, service, method); + debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); + + if ((style = strchr(user, ':')) != NULL) + *style++ = 0; + + if (authctxt->attempt++ == 0) { + /* setup auth context */ + authctxt->pw = PRIVSEP(getpwnamallow(user)); + authctxt->user = xstrdup(user); + if (authctxt->pw && strcmp(service, "ssh-connection")==0) { + authctxt->valid = 1; + debug2("input_userauth_request: setting up authctxt for %s", user); +#ifdef USE_PAM + if (options.use_pam) + PRIVSEP(start_pam(authctxt)); +#endif + } else { + logit("input_userauth_request: invalid user %s", user); + authctxt->pw = fakepw(); +#ifdef USE_PAM + if (options.use_pam) + PRIVSEP(start_pam(authctxt)); +#endif + } + setproctitle("%s%s", authctxt->valid ? user : "unknown", + use_privsep ? " [net]" : ""); + authctxt->service = xstrdup(service); + authctxt->style = style ? xstrdup(style) : NULL; + if (use_privsep) + mm_inform_authserv(service, style); + } else if (strcmp(user, authctxt->user) != 0 || + strcmp(service, authctxt->service) != 0) { + packet_disconnect("Change of username or service not allowed: " + "(%s,%s) -> (%s,%s)", + authctxt->user, authctxt->service, user, service); + } + /* reset state */ + auth2_challenge_stop(authctxt); + +#ifdef GSSAPI + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); +#endif + + authctxt->postponed = 0; + + /* try to authenticate user */ + m = authmethod_lookup(method); + if (m != NULL) { + debug2("input_userauth_request: try method %s", method); + authenticated = m->userauth(authctxt); + } + userauth_finish(authctxt, authenticated, method); + + xfree(service); + xfree(user); + xfree(method); +} + +void +userauth_finish(Authctxt *authctxt, int authenticated, char *method) +{ + char *methods; + + if (!authctxt->valid && authenticated) + fatal("INTERNAL ERROR: authenticated invalid user %s", + authctxt->user); + + /* Special handling for root */ + if (authenticated && authctxt->pw->pw_uid == 0 && + !auth_root_allowed(method)) + authenticated = 0; + +#ifdef USE_PAM + if (options.use_pam && authenticated && !PRIVSEP(do_pam_account())) + authenticated = 0; +#endif + +#ifdef _UNICOS + if (authenticated && cray_access_denied(authctxt->user)) { + authenticated = 0; + fatal("Access denied for user %s.",authctxt->user); + } +#endif /* _UNICOS */ + + /* Log before sending the reply */ + auth_log(authctxt, authenticated, method, " ssh2"); + + if (authctxt->postponed) + return; + + /* XXX todo: check if multiple auth methods are needed */ + if (authenticated == 1) { + /* turn off userauth */ + dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); + packet_start(SSH2_MSG_USERAUTH_SUCCESS); + packet_send(); + packet_write_wait(); + /* now we can break out */ + authctxt->success = 1; + } else { + if (authctxt->failures++ > options.max_authtries) + packet_disconnect(AUTH_FAIL_MSG, authctxt->user); + methods = authmethods_get(); + packet_start(SSH2_MSG_USERAUTH_FAILURE); + packet_put_cstring(methods); + packet_put_char(0); /* XXX partial success, unused */ + packet_send(); + packet_write_wait(); + xfree(methods); + } +} + +#define DELIM "," + +static char * +authmethods_get(void) +{ + Buffer b; + char *list; + int i; + + buffer_init(&b); + for (i = 0; authmethods[i] != NULL; i++) { + if (strcmp(authmethods[i]->name, "none") == 0) + continue; + if (authmethods[i]->enabled != NULL && + *(authmethods[i]->enabled) != 0) { + if (buffer_len(&b) > 0) + buffer_append(&b, ",", 1); + buffer_append(&b, authmethods[i]->name, + strlen(authmethods[i]->name)); + } + } + buffer_append(&b, "\0", 1); + list = xstrdup(buffer_ptr(&b)); + buffer_free(&b); + return list; +} + +static Authmethod * +authmethod_lookup(const char *name) +{ + int i; + + if (name != NULL) + for (i = 0; authmethods[i] != NULL; i++) + if (authmethods[i]->enabled != NULL && + *(authmethods[i]->enabled) != 0 && + strcmp(name, authmethods[i]->name) == 0) + return authmethods[i]; + debug2("Unrecognized authentication method name: %s", + name ? name : "NULL"); + return NULL; +} diff --git a/crypto/openssh-3.9p1/authfd.c b/crypto/openssh-3.9p1/authfd.c new file mode 100644 index 0000000000..662350cef7 --- /dev/null +++ b/crypto/openssh-3.9p1/authfd.c @@ -0,0 +1,662 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Functions for connecting the local authentication agent. + * + * 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". + * + * SSH2 implementation, + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: authfd.c,v 1.64 2004/08/11 21:44:31 avsm Exp $"); + +#include + +#include "ssh.h" +#include "rsa.h" +#include "buffer.h" +#include "bufaux.h" +#include "xmalloc.h" +#include "getput.h" +#include "key.h" +#include "authfd.h" +#include "cipher.h" +#include "kex.h" +#include "compat.h" +#include "log.h" +#include "atomicio.h" + +static int agent_present = 0; + +/* helper */ +int decode_reply(int type); + +/* macro to check for "agent failure" message */ +#define agent_failed(x) \ + ((x == SSH_AGENT_FAILURE) || (x == SSH_COM_AGENT2_FAILURE) || \ + (x == SSH2_AGENT_FAILURE)) + +int +ssh_agent_present(void) +{ + int authfd; + + if (agent_present) + return 1; + if ((authfd = ssh_get_authentication_socket()) == -1) + return 0; + else { + ssh_close_authentication_socket(authfd); + return 1; + } +} + +/* Returns the number of the authentication fd, or -1 if there is none. */ + +int +ssh_get_authentication_socket(void) +{ + const char *authsocket; + int sock; + struct sockaddr_un sunaddr; + + authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); + if (!authsocket) + return -1; + + sunaddr.sun_family = AF_UNIX; + strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return -1; + + /* close on exec */ + if (fcntl(sock, F_SETFD, 1) == -1) { + close(sock); + return -1; + } + if (connect(sock, (struct sockaddr *) &sunaddr, sizeof sunaddr) < 0) { + close(sock); + return -1; + } + agent_present = 1; + return sock; +} + +static int +ssh_request_reply(AuthenticationConnection *auth, Buffer *request, Buffer *reply) +{ + int l; + u_int len; + char buf[1024]; + + /* Get the length of the message, and format it in the buffer. */ + len = buffer_len(request); + PUT_32BIT(buf, len); + + /* Send the length and then the packet to the agent. */ + if (atomicio(vwrite, auth->fd, buf, 4) != 4 || + atomicio(vwrite, auth->fd, buffer_ptr(request), + buffer_len(request)) != buffer_len(request)) { + error("Error writing to authentication socket."); + return 0; + } + /* + * Wait for response from the agent. First read the length of the + * response packet. + */ + if (atomicio(read, auth->fd, buf, 4) != 4) { + error("Error reading response length from authentication socket."); + return 0; + } + + /* Extract the length, and check it for sanity. */ + len = GET_32BIT(buf); + if (len > 256 * 1024) + fatal("Authentication response too long: %u", len); + + /* Read the rest of the response in to the buffer. */ + buffer_clear(reply); + while (len > 0) { + l = len; + if (l > sizeof(buf)) + l = sizeof(buf); + l = atomicio(read, auth->fd, buf, l); + if (l <= 0) { + error("Error reading response from authentication socket."); + return 0; + } + buffer_append(reply, buf, l); + len -= l; + } + return 1; +} + +/* + * Closes the agent socket if it should be closed (depends on how it was + * obtained). The argument must have been returned by + * ssh_get_authentication_socket(). + */ + +void +ssh_close_authentication_socket(int sock) +{ + if (getenv(SSH_AUTHSOCKET_ENV_NAME)) + close(sock); +} + +/* + * Opens and connects a private socket for communication with the + * authentication agent. Returns the file descriptor (which must be + * shut down and closed by the caller when no longer needed). + * Returns NULL if an error occurred and the connection could not be + * opened. + */ + +AuthenticationConnection * +ssh_get_authentication_connection(void) +{ + AuthenticationConnection *auth; + int sock; + + sock = ssh_get_authentication_socket(); + + /* + * Fail if we couldn't obtain a connection. This happens if we + * exited due to a timeout. + */ + if (sock < 0) + return NULL; + + auth = xmalloc(sizeof(*auth)); + auth->fd = sock; + 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 *auth) +{ + buffer_free(&auth->identities); + close(auth->fd); + xfree(auth); +} + +/* Lock/unlock agent */ +int +ssh_lock_agent(AuthenticationConnection *auth, int lock, const char *password) +{ + int type; + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, lock ? SSH_AGENTC_LOCK : SSH_AGENTC_UNLOCK); + buffer_put_cstring(&msg, password); + + if (ssh_request_reply(auth, &msg, &msg) == 0) { + buffer_free(&msg); + return 0; + } + type = buffer_get_char(&msg); + buffer_free(&msg); + return decode_reply(type); +} + +/* + * Returns the first authentication identity held by the agent. + */ + +int +ssh_get_num_identities(AuthenticationConnection *auth, int version) +{ + int type, code1 = 0, code2 = 0; + Buffer request; + + switch (version) { + case 1: + code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; + code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER; + break; + case 2: + code1 = SSH2_AGENTC_REQUEST_IDENTITIES; + code2 = SSH2_AGENT_IDENTITIES_ANSWER; + break; + default: + return 0; + } + + /* + * Send a message to the agent requesting for a list of the + * identities it can represent. + */ + buffer_init(&request); + buffer_put_char(&request, code1); + + buffer_clear(&auth->identities); + if (ssh_request_reply(auth, &request, &auth->identities) == 0) { + buffer_free(&request); + return 0; + } + buffer_free(&request); + + /* Get message type, and verify that we got a proper answer. */ + type = buffer_get_char(&auth->identities); + if (agent_failed(type)) { + return 0; + } else if (type != code2) { + fatal("Bad authentication reply message type: %d", type); + } + + /* Get the number of entries in the response and check it for sanity. */ + auth->howmany = buffer_get_int(&auth->identities); + if ((u_int)auth->howmany > 1024) + fatal("Too many identities in authentication reply: %d", + auth->howmany); + + return auth->howmany; +} + +Key * +ssh_get_first_identity(AuthenticationConnection *auth, char **comment, int version) +{ + /* get number of identities and return the first entry (if any). */ + if (ssh_get_num_identities(auth, version) > 0) + return ssh_get_next_identity(auth, comment, version); + return NULL; +} + +Key * +ssh_get_next_identity(AuthenticationConnection *auth, char **comment, int version) +{ + u_int bits; + u_char *blob; + u_int blen; + Key *key = NULL; + + /* Return failure if no more entries. */ + if (auth->howmany <= 0) + return NULL; + + /* + * Get the next entry from the packet. These will abort with a fatal + * error if the packet is too short or contains corrupt data. + */ + switch (version) { + case 1: + key = key_new(KEY_RSA1); + bits = buffer_get_int(&auth->identities); + buffer_get_bignum(&auth->identities, key->rsa->e); + buffer_get_bignum(&auth->identities, key->rsa->n); + *comment = buffer_get_string(&auth->identities, NULL); + if (bits != BN_num_bits(key->rsa->n)) + logit("Warning: identity keysize mismatch: actual %d, announced %u", + BN_num_bits(key->rsa->n), bits); + break; + case 2: + blob = buffer_get_string(&auth->identities, &blen); + *comment = buffer_get_string(&auth->identities, NULL); + key = key_from_blob(blob, blen); + xfree(blob); + break; + default: + return NULL; + break; + } + /* Decrement the number of remaining entries. */ + auth->howmany--; + return key; +} + +/* + * 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, + Key* key, BIGNUM *challenge, + u_char session_id[16], + u_int response_type, + u_char response[16]) +{ + Buffer buffer; + int success = 0; + int i; + int type; + + if (key->type != KEY_RSA1) + return 0; + if (response_type == 0) { + logit("Compatibility with ssh protocol version 1.0 no longer supported."); + return 0; + } + buffer_init(&buffer); + buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE); + buffer_put_int(&buffer, BN_num_bits(key->rsa->n)); + buffer_put_bignum(&buffer, key->rsa->e); + buffer_put_bignum(&buffer, key->rsa->n); + buffer_put_bignum(&buffer, challenge); + buffer_append(&buffer, session_id, 16); + buffer_put_int(&buffer, response_type); + + if (ssh_request_reply(auth, &buffer, &buffer) == 0) { + buffer_free(&buffer); + return 0; + } + type = buffer_get_char(&buffer); + + if (agent_failed(type)) { + logit("Agent admitted failure to authenticate using the key."); + } else if (type != SSH_AGENT_RSA_RESPONSE) { + fatal("Bad authentication response: %d", type); + } else { + success = 1; + /* + * 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); + } + buffer_free(&buffer); + return success; +} + +/* ask agent to sign data, returns -1 on error, 0 on success */ +int +ssh_agent_sign(AuthenticationConnection *auth, + Key *key, + u_char **sigp, u_int *lenp, + u_char *data, u_int datalen) +{ + extern int datafellows; + Buffer msg; + u_char *blob; + u_int blen; + int type, flags = 0; + int ret = -1; + + if (key_to_blob(key, &blob, &blen) == 0) + return -1; + + if (datafellows & SSH_BUG_SIGBLOB) + flags = SSH_AGENT_OLD_SIGNATURE; + + buffer_init(&msg); + buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); + buffer_put_string(&msg, blob, blen); + buffer_put_string(&msg, data, datalen); + buffer_put_int(&msg, flags); + xfree(blob); + + if (ssh_request_reply(auth, &msg, &msg) == 0) { + buffer_free(&msg); + return -1; + } + type = buffer_get_char(&msg); + if (agent_failed(type)) { + logit("Agent admitted failure to sign using the key."); + } else if (type != SSH2_AGENT_SIGN_RESPONSE) { + fatal("Bad authentication response: %d", type); + } else { + ret = 0; + *sigp = buffer_get_string(&msg, lenp); + } + buffer_free(&msg); + return ret; +} + +/* Encode key for a message to the agent. */ + +static void +ssh_encode_identity_rsa1(Buffer *b, RSA *key, const char *comment) +{ + buffer_put_int(b, BN_num_bits(key->n)); + buffer_put_bignum(b, key->n); + buffer_put_bignum(b, key->e); + buffer_put_bignum(b, key->d); + /* To keep within the protocol: p < q for ssh. in SSL p > q */ + buffer_put_bignum(b, key->iqmp); /* ssh key->u */ + buffer_put_bignum(b, key->q); /* ssh key->p, SSL key->q */ + buffer_put_bignum(b, key->p); /* ssh key->q, SSL key->p */ + buffer_put_cstring(b, comment); +} + +static void +ssh_encode_identity_ssh2(Buffer *b, Key *key, const char *comment) +{ + buffer_put_cstring(b, key_ssh_name(key)); + switch (key->type) { + case KEY_RSA: + buffer_put_bignum2(b, key->rsa->n); + buffer_put_bignum2(b, key->rsa->e); + buffer_put_bignum2(b, key->rsa->d); + buffer_put_bignum2(b, key->rsa->iqmp); + buffer_put_bignum2(b, key->rsa->p); + buffer_put_bignum2(b, key->rsa->q); + break; + case KEY_DSA: + buffer_put_bignum2(b, key->dsa->p); + buffer_put_bignum2(b, key->dsa->q); + buffer_put_bignum2(b, key->dsa->g); + buffer_put_bignum2(b, key->dsa->pub_key); + buffer_put_bignum2(b, key->dsa->priv_key); + break; + } + buffer_put_cstring(b, comment); +} + +/* + * Adds an identity to the authentication server. This call is not meant to + * be used by normal applications. + */ + +int +ssh_add_identity_constrained(AuthenticationConnection *auth, Key *key, + const char *comment, u_int life, u_int confirm) +{ + Buffer msg; + int type, constrained = (life || confirm); + + buffer_init(&msg); + + switch (key->type) { + case KEY_RSA1: + type = constrained ? + SSH_AGENTC_ADD_RSA_ID_CONSTRAINED : + SSH_AGENTC_ADD_RSA_IDENTITY; + buffer_put_char(&msg, type); + ssh_encode_identity_rsa1(&msg, key->rsa, comment); + break; + case KEY_RSA: + case KEY_DSA: + type = constrained ? + SSH2_AGENTC_ADD_ID_CONSTRAINED : + SSH2_AGENTC_ADD_IDENTITY; + buffer_put_char(&msg, type); + ssh_encode_identity_ssh2(&msg, key, comment); + break; + default: + buffer_free(&msg); + return 0; + break; + } + if (constrained) { + if (life != 0) { + buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); + buffer_put_int(&msg, life); + } + if (confirm != 0) + buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); + } + if (ssh_request_reply(auth, &msg, &msg) == 0) { + buffer_free(&msg); + return 0; + } + type = buffer_get_char(&msg); + buffer_free(&msg); + return decode_reply(type); +} + +int +ssh_add_identity(AuthenticationConnection *auth, Key *key, const char *comment) +{ + return ssh_add_identity_constrained(auth, key, comment, 0, 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, Key *key) +{ + Buffer msg; + int type; + u_char *blob; + u_int blen; + + buffer_init(&msg); + + if (key->type == KEY_RSA1) { + buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); + buffer_put_int(&msg, BN_num_bits(key->rsa->n)); + buffer_put_bignum(&msg, key->rsa->e); + buffer_put_bignum(&msg, key->rsa->n); + } else if (key->type == KEY_DSA || key->type == KEY_RSA) { + key_to_blob(key, &blob, &blen); + buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); + buffer_put_string(&msg, blob, blen); + xfree(blob); + } else { + buffer_free(&msg); + return 0; + } + if (ssh_request_reply(auth, &msg, &msg) == 0) { + buffer_free(&msg); + return 0; + } + type = buffer_get_char(&msg); + buffer_free(&msg); + return decode_reply(type); +} + +int +ssh_update_card(AuthenticationConnection *auth, int add, + const char *reader_id, const char *pin, u_int life, u_int confirm) +{ + Buffer msg; + int type, constrained = (life || confirm); + + if (add) { + type = constrained ? + SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED : + SSH_AGENTC_ADD_SMARTCARD_KEY; + } else + type = SSH_AGENTC_REMOVE_SMARTCARD_KEY; + + buffer_init(&msg); + buffer_put_char(&msg, type); + buffer_put_cstring(&msg, reader_id); + buffer_put_cstring(&msg, pin); + + if (constrained) { + if (life != 0) { + buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_LIFETIME); + buffer_put_int(&msg, life); + } + if (confirm != 0) + buffer_put_char(&msg, SSH_AGENT_CONSTRAIN_CONFIRM); + } + + if (ssh_request_reply(auth, &msg, &msg) == 0) { + buffer_free(&msg); + return 0; + } + type = buffer_get_char(&msg); + buffer_free(&msg); + return decode_reply(type); +} + +/* + * Removes all identities from the agent. This call is not meant to be used + * by normal applications. + */ + +int +ssh_remove_all_identities(AuthenticationConnection *auth, int version) +{ + Buffer msg; + int type; + int code = (version==1) ? + SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES : + SSH2_AGENTC_REMOVE_ALL_IDENTITIES; + + buffer_init(&msg); + buffer_put_char(&msg, code); + + if (ssh_request_reply(auth, &msg, &msg) == 0) { + buffer_free(&msg); + return 0; + } + type = buffer_get_char(&msg); + buffer_free(&msg); + return decode_reply(type); +} + +int +decode_reply(int type) +{ + switch (type) { + case SSH_AGENT_FAILURE: + case SSH_COM_AGENT2_FAILURE: + case SSH2_AGENT_FAILURE: + logit("SSH_AGENT_FAILURE"); + return 0; + case SSH_AGENT_SUCCESS: + return 1; + default: + fatal("Bad response from authentication agent: %d", type); + } + /* NOTREACHED */ + return 0; +} diff --git a/crypto/openssh-3.9p1/authfd.h b/crypto/openssh-3.9p1/authfd.h new file mode 100644 index 0000000000..0a6a4e3ecd --- /dev/null +++ b/crypto/openssh-3.9p1/authfd.h @@ -0,0 +1,97 @@ +/* $OpenBSD: authfd.h,v 1.34 2003/11/21 11:57:03 djm Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Functions to interface with the SSH_AUTHENTICATION_FD socket. + * + * 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". + */ + +#ifndef AUTHFD_H +#define AUTHFD_H + +#include "buffer.h" + +/* 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 + +/* private OpenSSH extensions for SSH2 */ +#define SSH2_AGENTC_REQUEST_IDENTITIES 11 +#define SSH2_AGENT_IDENTITIES_ANSWER 12 +#define SSH2_AGENTC_SIGN_REQUEST 13 +#define SSH2_AGENT_SIGN_RESPONSE 14 +#define SSH2_AGENTC_ADD_IDENTITY 17 +#define SSH2_AGENTC_REMOVE_IDENTITY 18 +#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19 + +/* smartcard */ +#define SSH_AGENTC_ADD_SMARTCARD_KEY 20 +#define SSH_AGENTC_REMOVE_SMARTCARD_KEY 21 + +/* lock/unlock the agent */ +#define SSH_AGENTC_LOCK 22 +#define SSH_AGENTC_UNLOCK 23 + +/* add key with constraints */ +#define SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24 +#define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 +#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26 + +#define SSH_AGENT_CONSTRAIN_LIFETIME 1 +#define SSH_AGENT_CONSTRAIN_CONFIRM 2 + +/* extended failure messages */ +#define SSH2_AGENT_FAILURE 30 + +/* additional error code for ssh.com's ssh-agent2 */ +#define SSH_COM_AGENT2_FAILURE 102 + +#define SSH_AGENT_OLD_SIGNATURE 0x01 + +typedef struct { + int fd; + Buffer identities; + int howmany; +} AuthenticationConnection; + +int ssh_agent_present(void); +int ssh_get_authentication_socket(void); +void ssh_close_authentication_socket(int); + +AuthenticationConnection *ssh_get_authentication_connection(void); +void ssh_close_authentication_connection(AuthenticationConnection *); +int ssh_get_num_identities(AuthenticationConnection *, int); +Key *ssh_get_first_identity(AuthenticationConnection *, char **, int); +Key *ssh_get_next_identity(AuthenticationConnection *, char **, int); +int ssh_add_identity(AuthenticationConnection *, Key *, const char *); +int ssh_add_identity_constrained(AuthenticationConnection *, Key *, + const char *, u_int, u_int); +int ssh_remove_identity(AuthenticationConnection *, Key *); +int ssh_remove_all_identities(AuthenticationConnection *, int); +int ssh_lock_agent(AuthenticationConnection *, int, const char *); +int ssh_update_card(AuthenticationConnection *, int, const char *, + const char *, u_int, u_int); + +int +ssh_decrypt_challenge(AuthenticationConnection *, Key *, BIGNUM *, u_char[16], + u_int, u_char[16]); + +int +ssh_agent_sign(AuthenticationConnection *, Key *, u_char **, u_int *, u_char *, + u_int); + +#endif /* AUTHFD_H */ diff --git a/crypto/openssh-3.9p1/authfile.c b/crypto/openssh-3.9p1/authfile.c new file mode 100644 index 0000000000..76a60d020f --- /dev/null +++ b/crypto/openssh-3.9p1/authfile.c @@ -0,0 +1,660 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * This file contains functions for reading and writing identity files, and + * for reading the passphrase from the user. + * + * 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". + * + * + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: authfile.c,v 1.57 2004/06/21 17:36:31 avsm Exp $"); + +#include +#include +#include + +#include "cipher.h" +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" +#include "key.h" +#include "ssh.h" +#include "log.h" +#include "authfile.h" +#include "rsa.h" + +/* Version identification string for SSH v1 identity files. */ +static const char 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. + */ + +static int +key_save_private_rsa1(Key *key, const char *filename, const char *passphrase, + const char *comment) +{ + Buffer buffer, encrypted; + u_char buf[100], *cp; + int fd, i, cipher_num; + CipherContext ciphercontext; + Cipher *cipher; + u_int32_t rnd; + + /* + * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting + * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. + */ + cipher_num = (strcmp(passphrase, "") == 0) ? + SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER; + if ((cipher = cipher_by_number(cipher_num)) == NULL) + fatal("save_private_key_rsa: bad cipher"); + + /* This buffer is used to built the secret part of the private key. */ + buffer_init(&buffer); + + /* Put checkbytes for checking passphrase validity. */ + rnd = arc4random(); + buf[0] = rnd & 0xff; + buf[1] = (rnd >> 8) & 0xff; + buf[2] = buf[0]; + buf[3] = buf[1]; + buffer_append(&buffer, buf, 4); + + /* + * Store the private key (n and e will not be stored because they + * will be stored in plain text, and storing them also in encrypted + * format would just give known plaintext). + */ + buffer_put_bignum(&buffer, key->rsa->d); + buffer_put_bignum(&buffer, key->rsa->iqmp); + buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */ + buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */ + + /* Pad the part to be encrypted until its size is a multiple of 8. */ + while (buffer_len(&buffer) % 8 != 0) + buffer_put_char(&buffer, 0); + + /* This buffer will be used to contain the data in the file. */ + buffer_init(&encrypted); + + /* First store keyfile id string. */ + for (i = 0; authfile_id_string[i]; i++) + buffer_put_char(&encrypted, authfile_id_string[i]); + buffer_put_char(&encrypted, 0); + + /* Store cipher type. */ + buffer_put_char(&encrypted, cipher_num); + buffer_put_int(&encrypted, 0); /* For future extension */ + + /* Store public key. This will be in plain text. */ + buffer_put_int(&encrypted, BN_num_bits(key->rsa->n)); + buffer_put_bignum(&encrypted, key->rsa->n); + buffer_put_bignum(&encrypted, key->rsa->e); + buffer_put_cstring(&encrypted, comment); + + /* Allocate space for the private part of the key in the buffer. */ + cp = buffer_append_space(&encrypted, buffer_len(&buffer)); + + cipher_set_key_string(&ciphercontext, cipher, passphrase, + CIPHER_ENCRYPT); + cipher_crypt(&ciphercontext, cp, + buffer_ptr(&buffer), buffer_len(&buffer)); + cipher_cleanup(&ciphercontext); + memset(&ciphercontext, 0, sizeof(ciphercontext)); + + /* Destroy temporary data. */ + memset(buf, 0, sizeof(buf)); + buffer_free(&buffer); + + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) { + error("open %s failed: %s.", filename, strerror(errno)); + buffer_free(&encrypted); + return 0; + } + if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) != + buffer_len(&encrypted)) { + error("write to key file %s failed: %s", filename, + strerror(errno)); + buffer_free(&encrypted); + close(fd); + unlink(filename); + return 0; + } + close(fd); + buffer_free(&encrypted); + return 1; +} + +/* save SSH v2 key in OpenSSL PEM format */ +static int +key_save_private_pem(Key *key, const char *filename, const char *_passphrase, + const char *comment) +{ + FILE *fp; + int fd; + int success = 0; + int len = strlen(_passphrase); + u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; + const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; + + if (len > 0 && len <= 4) { + error("passphrase too short: have %d bytes, need > 4", len); + return 0; + } + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0) { + error("open %s failed: %s.", filename, strerror(errno)); + return 0; + } + fp = fdopen(fd, "w"); + if (fp == NULL ) { + error("fdopen %s failed: %s.", filename, strerror(errno)); + close(fd); + return 0; + } + switch (key->type) { + case KEY_DSA: + success = PEM_write_DSAPrivateKey(fp, key->dsa, + cipher, passphrase, len, NULL, NULL); + break; + case KEY_RSA: + success = PEM_write_RSAPrivateKey(fp, key->rsa, + cipher, passphrase, len, NULL, NULL); + break; + } + fclose(fp); + return success; +} + +int +key_save_private(Key *key, const char *filename, const char *passphrase, + const char *comment) +{ + switch (key->type) { + case KEY_RSA1: + return key_save_private_rsa1(key, filename, passphrase, + comment); + break; + case KEY_DSA: + case KEY_RSA: + return key_save_private_pem(key, filename, passphrase, + comment); + break; + default: + break; + } + error("key_save_private: cannot save key type %d", key->type); + return 0; +} + +/* + * Loads the public part of the ssh v1 key file. Returns NULL if an error was + * encountered (the file does not exist or is not readable), and the key + * otherwise. + */ + +static Key * +key_load_public_rsa1(int fd, const char *filename, char **commentp) +{ + Buffer buffer; + Key *pub; + struct stat st; + char *cp; + int i; + size_t len; + + if (fstat(fd, &st) < 0) { + error("fstat for key file %.200s failed: %.100s", + filename, strerror(errno)); + return NULL; + } + if (st.st_size > 1*1024*1024) + close(fd); + len = (size_t)st.st_size; /* truncated */ + + buffer_init(&buffer); + cp = buffer_append_space(&buffer, len); + + if (read(fd, cp, (size_t) len) != (size_t) len) { + debug("Read from key file %.200s failed: %.100s", filename, + strerror(errno)); + buffer_free(&buffer); + return NULL; + } + + /* Check that it is at least big enough to contain the ID string. */ + if (len < sizeof(authfile_id_string)) { + debug3("Not a RSA1 key file %.200s.", filename); + buffer_free(&buffer); + return NULL; + } + /* + * Make sure it begins with the id string. Consume the id string + * from the buffer. + */ + for (i = 0; i < sizeof(authfile_id_string); i++) + if (buffer_get_char(&buffer) != authfile_id_string[i]) { + debug3("Not a RSA1 key file %.200s.", filename); + buffer_free(&buffer); + return NULL; + } + /* 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. */ + (void) buffer_get_int(&buffer); + pub = key_new(KEY_RSA1); + buffer_get_bignum(&buffer, pub->rsa->n); + buffer_get_bignum(&buffer, pub->rsa->e); + if (commentp) + *commentp = buffer_get_string(&buffer, NULL); + /* The encrypted private part is not parsed by this function. */ + + buffer_free(&buffer); + return pub; +} + +/* load public key from private-key file, works only for SSH v1 */ +Key * +key_load_public_type(int type, const char *filename, char **commentp) +{ + Key *pub; + int fd; + + if (type == KEY_RSA1) { + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + pub = key_load_public_rsa1(fd, filename, commentp); + close(fd); + return pub; + } + return NULL; +} + +/* + * Loads the private key from the file. Returns 0 if an error is encountered + * (file does not exist or is not readable, or passphrase is bad). This + * initializes the private key. + * Assumes we are called under uid of the owner of the file. + */ + +static Key * +key_load_private_rsa1(int fd, const char *filename, const char *passphrase, + char **commentp) +{ + int i, check1, check2, cipher_type; + size_t len; + Buffer buffer, decrypted; + u_char *cp; + CipherContext ciphercontext; + Cipher *cipher; + Key *prv = NULL; + struct stat st; + + if (fstat(fd, &st) < 0) { + error("fstat for key file %.200s failed: %.100s", + filename, strerror(errno)); + close(fd); + return NULL; + } + if (st.st_size > 1*1024*1024) { + close(fd); + return (NULL); + } + len = (size_t)st.st_size; /* truncated */ + + buffer_init(&buffer); + cp = buffer_append_space(&buffer, len); + + if (read(fd, cp, (size_t) len) != (size_t) len) { + debug("Read from key file %.200s failed: %.100s", filename, + strerror(errno)); + buffer_free(&buffer); + close(fd); + return NULL; + } + + /* Check that it is at least big enough to contain the ID string. */ + if (len < sizeof(authfile_id_string)) { + debug3("Not a RSA1 key file %.200s.", filename); + buffer_free(&buffer); + close(fd); + return NULL; + } + /* + * Make sure it begins with the id string. Consume the id string + * from the buffer. + */ + for (i = 0; i < sizeof(authfile_id_string); i++) + if (buffer_get_char(&buffer) != authfile_id_string[i]) { + debug3("Not a RSA1 key file %.200s.", filename); + buffer_free(&buffer); + close(fd); + return NULL; + } + + /* Read cipher type. */ + cipher_type = buffer_get_char(&buffer); + (void) buffer_get_int(&buffer); /* Reserved data. */ + + /* Read the public key from the buffer. */ + (void) buffer_get_int(&buffer); + prv = key_new_private(KEY_RSA1); + + buffer_get_bignum(&buffer, prv->rsa->n); + buffer_get_bignum(&buffer, prv->rsa->e); + if (commentp) + *commentp = buffer_get_string(&buffer, NULL); + else + xfree(buffer_get_string(&buffer, NULL)); + + /* Check that it is a supported cipher. */ + cipher = cipher_by_number(cipher_type); + if (cipher == NULL) { + debug("Unsupported cipher %d used in key file %.200s.", + cipher_type, filename); + buffer_free(&buffer); + goto fail; + } + /* Initialize space for decrypted data. */ + buffer_init(&decrypted); + cp = buffer_append_space(&decrypted, buffer_len(&buffer)); + + /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ + cipher_set_key_string(&ciphercontext, cipher, passphrase, + CIPHER_DECRYPT); + cipher_crypt(&ciphercontext, cp, + buffer_ptr(&buffer), buffer_len(&buffer)); + cipher_cleanup(&ciphercontext); + memset(&ciphercontext, 0, sizeof(ciphercontext)); + 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); + goto fail; + } + /* Read the rest of the private key. */ + buffer_get_bignum(&decrypted, prv->rsa->d); + buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */ + /* in SSL and SSH v1 p and q are exchanged */ + buffer_get_bignum(&decrypted, prv->rsa->q); /* p */ + buffer_get_bignum(&decrypted, prv->rsa->p); /* q */ + + /* calculate p-1 and q-1 */ + rsa_generate_additional_parameters(prv->rsa); + + buffer_free(&decrypted); + + /* enable blinding */ + if (RSA_blinding_on(prv->rsa, NULL) != 1) { + error("key_load_private_rsa1: RSA_blinding_on failed"); + goto fail; + } + close(fd); + return prv; + +fail: + if (commentp) + xfree(*commentp); + close(fd); + key_free(prv); + return NULL; +} + +Key * +key_load_private_pem(int fd, int type, const char *passphrase, + char **commentp) +{ + FILE *fp; + EVP_PKEY *pk = NULL; + Key *prv = NULL; + char *name = ""; + + fp = fdopen(fd, "r"); + if (fp == NULL) { + error("fdopen failed: %s", strerror(errno)); + close(fd); + return NULL; + } + pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); + if (pk == NULL) { + debug("PEM_read_PrivateKey failed"); + (void)ERR_get_error(); + } else if (pk->type == EVP_PKEY_RSA && + (type == KEY_UNSPEC||type==KEY_RSA)) { + prv = key_new(KEY_UNSPEC); + prv->rsa = EVP_PKEY_get1_RSA(pk); + prv->type = KEY_RSA; + name = "rsa w/o comment"; +#ifdef DEBUG_PK + RSA_print_fp(stderr, prv->rsa, 8); +#endif + if (RSA_blinding_on(prv->rsa, NULL) != 1) { + error("key_load_private_pem: RSA_blinding_on failed"); + key_free(prv); + prv = NULL; + } + } else if (pk->type == EVP_PKEY_DSA && + (type == KEY_UNSPEC||type==KEY_DSA)) { + prv = key_new(KEY_UNSPEC); + prv->dsa = EVP_PKEY_get1_DSA(pk); + prv->type = KEY_DSA; + name = "dsa w/o comment"; +#ifdef DEBUG_PK + DSA_print_fp(stderr, prv->dsa, 8); +#endif + } else { + error("PEM_read_PrivateKey: mismatch or " + "unknown EVP_PKEY save_type %d", pk->save_type); + } + fclose(fp); + if (pk != NULL) + EVP_PKEY_free(pk); + if (prv != NULL && commentp) + *commentp = xstrdup(name); + debug("read PEM private key done: type %s", + prv ? key_type(prv) : ""); + return prv; +} + +static int +key_perm_ok(int fd, const char *filename) +{ + struct stat st; + + if (fstat(fd, &st) < 0) + return 0; + /* + * if a key owned by the user is accessed, then we check the + * permissions of the file. if the key owned by a different user, + * then we don't care. + */ +#ifdef HAVE_CYGWIN + if (check_ntsec(filename)) +#endif + if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("Permissions 0%3.3o for '%s' are too open.", + (u_int)st.st_mode & 0777, filename); + error("It is recommended that your private key files are NOT accessible by others."); + error("This private key will be ignored."); + return 0; + } + return 1; +} + +Key * +key_load_private_type(int type, const char *filename, const char *passphrase, + char **commentp) +{ + int fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + if (!key_perm_ok(fd, filename)) { + error("bad permissions: ignore key: %s", filename); + close(fd); + return NULL; + } + switch (type) { + case KEY_RSA1: + return key_load_private_rsa1(fd, filename, passphrase, + commentp); + /* closes fd */ + break; + case KEY_DSA: + case KEY_RSA: + case KEY_UNSPEC: + return key_load_private_pem(fd, type, passphrase, commentp); + /* closes fd */ + break; + default: + close(fd); + break; + } + return NULL; +} + +Key * +key_load_private(const char *filename, const char *passphrase, + char **commentp) +{ + Key *pub, *prv; + int fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + if (!key_perm_ok(fd, filename)) { + error("bad permissions: ignore key: %s", filename); + close(fd); + return NULL; + } + pub = key_load_public_rsa1(fd, filename, commentp); + lseek(fd, (off_t) 0, SEEK_SET); /* rewind */ + if (pub == NULL) { + /* closes fd */ + prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL); + /* use the filename as a comment for PEM */ + if (commentp && prv) + *commentp = xstrdup(filename); + } else { + /* it's a SSH v1 key if the public key part is readable */ + key_free(pub); + /* closes fd */ + prv = key_load_private_rsa1(fd, filename, passphrase, NULL); + } + return prv; +} + +static int +key_try_load_public(Key *k, const char *filename, char **commentp) +{ + FILE *f; + char line[4096]; + char *cp; + + f = fopen(filename, "r"); + if (f != NULL) { + while (fgets(line, sizeof(line), f)) { + line[sizeof(line)-1] = '\0'; + cp = line; + switch (*cp) { + case '#': + case '\n': + case '\0': + continue; + } + /* Skip leading whitespace. */ + for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) + ; + if (*cp) { + if (key_read(k, &cp) == 1) { + if (commentp) + *commentp=xstrdup(filename); + fclose(f); + return 1; + } + } + } + fclose(f); + } + return 0; +} + +/* load public key from ssh v1 private or any pubkey file */ +Key * +key_load_public(const char *filename, char **commentp) +{ + Key *pub; + char file[MAXPATHLEN]; + + /* try rsa1 private key */ + pub = key_load_public_type(KEY_RSA1, filename, commentp); + if (pub != NULL) + return pub; + + /* try rsa1 public key */ + pub = key_new(KEY_RSA1); + if (key_try_load_public(pub, filename, commentp) == 1) + return pub; + key_free(pub); + + /* try ssh2 public key */ + pub = key_new(KEY_UNSPEC); + if (key_try_load_public(pub, filename, commentp) == 1) + return pub; + if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && + (strlcat(file, ".pub", sizeof file) < sizeof(file)) && + (key_try_load_public(pub, file, commentp) == 1)) + return pub; + key_free(pub); + return NULL; +} diff --git a/crypto/openssh-3.9p1/authfile.h b/crypto/openssh-3.9p1/authfile.h new file mode 100644 index 0000000000..7f92701ec0 --- /dev/null +++ b/crypto/openssh-3.9p1/authfile.h @@ -0,0 +1,25 @@ +/* $OpenBSD: authfile.h,v 1.10 2002/05/23 19:24:30 markus Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#ifndef AUTHFILE_H +#define AUTHFILE_H + +int key_save_private(Key *, const char *, const char *, const char *); +Key *key_load_public(const char *, char **); +Key *key_load_public_type(int, const char *, char **); +Key *key_load_private(const char *, const char *, char **); +Key *key_load_private_type(int, const char *, const char *, char **); +Key *key_load_private_pem(int, int, const char *, char **); + +#endif diff --git a/crypto/openssh-3.9p1/bufaux.c b/crypto/openssh-3.9p1/bufaux.c new file mode 100644 index 0000000000..bf148316d1 --- /dev/null +++ b/crypto/openssh-3.9p1/bufaux.c @@ -0,0 +1,276 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Auxiliary functions for storing and retrieving various data types to/from + * Buffers. + * + * 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". + * + * + * SSH2 packet format added by Markus Friedl + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: bufaux.c,v 1.32 2004/02/23 15:12:46 markus Exp $"); + +#include +#include "bufaux.h" +#include "xmalloc.h" +#include "getput.h" +#include "log.h" + +/* + * Stores an BIGNUM in the buffer with a 2-byte msb first bit count, followed + * by (bits+7)/8 bytes of binary data, msb first. + */ +void +buffer_put_bignum(Buffer *buffer, const BIGNUM *value) +{ + int bits = BN_num_bits(value); + int bin_size = (bits + 7) / 8; + u_char *buf = xmalloc(bin_size); + int oi; + char msg[2]; + + /* Get the value of in binary */ + oi = BN_bn2bin(value, buf); + if (oi != bin_size) + fatal("buffer_put_bignum: BN_bn2bin() failed: oi %d != bin_size %d", + oi, bin_size); + + /* Store the number of bits in the buffer in two bytes, msb first. */ + PUT_16BIT(msg, bits); + buffer_append(buffer, msg, 2); + /* Store the binary data. */ + buffer_append(buffer, (char *)buf, oi); + + memset(buf, 0, bin_size); + xfree(buf); +} + +/* + * Retrieves an BIGNUM from the buffer. + */ +void +buffer_get_bignum(Buffer *buffer, BIGNUM *value) +{ + u_int bits, bytes; + u_char buf[2], *bin; + + /* Get the number for bits. */ + buffer_get(buffer, (char *) buf, 2); + bits = GET_16BIT(buf); + /* Compute the number of binary bytes that follow. */ + bytes = (bits + 7) / 8; + if (bytes > 8 * 1024) + fatal("buffer_get_bignum: cannot handle BN of size %d", bytes); + if (buffer_len(buffer) < bytes) + fatal("buffer_get_bignum: input buffer too small"); + bin = buffer_ptr(buffer); + BN_bin2bn(bin, bytes, value); + buffer_consume(buffer, bytes); +} + +/* + * Stores an BIGNUM in the buffer in SSH2 format. + */ +void +buffer_put_bignum2(Buffer *buffer, const BIGNUM *value) +{ + u_int bytes; + u_char *buf; + int oi; + u_int hasnohigh = 0; + + if (BN_is_zero(value)) { + buffer_put_int(buffer, 0); + return; + } + if (value->neg) + fatal("buffer_put_bignum2: negative numbers not supported"); + bytes = BN_num_bytes(value) + 1; /* extra padding byte */ + if (bytes < 2) + fatal("buffer_put_bignum2: BN too small"); + buf = xmalloc(bytes); + buf[0] = '\0'; + /* Get the value of in binary */ + oi = BN_bn2bin(value, buf+1); + if (oi != bytes-1) + fatal("buffer_put_bignum2: BN_bn2bin() failed: " + "oi %d != bin_size %d", oi, bytes); + hasnohigh = (buf[1] & 0x80) ? 0 : 1; + buffer_put_string(buffer, buf+hasnohigh, bytes-hasnohigh); + memset(buf, 0, bytes); + xfree(buf); +} + +void +buffer_get_bignum2(Buffer *buffer, BIGNUM *value) +{ + u_int len; + u_char *bin = buffer_get_string(buffer, &len); + + if (len > 0 && (bin[0] & 0x80)) + fatal("buffer_get_bignum2: negative numbers not supported"); + if (len > 8 * 1024) + fatal("buffer_get_bignum2: cannot handle BN of size %d", len); + BN_bin2bn(bin, len, value); + xfree(bin); +} + +/* + * Returns integers from the buffer (msb first). + */ + +u_short +buffer_get_short(Buffer *buffer) +{ + u_char buf[2]; + + buffer_get(buffer, (char *) buf, 2); + return GET_16BIT(buf); +} + +u_int +buffer_get_int(Buffer *buffer) +{ + u_char buf[4]; + + buffer_get(buffer, (char *) buf, 4); + return GET_32BIT(buf); +} + +u_int64_t +buffer_get_int64(Buffer *buffer) +{ + u_char buf[8]; + + buffer_get(buffer, (char *) buf, 8); + return GET_64BIT(buf); +} + +/* + * Stores integers in the buffer, msb first. + */ +void +buffer_put_short(Buffer *buffer, u_short value) +{ + char buf[2]; + + PUT_16BIT(buf, value); + buffer_append(buffer, buf, 2); +} + +void +buffer_put_int(Buffer *buffer, u_int value) +{ + char buf[4]; + + PUT_32BIT(buf, value); + buffer_append(buffer, buf, 4); +} + +void +buffer_put_int64(Buffer *buffer, u_int64_t value) +{ + char buf[8]; + + PUT_64BIT(buf, value); + buffer_append(buffer, buf, 8); +} + +/* + * 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. + */ +void * +buffer_get_string(Buffer *buffer, u_int *length_ptr) +{ + u_char *value; + u_int len; + + /* Get the length. */ + len = buffer_get_int(buffer); + if (len > 256 * 1024) + fatal("buffer_get_string: bad string length %u", 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, u_int len) +{ + buffer_put_int(buffer, len); + buffer_append(buffer, buf, len); +} +void +buffer_put_cstring(Buffer *buffer, const char *s) +{ + if (s == NULL) + fatal("buffer_put_cstring: s == NULL"); + buffer_put_string(buffer, s, strlen(s)); +} + +/* + * Returns a character from the buffer (0 - 255). + */ +int +buffer_get_char(Buffer *buffer) +{ + char ch; + + buffer_get(buffer, &ch, 1); + return (u_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/crypto/openssh-3.9p1/bufaux.h b/crypto/openssh-3.9p1/bufaux.h new file mode 100644 index 0000000000..61c72e3537 --- /dev/null +++ b/crypto/openssh-3.9p1/bufaux.h @@ -0,0 +1,45 @@ +/* $OpenBSD: bufaux.h,v 1.19 2003/11/10 16:23:41 jakob Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#ifndef BUFAUX_H +#define BUFAUX_H + +#include "buffer.h" +#include + +void buffer_put_bignum(Buffer *, const BIGNUM *); +void buffer_put_bignum2(Buffer *, const BIGNUM *); +void buffer_get_bignum(Buffer *, BIGNUM *); +void buffer_get_bignum2(Buffer *, BIGNUM *); + +u_short buffer_get_short(Buffer *); +void buffer_put_short(Buffer *, u_short); + +u_int buffer_get_int(Buffer *); +void buffer_put_int(Buffer *, u_int); + +u_int64_t buffer_get_int64(Buffer *); +void buffer_put_int64(Buffer *, u_int64_t); + +int buffer_get_char(Buffer *); +void buffer_put_char(Buffer *, int); + +void *buffer_get_string(Buffer *, u_int *); +void buffer_put_string(Buffer *, const void *, u_int); +void buffer_put_cstring(Buffer *, const char *); + +#define buffer_skip_string(b) \ + do { u_int l = buffer_get_int(b); buffer_consume(b, l); } while(0) + +#endif /* BUFAUX_H */ diff --git a/crypto/openssh-3.9p1/buffer.c b/crypto/openssh-3.9p1/buffer.c new file mode 100644 index 0000000000..9217cb2695 --- /dev/null +++ b/crypto/openssh-3.9p1/buffer.c @@ -0,0 +1,183 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Functions for manipulating fifo buffers (that can grow if needed). + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: buffer.c,v 1.21 2003/11/21 11:57:03 djm Exp $"); + +#include "xmalloc.h" +#include "buffer.h" +#include "log.h" + +/* Initializes the buffer structure. */ + +void +buffer_init(Buffer *buffer) +{ + const u_int len = 4096; + + buffer->alloc = 0; + buffer->buf = xmalloc(len); + buffer->alloc = len; + buffer->offset = 0; + buffer->end = 0; +} + +/* Frees any memory used for the buffer. */ + +void +buffer_free(Buffer *buffer) +{ + if (buffer->alloc > 0) { + memset(buffer->buf, 0, buffer->alloc); + buffer->alloc = 0; + 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 void *data, u_int len) +{ + void *p; + p = buffer_append_space(buffer, len); + memcpy(p, 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, u_int len) +{ + u_int newlen; + void *p; + + if (len > 0x100000) + fatal("buffer_append_space: len %u not supported", 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) { + p = buffer->buf + buffer->end; + buffer->end += len; + return p; + } + /* + * 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. */ + + newlen = buffer->alloc + len + 32768; + if (newlen > 0xa00000) + fatal("buffer_append_space: alloc %u not supported", + newlen); + buffer->buf = xrealloc(buffer->buf, newlen); + buffer->alloc = newlen; + goto restart; + /* NOTREACHED */ +} + +/* Returns the number of bytes of data in the buffer. */ + +u_int +buffer_len(Buffer *buffer) +{ + return buffer->end - buffer->offset; +} + +/* Gets data from the beginning of the buffer. */ + +void +buffer_get(Buffer *buffer, void *buf, u_int len) +{ + if (len > buffer->end - buffer->offset) + fatal("buffer_get: trying to get more bytes %d than in buffer %d", + len, buffer->end - buffer->offset); + 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, u_int bytes) +{ + if (bytes > buffer->end - buffer->offset) + fatal("buffer_consume: 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, u_int bytes) +{ + if (bytes > buffer->end - buffer->offset) + fatal("buffer_consume_end: trying to get more bytes than in buffer"); + buffer->end -= bytes; +} + +/* Returns a pointer to the first used byte in the buffer. */ + +void * +buffer_ptr(Buffer *buffer) +{ + return buffer->buf + buffer->offset; +} + +/* Dumps the contents of the buffer to stderr. */ + +void +buffer_dump(Buffer *buffer) +{ + u_int i; + u_char *ucp = buffer->buf; + + for (i = buffer->offset; i < buffer->end; i++) { + fprintf(stderr, "%02x", ucp[i]); + if ((i-buffer->offset)%16==15) + fprintf(stderr, "\r\n"); + else if ((i-buffer->offset)%2==1) + fprintf(stderr, " "); + } + fprintf(stderr, "\r\n"); +} diff --git a/crypto/openssh-3.9p1/buffer.h b/crypto/openssh-3.9p1/buffer.h new file mode 100644 index 0000000000..5e4c412442 --- /dev/null +++ b/crypto/openssh-3.9p1/buffer.h @@ -0,0 +1,43 @@ +/* $OpenBSD: buffer.h,v 1.11 2002/03/04 17:27:39 stevesk Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Code for manipulating FIFO buffers. + * + * 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". + */ + +#ifndef BUFFER_H +#define BUFFER_H + +typedef struct { + u_char *buf; /* Buffer for data. */ + u_int alloc; /* Number of bytes allocated for data. */ + u_int offset; /* Offset of first byte containing data. */ + u_int end; /* Offset of last byte containing data. */ +} Buffer; + +void buffer_init(Buffer *); +void buffer_clear(Buffer *); +void buffer_free(Buffer *); + +u_int buffer_len(Buffer *); +void *buffer_ptr(Buffer *); + +void buffer_append(Buffer *, const void *, u_int); +void *buffer_append_space(Buffer *, u_int); + +void buffer_get(Buffer *, void *, u_int); + +void buffer_consume(Buffer *, u_int); +void buffer_consume_end(Buffer *, u_int); + +void buffer_dump(Buffer *); + +#endif /* BUFFER_H */ diff --git a/crypto/openssh-3.9p1/buildpkg.sh.in b/crypto/openssh-3.9p1/buildpkg.sh.in new file mode 100644 index 0000000000..f243e90bf9 --- /dev/null +++ b/crypto/openssh-3.9p1/buildpkg.sh.in @@ -0,0 +1,562 @@ +#!/bin/sh +# +# Fake Root Solaris/SVR4/SVR5 Build System - Prototype +# +# The following code has been provide under Public Domain License. I really +# don't care what you use it for. Just as long as you don't complain to me +# nor my employer if you break it. - Ben Lindstrom (mouring@eviladmin.org) +# +umask 022 +# +# Options for building the package +# You can create a openssh-config.local with your customized options +# +REMOVE_FAKE_ROOT_WHEN_DONE=yes +# +# uncommenting TEST_DIR and using +# configure --prefix=/var/tmp --with-privsep-path=/var/tmp/empty +# and +# PKGNAME=tOpenSSH should allow testing a package without interfering +# with a real OpenSSH package on a system. This is not needed on systems +# that support the -R option to pkgadd. +#TEST_DIR=/var/tmp # leave commented out for production build +PKGNAME=OpenSSH +# revisions within the same version (REV=a) +#REV= +SYSVINIT_NAME=opensshd +MAKE=${MAKE:="make"} +SSHDUID=67 # Default privsep uid +SSHDGID=67 # Default privsep gid +# uncomment these next three as needed +#PERMIT_ROOT_LOGIN=no +#X11_FORWARDING=yes +#USR_LOCAL_IS_SYMLINK=yes +# System V init run levels +SYSVINITSTART=S98 +SYSVINITSTOPT=K30 +# We will source these if they exist +POST_MAKE_INSTALL_FIXES=./pkg_post_make_install_fixes.sh +POST_PROTOTYPE_EDITS=./pkg-post-prototype-edit.sh +# We'll be one level deeper looking for these +PKG_PREINSTALL_LOCAL=../pkg-preinstall.local +PKG_POSTINSTALL_LOCAL=../pkg-postinstall.local +PKG_PREREMOVE_LOCAL=../pkg-preremove.local +PKG_POSTREMOVE_LOCAL=../pkg-postremove.local +PKG_REQUEST_LOCAL=../pkg-request.local +# end of sourced files +# +OPENSSHD=opensshd.init + +PATH_GROUPADD_PROG=@PATH_GROUPADD_PROG@ +PATH_USERADD_PROG=@PATH_USERADD_PROG@ +PATH_PASSWD_PROG=@PATH_PASSWD_PROG@ +# +# list of system directories we do NOT want to change owner/group/perms +# when installing our package +SYSTEM_DIR="/etc \ +/etc/init.d \ +/etc/rcS.d \ +/etc/rc0.d \ +/etc/rc1.d \ +/etc/rc2.d \ +/etc/opt \ +/opt \ +/opt/bin \ +/usr \ +/usr/bin \ +/usr/lib \ +/usr/sbin \ +/usr/share \ +/usr/share/man \ +/usr/share/man/man1 \ +/usr/share/man/man8 \ +/usr/local \ +/usr/local/bin \ +/usr/local/etc \ +/usr/local/libexec \ +/usr/local/man \ +/usr/local/man/man1 \ +/usr/local/man/man8 \ +/usr/local/sbin \ +/usr/local/share \ +/var \ +/var/opt \ +/var/run \ +/var/tmp \ +/tmp" + +# We may need to build as root so we make sure PATH is set up +# only set the path if it's not set already +[ -d /opt/bin ] && { + echo $PATH | grep ":/opt/bin" > /dev/null 2>&1 + [ $? -ne 0 ] && PATH=$PATH:/opt/bin +} +[ -d /usr/local/bin ] && { + echo $PATH | grep ":/usr/local/bin" > /dev/null 2>&1 + [ $? -ne 0 ] && PATH=$PATH:/usr/local/bin +} +[ -d /usr/ccs/bin ] && { + echo $PATH | grep ":/usr/ccs/bin" > /dev/null 2>&1 + [ $? -ne 0 ] && PATH=$PATH:/usr/ccs/bin +} +export PATH +# + +[ -f Makefile ] || { + echo "Please run this script from your build directory" + exit 1 +} + +# we will look for openssh-config.local to override the above options +[ -s ./openssh-config.local ] && . ./openssh-config.local + +START=`pwd` +FAKE_ROOT=$START/pkg + +## Fill in some details, like prefix and sysconfdir +for confvar in prefix exec_prefix bindir sbindir libexecdir datadir mandir sysconfdir piddir srcdir +do + eval $confvar=`grep "^$confvar=" Makefile | cut -d = -f 2` +done + + +## Collect value of privsep user +for confvar in SSH_PRIVSEP_USER +do + eval $confvar=`awk '/#define[ \t]'$confvar'/{print $3}' config.h` +done + +## Set privsep defaults if not defined +if [ -z "$SSH_PRIVSEP_USER" ] +then + SSH_PRIVSEP_USER=sshd +fi + +## Extract common info requires for the 'info' part of the package. +VERSION=`./ssh -V 2>&1 | sed -e 's/,.*//'` + +ARCH=`uname -m` +DEF_MSG="\n" +OS_VER=`uname -v` +SCRIPT_SHELL=/sbin/sh +UNAME_S=`uname -s` +case ${UNAME_S} in + SunOS) UNAME_S=Solaris + ARCH=`uname -p` + RCS_D=yes + DEF_MSG="(default: n)" + ;; + SCO_SV) UNAME_S=OpenServer + OS_VER=`uname -X | grep Release | sed -e 's/^Rel.*3.2v//'` + SCRIPT_SHELL=/bin/sh + RC1_D=no + DEF_MSG="(default: n)" + ;; +esac + +case `basename $0` in + buildpkg.sh) +## Start by faking root install +echo "Faking root install..." +[ -d $FAKE_ROOT ] && rm -fr $FAKE_ROOT +mkdir $FAKE_ROOT +${MAKE} install-nokeys DESTDIR=$FAKE_ROOT +if [ $? -gt 0 ] +then + echo "Fake root install failed, stopping." + exit 1 +fi + +## Setup our run level stuff while we are at it. +mkdir -p $FAKE_ROOT${TEST_DIR}/etc/init.d + +cp ${OPENSSHD} $FAKE_ROOT${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} +chmod 744 $FAKE_ROOT${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} + +[ "${PERMIT_ROOT_LOGIN}" = no ] && \ + perl -p -i -e "s/#PermitRootLogin yes/PermitRootLogin no/" \ + $FAKE_ROOT/${sysconfdir}/sshd_config +[ "${X11_FORWARDING}" = yes ] && \ + perl -p -i -e "s/#X11Forwarding no/X11Forwarding yes/" \ + $FAKE_ROOT/${sysconfdir}/sshd_config +# fix PrintMotd +perl -p -i -e "s/#PrintMotd yes/PrintMotd no/" \ + $FAKE_ROOT/${sysconfdir}/sshd_config + +# We don't want to overwrite config files on multiple installs +mv $FAKE_ROOT/${sysconfdir}/ssh_config $FAKE_ROOT/${sysconfdir}/ssh_config.default +mv $FAKE_ROOT/${sysconfdir}/sshd_config $FAKE_ROOT/${sysconfdir}/sshd_config.default +[ -f $FAKE_ROOT/${sysconfdir}/ssh_prng_cmds ] && \ +mv $FAKE_ROOT/${sysconfdir}/ssh_prng_cmds $FAKE_ROOT/${sysconfdir}/ssh_prng_cmds.default + +# local tweeks here +[ -s "${POST_MAKE_INSTALL_FIXES}" ] && . ${POST_MAKE_INSTALL_FIXES} + +cd $FAKE_ROOT + +## Ok, this is outright wrong, but it will work. I'm tired of pkgmk +## whining. +for i in *; do + PROTO_ARGS="$PROTO_ARGS $i=/$i"; +done + +## Build info file +echo "Building pkginfo file..." +cat > pkginfo << _EOF +PKG=$PKGNAME +NAME="OpenSSH Portable for ${UNAME_S}" +DESC="Secure Shell remote access utility; replaces telnet and rlogin/rsh." +VENDOR="OpenSSH Portable Team - http://www.openssh.com/portable.html" +ARCH=$ARCH +VERSION=$VERSION$REV +CATEGORY="Security,application" +BASEDIR=/ +CLASSES="none" +PSTAMP="${UNAME_S} ${OS_VER} ${ARCH} `date '+%d%b%Y %H:%M'`" +_EOF + +## Build empty depend file that may get updated by $POST_PROTOTYPE_EDITS +echo "Building depend file..." +touch depend + +## Build space file +echo "Building space file..." +cat > space << _EOF +# extra space required by start/stop links added by installf in postinstall +$TEST_DIR/etc/rc0.d/${SYSVINITSTOPT}${SYSVINIT_NAME} 0 1 +$TEST_DIR/etc/rc2.d/${SYSVINITSTART}${SYSVINIT_NAME} 0 1 +_EOF +[ "$RC1_D" = no ] || \ +echo "$TEST_DIR/etc/rc1.d/${SYSVINITSTOPT}${SYSVINIT_NAME} 0 1" >> space +[ "$RCS_D" = yes ] && \ +echo "$TEST_DIR/etc/rcS.d/${SYSVINITSTOPT}${SYSVINIT_NAME} 0 1" >> space + +## Build preinstall file +echo "Building preinstall file..." +cat > preinstall << _EOF +#! ${SCRIPT_SHELL} +# +_EOF + +# local preinstall changes here +[ -s "${PKG_PREINSTALL_LOCAL}" ] && . ${PKG_PREINSTALL_LOCAL} + +cat >> preinstall << _EOF +# +[ "\${PRE_INS_STOP}" = "yes" ] && ${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} stop +exit 0 +_EOF + +## Build postinstall file +echo "Building postinstall file..." +cat > postinstall << _EOF +#! ${SCRIPT_SHELL} +# +[ -f \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_config ] || \\ + cp -p \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_config.default \\ + \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_config +[ -f \${PKG_INSTALL_ROOT}${sysconfdir}/sshd_config ] || \\ + cp -p \${PKG_INSTALL_ROOT}${sysconfdir}/sshd_config.default \\ + \${PKG_INSTALL_ROOT}${sysconfdir}/sshd_config +[ -f \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_prng_cmds.default ] && { + [ -f \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_prng_cmds ] || \\ + cp -p \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_prng_cmds.default \\ + \${PKG_INSTALL_ROOT}${sysconfdir}/ssh_prng_cmds +} + +# make rc?.d dirs only if we are doing a test install +[ -n "${TEST_DIR}" ] && { + [ "$RCS_D" = yes ] && mkdir -p ${TEST_DIR}/etc/rcS.d + mkdir -p ${TEST_DIR}/etc/rc0.d + [ "$RC1_D" = no ] || mkdir -p ${TEST_DIR}/etc/rc1.d + mkdir -p ${TEST_DIR}/etc/rc2.d +} + +if [ "\${USE_SYM_LINKS}" = yes ] +then + [ "$RCS_D" = yes ] && \ +installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rcS.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=../init.d/${SYSVINIT_NAME} s + installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc0.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=../init.d/${SYSVINIT_NAME} s + [ "$RC1_D" = no ] || \ + installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc1.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=../init.d/${SYSVINIT_NAME} s + installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc2.d/${SYSVINITSTART}${SYSVINIT_NAME}=../init.d/${SYSVINIT_NAME} s +else + [ "$RCS_D" = yes ] && \ +installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rcS.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=$TEST_DIR/etc/init.d/${SYSVINIT_NAME} l + installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc0.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=$TEST_DIR/etc/init.d/${SYSVINIT_NAME} l + [ "$RC1_D" = no ] || \ + installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc1.d/${SYSVINITSTOPT}${SYSVINIT_NAME}=$TEST_DIR/etc/init.d/${SYSVINIT_NAME} l + installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR/etc/rc2.d/${SYSVINITSTART}${SYSVINIT_NAME}=$TEST_DIR/etc/init.d/${SYSVINIT_NAME} l +fi + +# If piddir doesn't exist we add it. (Ie. --with-pid-dir=/var/opt/ssh) +[ -d $piddir ] || installf ${PKGNAME} \${PKG_INSTALL_ROOT}$TEST_DIR$piddir d 0755 root sys + +_EOF + +# local postinstall changes here +[ -s "${PKG_POSTINSTALL_LOCAL}" ] && . ${PKG_POSTINSTALL_LOCAL} + +cat >> postinstall << _EOF +installf -f ${PKGNAME} + +# Use chroot to handle PKG_INSTALL_ROOT +if [ ! -z "\${PKG_INSTALL_ROOT}" ] +then + chroot="chroot \${PKG_INSTALL_ROOT}" +fi +# If this is a test build, we will skip the groupadd/useradd/passwd commands +if [ ! -z "${TEST_DIR}" ] +then + chroot=echo +fi + +if egrep '^[ \t]*UsePrivilegeSeparation[ \t]+no' \${PKG_INSTALL_ROOT}/$sysconfdir/sshd_config >/dev/null +then + echo "UsePrivilegeSeparation disabled in config, not creating PrivSep user" + echo "or group." +else + echo "UsePrivilegeSeparation enabled in config (or defaulting to on)." + + # user required? + if cut -f1 -d: \${PKG_INSTALL_ROOT}/etc/passwd | egrep '^'$SSH_PRIVSEP_USER'\$' >/dev/null + then + echo "PrivSep user $SSH_PRIVSEP_USER already exists." + SSH_PRIVSEP_GROUP=\`grep "^$SSH_PRIVSEP_USER:" \${PKG_INSTALL_ROOT}/etc/passwd | awk -F: '{print \$4}'\` + SSH_PRIVSEP_GROUP=\`grep ":\$SSH_PRIVSEP_GROUP:" \${PKG_INSTALL_ROOT}/etc/group | awk -F: '{print \$1}'\` + else + DO_PASSWD=yes + fi + [ -z "\$SSH_PRIVSEP_GROUP" ] && SSH_PRIVSEP_GROUP=$SSH_PRIVSEP_USER + + # group required? + if cut -f1 -d: \${PKG_INSTALL_ROOT}/etc/group | egrep '^'\$SSH_PRIVSEP_GROUP'\$' >/dev/null + then + echo "PrivSep group \$SSH_PRIVSEP_GROUP already exists." + else + DO_GROUP=yes + fi + + # create group if required + [ "\$DO_GROUP" = yes ] && { + # Use gid of 67 if possible + if cut -f3 -d: \${PKG_INSTALL_ROOT}/etc/group | egrep '^'$SSHDGID'\$' >/dev/null + then + : + else + sshdgid="-g $SSHDGID" + fi + echo "Creating PrivSep group \$SSH_PRIVSEP_GROUP." + \$chroot ${PATH_GROUPADD_PROG} \$sshdgid \$SSH_PRIVSEP_GROUP + } + + # Create user if required + [ "\$DO_PASSWD" = yes ] && { + # Use uid of 67 if possible + if cut -f3 -d: \${PKG_INSTALL_ROOT}/etc/passwd | egrep '^'$SSHDGID'\$' >/dev/null + then + : + else + sshduid="-u $SSHDUID" + fi + echo "Creating PrivSep user $SSH_PRIVSEP_USER." + \$chroot ${PATH_USERADD_PROG} -c 'SSHD PrivSep User' -s /bin/false -g $SSH_PRIVSEP_USER \$sshduid $SSH_PRIVSEP_USER + \$chroot ${PATH_PASSWD_PROG} -l $SSH_PRIVSEP_USER + } +fi + +[ "\${POST_INS_START}" = "yes" ] && ${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} start +exit 0 +_EOF + +## Build preremove file +echo "Building preremove file..." +cat > preremove << _EOF +#! ${SCRIPT_SHELL} +# +${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} stop +_EOF + +# local preremove changes here +[ -s "${PKG_PREREMOVE_LOCAL}" ] && . ${PKG_PREREMOVE_LOCAL} + +cat >> preremove << _EOF +exit 0 +_EOF + +## Build postremove file +echo "Building postremove file..." +cat > postremove << _EOF +#! ${SCRIPT_SHELL} +# +_EOF + +# local postremove changes here +[ -s "${PKG_POSTREMOVE_LOCAL}" ] && . ${PKG_POSTREMOVE_LOCAL} + +cat >> postremove << _EOF +exit 0 +_EOF + +## Build request file +echo "Building request file..." +cat > request << _EOF +trap 'exit 3' 15 + +_EOF + +[ -x /usr/bin/ckyorn ] || cat >> request << _EOF + +ckyorn() { +# for some strange reason OpenServer has no ckyorn +# We build a striped down version here + +DEFAULT=n +PROMPT="Yes or No [yes,no,?,quit]" +HELP_PROMPT=" Enter y or yes if your answer is yes; n or no if your answer is no." +USAGE="usage: ckyorn [options] +where options may include: + -d default + -h help + -p prompt +" + +if [ \$# != 0 ] +then + while getopts d:p:h: c + do + case \$c in + h) HELP_PROMPT="\$OPTARG" ;; + d) DEFAULT=\$OPTARG ;; + p) PROMPT=\$OPTARG ;; + \\?) echo "\$USAGE" 1>&2 + exit 1 ;; + esac + done + shift \`expr \$OPTIND - 1\` +fi + +while true +do + echo "\${PROMPT}\\c " 1>&2 + read key + [ -z "\$key" ] && key=\$DEFAULT + case \$key in + [n,N]|[n,N][o,O]|[y,Y]|[y,Y][e,E][s,S]) echo "\${key}\\c" + exit 0 ;; + \\?) echo \$HELP_PROMPT 1>&2 ;; + q|quit) echo "q\\c" 1>&2 + exit 3 ;; + esac +done + +} + +_EOF + +cat >> request << _EOF +USE_SYM_LINKS=no +PRE_INS_STOP=no +POST_INS_START=no +# Use symbolic links? +ans=\`ckyorn -d n \ +-p "Do you want symbolic links for the start/stop scripts? ${DEF_MSG}"\` || exit \$? +case \$ans in + [y,Y]*) USE_SYM_LINKS=yes ;; +esac + +# determine if should restart the daemon +if [ -s ${piddir}/sshd.pid -a -f ${TEST_DIR}/etc/init.d/${SYSVINIT_NAME} ] +then + ans=\`ckyorn -d n \ +-p "Should the running sshd daemon be restarted? ${DEF_MSG}"\` || exit \$? + case \$ans in + [y,Y]*) PRE_INS_STOP=yes + POST_INS_START=yes + ;; + esac + +else + +# determine if we should start sshd + ans=\`ckyorn -d n \ +-p "Start the sshd daemon after installing this package? ${DEF_MSG}"\` || exit \$? + case \$ans in + [y,Y]*) POST_INS_START=yes ;; + esac +fi + +# make parameters available to installation service, +# and so to any other packaging scripts +cat >\$1 <> request << _EOF +exit 0 + +_EOF + +## Next Build our prototype +echo "Building prototype file..." +cat >mk-proto.awk << _EOF + BEGIN { print "i pkginfo"; print "i depend"; \\ + print "i preinstall"; print "i postinstall"; \\ + print "i preremove"; print "i postremove"; \\ + print "i request"; print "i space"; \\ + split("$SYSTEM_DIR",sys_files); } + { + for (dir in sys_files) { if ( \$3 != sys_files[dir] ) + { if ( \$1 == "s" ) + { \$5=""; \$6=""; } + else + { \$5="root"; \$6="sys"; } + } + else + { \$4="?"; \$5="?"; \$6="?"; break;} + } } + { print; } +_EOF + +find . | egrep -v "prototype|pkginfo|mk-proto.awk" | sort | \ + pkgproto $PROTO_ARGS | nawk -f mk-proto.awk > prototype + +# /usr/local is a symlink on some systems +[ "${USR_LOCAL_IS_SYMLINK}" = yes ] && { + grep -v "^d none /usr/local ? ? ?$" prototype > prototype.new + mv prototype.new prototype +} + +## Step back a directory and now build the package. +cd .. +# local prototype tweeks here +[ -s "${POST_PROTOTYPE_EDITS}" ] && . ${POST_PROTOTYPE_EDITS} + +echo "Building package.." +pkgmk -d ${FAKE_ROOT} -f $FAKE_ROOT/prototype -o +echo | pkgtrans -os ${FAKE_ROOT} ${START}/$PKGNAME-$VERSION$REV-$UNAME_S-$ARCH.pkg + ;; + + justpkg.sh) +rm -fr ${FAKE_ROOT}/${PKGNAME} +grep -v "^PSTAMP=" $FAKE_ROOT/pkginfo > $$tmp +mv $$tmp $FAKE_ROOT/pkginfo +cat >> $FAKE_ROOT/pkginfo << _EOF +PSTAMP="${UNAME_S} ${OS_VER} ${ARCH} `date '+%d%b%Y %H:%M'`" +_EOF +pkgmk -d ${FAKE_ROOT} -f $FAKE_ROOT/prototype -o +echo | pkgtrans -os ${FAKE_ROOT} ${START}/$PKGNAME-$VERSION$REV-$UNAME_S-$ARCH.pkg + ;; + +esac + +[ "${REMOVE_FAKE_ROOT_WHEN_DONE}" = yes ] && rm -rf $FAKE_ROOT +exit 0 + diff --git a/crypto/openssh-3.9p1/canohost.c b/crypto/openssh-3.9p1/canohost.c new file mode 100644 index 0000000000..8ad684d6c3 --- /dev/null +++ b/crypto/openssh-3.9p1/canohost.c @@ -0,0 +1,398 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Functions for returning the canonical host name of the remote site. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: canohost.c,v 1.41 2004/07/21 11:51:29 djm Exp $"); + +#include "packet.h" +#include "xmalloc.h" +#include "log.h" +#include "canohost.h" + +static void check_ip_options(int, char *); +static void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); + +/* + * Return the canonical name of the host at the other end of the socket. The + * caller should free the returned string with xfree. + */ + +static char * +get_remote_hostname(int sock, int use_dns) +{ + struct sockaddr_storage from; + int i; + socklen_t fromlen; + struct addrinfo hints, *ai, *aitop; + char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST]; + + /* Get IP address of client. */ + fromlen = sizeof(from); + memset(&from, 0, sizeof(from)); + if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) { + debug("getpeername failed: %.100s", strerror(errno)); + cleanup_exit(255); + } + + if (from.ss_family == AF_INET) + check_ip_options(sock, ntop); + + ipv64_normalise_mapped(&from, &fromlen); + + if (from.ss_family == AF_INET6) + fromlen = sizeof(struct sockaddr_in6); + + if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), + NULL, 0, NI_NUMERICHOST) != 0) + fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed"); + + if (!use_dns) + return xstrdup(ntop); + + debug3("Trying to reverse map address %.100s.", ntop); + /* Map the IP address to a host name. */ + if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), + NULL, 0, NI_NAMEREQD) != 0) { + /* Host name not found. Use ip address. */ + return xstrdup(ntop); + } + + /* + * if reverse lookup result looks like a numeric hostname, + * someone is trying to trick us by PTR record like following: + * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(name, "0", &hints, &ai) == 0) { + logit("Nasty PTR record \"%s\" is set up for %s, ignoring", + name, ntop); + freeaddrinfo(ai); + return xstrdup(ntop); + } + + /* + * 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). + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = from.ss_family; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { + logit("reverse mapping checking getaddrinfo for %.700s " + "failed - POSSIBLE BREAKIN ATTEMPT!", name); + return xstrdup(ntop); + } + /* Look for the address from the list of addresses. */ + for (ai = aitop; ai; ai = ai->ai_next) { + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, + sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && + (strcmp(ntop, ntop2) == 0)) + break; + } + freeaddrinfo(aitop); + /* If we reached the end of the list, the address was not there. */ + if (!ai) { + /* Address not found for the host name. */ + logit("Address %.100s maps to %.600s, but this does not " + "map back to the address - POSSIBLE BREAKIN ATTEMPT!", + ntop, name); + return xstrdup(ntop); + } + return xstrdup(name); +} + +/* + * If IP options are supported, make sure there are none (log and + * disconnect them if any are found). Basically we are worried about + * source routing; it can be used to pretend you are somebody + * (ip-address) you are not. That itself may be "almost acceptable" + * under certain circumstances, but rhosts autentication is useless + * if source routing is accepted. Notice also that if we just dropped + * source routing here, the other side could use IP spoofing to do + * rest of the interaction and could still bypass security. So we + * exit here if we detect any IP options. + */ +/* IPv4 only */ +static void +check_ip_options(int sock, char *ipaddr) +{ +#ifdef IP_OPTIONS + u_char options[200]; + char text[sizeof(options) * 3 + 1]; + socklen_t option_size; + int i, ipproto; + struct protoent *ip; + + if ((ip = getprotobyname("ip")) != NULL) + ipproto = ip->p_proto; + else + ipproto = IPPROTO_IP; + option_size = sizeof(options); + if (getsockopt(sock, ipproto, IP_OPTIONS, options, + &option_size) >= 0 && option_size != 0) { + text[0] = '\0'; + for (i = 0; i < option_size; i++) + snprintf(text + i*3, sizeof(text) - i*3, + " %2.2x", options[i]); + logit("Connection from %.100s with IP options:%.800s", + ipaddr, text); + packet_disconnect("Connection from %.100s with IP options:%.800s", + ipaddr, text); + } +#endif /* IP_OPTIONS */ +} + +static void +ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) +{ + struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr; + struct sockaddr_in *a4 = (struct sockaddr_in *)addr; + struct in_addr inaddr; + u_int16_t port; + + if (addr->ss_family != AF_INET6 || + !IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr)) + return; + + debug3("Normalising mapped IPv4 in IPv6 address"); + + memcpy(&inaddr, ((char *)&a6->sin6_addr) + 12, sizeof(inaddr)); + port = a6->sin6_port; + + memset(addr, 0, sizeof(*a4)); + + a4->sin_family = AF_INET; + *len = sizeof(*a4); + memcpy(&a4->sin_addr, &inaddr, sizeof(inaddr)); + a4->sin_port = port; +} + +/* + * 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(int use_dns) +{ + static char *canonical_host_name = NULL; + static int use_dns_done = 0; + + /* Check if we have previously retrieved name with same option. */ + if (canonical_host_name != NULL) { + if (use_dns_done != use_dns) + xfree(canonical_host_name); + else + return canonical_host_name; + } + + /* Get the real hostname if socket; otherwise return UNKNOWN. */ + if (packet_connection_is_on_socket()) + canonical_host_name = get_remote_hostname( + packet_get_connection_in(), use_dns); + else + canonical_host_name = xstrdup("UNKNOWN"); + + use_dns_done = use_dns; + return canonical_host_name; +} + +/* + * Returns the local/remote IP-address/hostname of socket as a string. + * The returned string must be freed. + */ +static char * +get_socket_address(int sock, int remote, int flags) +{ + struct sockaddr_storage addr; + socklen_t addrlen; + char ntop[NI_MAXHOST]; + + /* Get IP address of client. */ + addrlen = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + + if (remote) { + if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) + < 0) + return NULL; + } else { + if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) + < 0) + return NULL; + } + + /* Work around Linux IPv6 weirdness */ + if (addr.ss_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + + /* Get the address in ascii. */ + if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop), + NULL, 0, flags) != 0) { + error("get_socket_address: getnameinfo %d failed", flags); + return NULL; + } + return xstrdup(ntop); +} + +char * +get_peer_ipaddr(int sock) +{ + char *p; + + if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL) + return p; + return xstrdup("UNKNOWN"); +} + +char * +get_local_ipaddr(int sock) +{ + char *p; + + if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL) + return p; + return xstrdup("UNKNOWN"); +} + +char * +get_local_name(int sock) +{ + return get_socket_address(sock, 0, NI_NAMEREQD); +} + +/* + * Returns the IP-address of the remote host as a string. The returned + * string must not be freed. + */ + +const char * +get_remote_ipaddr(void) +{ + static char *canonical_host_ip = NULL; + + /* Check whether we have cached the ipaddr. */ + if (canonical_host_ip == NULL) { + if (packet_connection_is_on_socket()) { + canonical_host_ip = + get_peer_ipaddr(packet_get_connection_in()); + if (canonical_host_ip == NULL) + cleanup_exit(255); + } else { + /* If not on socket, return UNKNOWN. */ + canonical_host_ip = xstrdup("UNKNOWN"); + } + } + return canonical_host_ip; +} + +const char * +get_remote_name_or_ip(u_int utmp_len, int use_dns) +{ + static const char *remote = ""; + if (utmp_len > 0) + remote = get_canonical_hostname(use_dns); + if (utmp_len == 0 || strlen(remote) > utmp_len) + remote = get_remote_ipaddr(); + return remote; +} + +/* Returns the local/remote port for the socket. */ + +static int +get_sock_port(int sock, int local) +{ + struct sockaddr_storage from; + socklen_t fromlen; + char strport[NI_MAXSERV]; + + /* Get IP address of client. */ + fromlen = sizeof(from); + memset(&from, 0, sizeof(from)); + if (local) { + if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) { + error("getsockname failed: %.100s", strerror(errno)); + return 0; + } + } else { + if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) { + debug("getpeername failed: %.100s", strerror(errno)); + cleanup_exit(255); + } + } + + /* Work around Linux IPv6 weirdness */ + if (from.ss_family == AF_INET6) + fromlen = sizeof(struct sockaddr_in6); + + /* Return port number. */ + if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, + strport, sizeof(strport), NI_NUMERICSERV) != 0) + fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed"); + return atoi(strport); +} + +/* Returns remote/local port number for the current connection. */ + +static int +get_port(int local) +{ + /* + * If the connection is not a socket, return 65535. This is + * intentionally chosen to be an unprivileged port number. + */ + if (!packet_connection_is_on_socket()) + return 65535; + + /* Get socket and return the port number. */ + return get_sock_port(packet_get_connection_in(), local); +} + +int +get_peer_port(int sock) +{ + return get_sock_port(sock, 0); +} + +int +get_remote_port(void) +{ + static int port = -1; + + /* Cache to avoid getpeername() on a dead connection */ + if (port == -1) + port = get_port(0); + + return port; +} + +int +get_local_port(void) +{ + return get_port(1); +} diff --git a/crypto/openssh-3.9p1/canohost.h b/crypto/openssh-3.9p1/canohost.h new file mode 100644 index 0000000000..4347b488a1 --- /dev/null +++ b/crypto/openssh-3.9p1/canohost.h @@ -0,0 +1,25 @@ +/* $OpenBSD: canohost.h,v 1.8 2001/06/26 17:27:23 markus Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +const char *get_canonical_hostname(int); +const char *get_remote_ipaddr(void); +const char *get_remote_name_or_ip(u_int, int); + +char *get_peer_ipaddr(int); +int get_peer_port(int); +char *get_local_ipaddr(int); +char *get_local_name(int); + +int get_remote_port(void); +int get_local_port(void); diff --git a/crypto/openssh-3.9p1/channels.c b/crypto/openssh-3.9p1/channels.c new file mode 100644 index 0000000000..1f6984aa76 --- /dev/null +++ b/crypto/openssh-3.9p1/channels.c @@ -0,0 +1,2972 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * 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. + * + * 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". + * + * SSH2 support added by Markus Friedl. + * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. + * Copyright (c) 1999 Dug Song. All rights reserved. + * Copyright (c) 1999 Theo de Raadt. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: channels.c,v 1.209 2004/08/11 21:43:04 avsm Exp $"); + +#include "ssh.h" +#include "ssh1.h" +#include "ssh2.h" +#include "packet.h" +#include "xmalloc.h" +#include "log.h" +#include "misc.h" +#include "channels.h" +#include "compat.h" +#include "canohost.h" +#include "key.h" +#include "authfd.h" +#include "pathnames.h" +#include "bufaux.h" + +/* -- channel core */ + +/* + * 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 set to NULL + */ +static u_int channels_alloc = 0; + +/* + * Maximum file descriptor value used in any of the channels. This is + * updated in channel_new. + */ +static int channel_max_fd = 0; + + +/* -- tcp forwarding */ + +/* + * 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_to_connect; /* Connect to 'host'. */ + u_short port_to_connect; /* Connect to 'port'. */ + u_short listen_port; /* Remote side should listen 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; + + +/* -- X11 forwarding */ + +/* Maximum number of fake X11 displays to try. */ +#define MAX_DISPLAYS 1000 + +/* Saved X11 authentication protocol name. */ +static char *x11_saved_proto = NULL; + +/* Saved X11 authentication data. This is the real data. */ +static char *x11_saved_data = NULL; +static u_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. + */ +static char *x11_fake_data = NULL; +static u_int x11_fake_data_len; + + +/* -- agent forwarding */ + +#define NUM_SOCKS 10 + +/* AF_UNSPEC or AF_INET or AF_INET6 */ +static int IPv4or6 = AF_UNSPEC; + +/* helper */ +static void port_open_helper(Channel *c, char *rtype); + +/* -- channel core */ + +Channel * +channel_lookup(int id) +{ + Channel *c; + + if (id < 0 || (u_int)id >= channels_alloc) { + logit("channel_lookup: %d: bad id", id); + return NULL; + } + c = channels[id]; + if (c == NULL) { + logit("channel_lookup: %d: bad id: channel free", id); + return NULL; + } + return c; +} + +/* + * Register filedescriptors for a channel, used when allocating a channel or + * when the channel consumer/producer is ready, e.g. shell exec'd + */ + +static void +channel_register_fds(Channel *c, int rfd, int wfd, int efd, + int extusage, int nonblock) +{ + /* Update the maximum file descriptor value. */ + channel_max_fd = MAX(channel_max_fd, rfd); + channel_max_fd = MAX(channel_max_fd, wfd); + channel_max_fd = MAX(channel_max_fd, efd); + + /* XXX set close-on-exec -markus */ + + c->rfd = rfd; + c->wfd = wfd; + c->sock = (rfd == wfd) ? rfd : -1; + c->ctl_fd = -1; /* XXX: set elsewhere */ + c->efd = efd; + c->extended_usage = extusage; + + /* XXX ugly hack: nonblock is only set by the server */ + if (nonblock && isatty(c->rfd)) { + debug2("channel %d: rfd %d isatty", c->self, c->rfd); + c->isatty = 1; + if (!isatty(c->wfd)) { + error("channel %d: wfd %d is not a tty?", + c->self, c->wfd); + } + } else { + c->isatty = 0; + } + c->wfd_isatty = isatty(c->wfd); + + /* enable nonblocking mode */ + if (nonblock) { + if (rfd != -1) + set_nonblock(rfd); + if (wfd != -1) + set_nonblock(wfd); + if (efd != -1) + set_nonblock(efd); + } +} + +/* + * Allocate a new channel object and set its type and socket. This will cause + * remote_name to be freed. + */ + +Channel * +channel_new(char *ctype, int type, int rfd, int wfd, int efd, + u_int window, u_int maxpack, int extusage, char *remote_name, int nonblock) +{ + int found; + u_int i; + Channel *c; + + /* 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] = NULL; + } + /* Try to find a free slot where to put the new channel. */ + for (found = -1, i = 0; i < channels_alloc; i++) + if (channels[i] == NULL) { + /* Found a free slot. */ + found = (int)i; + break; + } + if (found < 0) { + /* There are no free slots. Take last+1 slot and expand the array. */ + found = channels_alloc; + if (channels_alloc > 10000) + fatal("channel_new: internal error: channels_alloc %d " + "too big.", channels_alloc); + channels = xrealloc(channels, + (channels_alloc + 10) * sizeof(Channel *)); + channels_alloc += 10; + debug2("channel: expanding %d", channels_alloc); + for (i = found; i < channels_alloc; i++) + channels[i] = NULL; + } + /* Initialize and return new channel. */ + c = channels[found] = xmalloc(sizeof(Channel)); + memset(c, 0, sizeof(Channel)); + buffer_init(&c->input); + buffer_init(&c->output); + buffer_init(&c->extended); + c->ostate = CHAN_OUTPUT_OPEN; + c->istate = CHAN_INPUT_OPEN; + c->flags = 0; + channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); + c->self = found; + c->type = type; + c->ctype = ctype; + c->local_window = window; + c->local_window_max = window; + c->local_consumed = 0; + c->local_maxpacket = maxpack; + c->remote_id = -1; + c->remote_name = xstrdup(remote_name); + c->remote_window = 0; + c->remote_maxpacket = 0; + c->force_drain = 0; + c->single_connection = 0; + c->detach_user = NULL; + c->confirm = NULL; + c->confirm_ctx = NULL; + c->input_filter = NULL; + debug("channel %d: new [%s]", found, remote_name); + return c; +} + +static int +channel_find_maxfd(void) +{ + u_int i; + int max = 0; + Channel *c; + + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c != NULL) { + max = MAX(max, c->rfd); + max = MAX(max, c->wfd); + max = MAX(max, c->efd); + } + } + return max; +} + +int +channel_close_fd(int *fdp) +{ + int ret = 0, fd = *fdp; + + if (fd != -1) { + ret = close(fd); + *fdp = -1; + if (fd == channel_max_fd) + channel_max_fd = channel_find_maxfd(); + } + return ret; +} + +/* Close all channel fd/socket. */ + +static void +channel_close_fds(Channel *c) +{ + debug3("channel %d: close_fds r %d w %d e %d c %d", + c->self, c->rfd, c->wfd, c->efd, c->ctl_fd); + + channel_close_fd(&c->sock); + channel_close_fd(&c->ctl_fd); + channel_close_fd(&c->rfd); + channel_close_fd(&c->wfd); + channel_close_fd(&c->efd); +} + +/* Free the channel and close its fd/socket. */ + +void +channel_free(Channel *c) +{ + char *s; + u_int i, n; + + for (n = 0, i = 0; i < channels_alloc; i++) + if (channels[i]) + n++; + debug("channel %d: free: %s, nchannels %u", c->self, + c->remote_name ? c->remote_name : "???", n); + + s = channel_open_message(); + debug3("channel %d: status: %s", c->self, s); + xfree(s); + + if (c->sock != -1) + shutdown(c->sock, SHUT_RDWR); + if (c->ctl_fd != -1) + shutdown(c->ctl_fd, SHUT_RDWR); + channel_close_fds(c); + buffer_free(&c->input); + buffer_free(&c->output); + buffer_free(&c->extended); + if (c->remote_name) { + xfree(c->remote_name); + c->remote_name = NULL; + } + channels[c->self] = NULL; + xfree(c); +} + +void +channel_free_all(void) +{ + u_int i; + + for (i = 0; i < channels_alloc; i++) + if (channels[i] != NULL) + channel_free(channels[i]); +} + +/* + * Closes the sockets/fds of all channels. This is used to close extra file + * descriptors after a fork. + */ + +void +channel_close_all(void) +{ + u_int i; + + for (i = 0; i < channels_alloc; i++) + if (channels[i] != NULL) + channel_close_fds(channels[i]); +} + +/* + * Stop listening to channels. + */ + +void +channel_stop_listening(void) +{ + u_int i; + Channel *c; + + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c != NULL) { + switch (c->type) { + case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: + case SSH_CHANNEL_X11_LISTENER: + channel_close_fd(&c->sock); + channel_free(c); + break; + } + } + } +} + +/* + * 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(void) +{ + u_int i; + Channel *c; + + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c != NULL && c->type == SSH_CHANNEL_OPEN) { +#if 0 + if (!compat20 && + buffer_len(&c->input) > packet_get_maxsize()) { + debug2("channel %d: big input buffer %d", + c->self, buffer_len(&c->input)); + return 0; + } +#endif + if (buffer_len(&c->output) > packet_get_maxsize()) { + debug2("channel %d: big output buffer %u > %u", + c->self, buffer_len(&c->output), + packet_get_maxsize()); + return 0; + } + } + } + return 1; +} + +/* Returns true if any channel is still open. */ + +int +channel_still_open(void) +{ + u_int i; + Channel *c; + + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c == NULL) + continue; + switch (c->type) { + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: + case SSH_CHANNEL_CLOSED: + case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_DYNAMIC: + case SSH_CHANNEL_CONNECTING: + case SSH_CHANNEL_ZOMBIE: + continue; + case SSH_CHANNEL_LARVAL: + if (!compat20) + fatal("cannot happen: SSH_CHANNEL_LARVAL"); + continue; + case SSH_CHANNEL_OPENING: + case SSH_CHANNEL_OPEN: + case SSH_CHANNEL_X11_OPEN: + return 1; + case SSH_CHANNEL_INPUT_DRAINING: + case SSH_CHANNEL_OUTPUT_DRAINING: + if (!compat13) + fatal("cannot happen: OUT_DRAIN"); + return 1; + default: + fatal("channel_still_open: bad channel type %d", c->type); + /* NOTREACHED */ + } + } + return 0; +} + +/* Returns the id of an open channel suitable for keepaliving */ + +int +channel_find_open(void) +{ + u_int i; + Channel *c; + + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c == NULL || c->remote_id < 0) + continue; + switch (c->type) { + case SSH_CHANNEL_CLOSED: + case SSH_CHANNEL_DYNAMIC: + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: + case SSH_CHANNEL_OPENING: + case SSH_CHANNEL_CONNECTING: + case SSH_CHANNEL_ZOMBIE: + continue; + case SSH_CHANNEL_LARVAL: + case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_OPEN: + case SSH_CHANNEL_X11_OPEN: + return i; + case SSH_CHANNEL_INPUT_DRAINING: + case SSH_CHANNEL_OUTPUT_DRAINING: + if (!compat13) + fatal("cannot happen: OUT_DRAIN"); + return i; + default: + fatal("channel_find_open: bad channel type %d", c->type); + /* NOTREACHED */ + } + } + return -1; +} + + +/* + * 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(void) +{ + Buffer buffer; + Channel *c; + char buf[1024], *cp; + u_int i; + + buffer_init(&buffer); + snprintf(buf, sizeof buf, "The following connections are open:\r\n"); + buffer_append(&buffer, buf, strlen(buf)); + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c == NULL) + continue; + switch (c->type) { + case SSH_CHANNEL_X11_LISTENER: + case SSH_CHANNEL_PORT_LISTENER: + case SSH_CHANNEL_RPORT_LISTENER: + case SSH_CHANNEL_CLOSED: + case SSH_CHANNEL_AUTH_SOCKET: + case SSH_CHANNEL_ZOMBIE: + continue; + case SSH_CHANNEL_LARVAL: + case SSH_CHANNEL_OPENING: + case SSH_CHANNEL_CONNECTING: + case SSH_CHANNEL_DYNAMIC: + case SSH_CHANNEL_OPEN: + case SSH_CHANNEL_X11_OPEN: + case SSH_CHANNEL_INPUT_DRAINING: + case SSH_CHANNEL_OUTPUT_DRAINING: + snprintf(buf, sizeof buf, + " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d cfd %d)\r\n", + c->self, c->remote_name, + c->type, c->remote_id, + c->istate, buffer_len(&c->input), + c->ostate, buffer_len(&c->output), + c->rfd, c->wfd, c->ctl_fd); + buffer_append(&buffer, buf, strlen(buf)); + continue; + default: + fatal("channel_open_message: bad channel type %d", c->type); + /* NOTREACHED */ + } + } + buffer_append(&buffer, "\0", 1); + cp = xstrdup(buffer_ptr(&buffer)); + buffer_free(&buffer); + return cp; +} + +void +channel_send_open(int id) +{ + Channel *c = channel_lookup(id); + + if (c == NULL) { + logit("channel_send_open: %d: bad id", id); + return; + } + debug2("channel %d: send open", id); + packet_start(SSH2_MSG_CHANNEL_OPEN); + packet_put_cstring(c->ctype); + packet_put_int(c->self); + packet_put_int(c->local_window); + packet_put_int(c->local_maxpacket); + packet_send(); +} + +void +channel_request_start(int id, char *service, int wantconfirm) +{ + Channel *c = channel_lookup(id); + + if (c == NULL) { + logit("channel_request_start: %d: unknown channel id", id); + return; + } + debug2("channel %d: request %s confirm %d", id, service, wantconfirm); + packet_start(SSH2_MSG_CHANNEL_REQUEST); + packet_put_int(c->remote_id); + packet_put_cstring(service); + packet_put_char(wantconfirm); +} +void +channel_register_confirm(int id, channel_callback_fn *fn, void *ctx) +{ + Channel *c = channel_lookup(id); + + if (c == NULL) { + logit("channel_register_comfirm: %d: bad id", id); + return; + } + c->confirm = fn; + c->confirm_ctx = ctx; +} +void +channel_register_cleanup(int id, channel_callback_fn *fn) +{ + Channel *c = channel_lookup(id); + + if (c == NULL) { + logit("channel_register_cleanup: %d: bad id", id); + return; + } + c->detach_user = fn; +} +void +channel_cancel_cleanup(int id) +{ + Channel *c = channel_lookup(id); + + if (c == NULL) { + logit("channel_cancel_cleanup: %d: bad id", id); + return; + } + c->detach_user = NULL; +} +void +channel_register_filter(int id, channel_filter_fn *fn) +{ + Channel *c = channel_lookup(id); + + if (c == NULL) { + logit("channel_register_filter: %d: bad id", id); + return; + } + c->input_filter = fn; +} + +void +channel_set_fds(int id, int rfd, int wfd, int efd, + int extusage, int nonblock, u_int window_max) +{ + Channel *c = channel_lookup(id); + + if (c == NULL || c->type != SSH_CHANNEL_LARVAL) + fatal("channel_activate for non-larval channel %d.", id); + channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); + c->type = SSH_CHANNEL_OPEN; + c->local_window = c->local_window_max = window_max; + packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); + packet_put_int(c->remote_id); + packet_put_int(c->local_window); + packet_send(); +} + +/* + * 'channel_pre*' are called just before select() to add any bits relevant to + * channels in the select bitmasks. + */ +/* + * 'channel_post*': perform any appropriate operations for channels which + * have events pending. + */ +typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset); +chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE]; +chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE]; + +static void +channel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset) +{ + FD_SET(c->sock, readset); +} + +static void +channel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset) +{ + debug3("channel %d: waiting for connection", c->self); + FD_SET(c->sock, writeset); +} + +static void +channel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset) +{ + if (buffer_len(&c->input) < packet_get_maxsize()) + FD_SET(c->sock, readset); + if (buffer_len(&c->output) > 0) + FD_SET(c->sock, writeset); +} + +static void +channel_pre_open(Channel *c, fd_set * readset, fd_set * writeset) +{ + u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); + + if (c->istate == CHAN_INPUT_OPEN && + limit > 0 && + buffer_len(&c->input) < limit) + FD_SET(c->rfd, readset); + if (c->ostate == CHAN_OUTPUT_OPEN || + c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { + if (buffer_len(&c->output) > 0) { + FD_SET(c->wfd, writeset); + } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { + if (CHANNEL_EFD_OUTPUT_ACTIVE(c)) + debug2("channel %d: obuf_empty delayed efd %d/(%d)", + c->self, c->efd, buffer_len(&c->extended)); + else + chan_obuf_empty(c); + } + } + /** XXX check close conditions, too */ + if (compat20 && c->efd != -1) { + if (c->extended_usage == CHAN_EXTENDED_WRITE && + buffer_len(&c->extended) > 0) + FD_SET(c->efd, writeset); + else if (!(c->flags & CHAN_EOF_SENT) && + c->extended_usage == CHAN_EXTENDED_READ && + buffer_len(&c->extended) < c->remote_window) + FD_SET(c->efd, readset); + } + /* XXX: What about efd? races? */ + if (compat20 && c->ctl_fd != -1 && + c->istate == CHAN_INPUT_OPEN && c->ostate == CHAN_OUTPUT_OPEN) + FD_SET(c->ctl_fd, readset); +} + +static void +channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) +{ + if (buffer_len(&c->input) == 0) { + packet_start(SSH_MSG_CHANNEL_CLOSE); + packet_put_int(c->remote_id); + packet_send(); + c->type = SSH_CHANNEL_CLOSED; + debug2("channel %d: closing after input drain.", c->self); + } +} + +static void +channel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset) +{ + if (buffer_len(&c->output) == 0) + chan_mark_dead(c); + else + FD_SET(c->sock, writeset); +} + +/* + * 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. + * XXX All this happens at the client side. + * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok + */ +static int +x11_open_helper(Buffer *b) +{ + u_char *ucp; + u_int proto_len, data_len; + + /* Check if the fixed size part of the packet is in buffer. */ + if (buffer_len(b) < 12) + return 0; + + /* Parse the lengths of variable-length fields. */ + ucp = buffer_ptr(b); + 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 { + debug2("Initial X11 packet contains bad byte order byte: 0x%x", + ucp[0]); + return -1; + } + + /* Check if the whole packet is in buffer. */ + if (buffer_len(b) < + 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) + return 0; + + /* Check if authentication protocol matches. */ + if (proto_len != strlen(x11_saved_proto) || + memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { + debug2("X11 connection uses different authentication protocol."); + return -1; + } + /* 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) { + debug2("X11 auth data does not match fake data."); + return -1; + } + /* Check fake data length */ + if (x11_fake_data_len != x11_saved_data_len) { + error("X11 fake_data_len %d != saved_data_len %d", + x11_fake_data_len, x11_saved_data_len); + return -1; + } + /* + * Received authentication protocol and data match + * our fake data. Substitute the fake data with real + * data. + */ + memcpy(ucp + 12 + ((proto_len + 3) & ~3), + x11_saved_data, x11_saved_data_len); + return 1; +} + +static void +channel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset) +{ + int ret = x11_open_helper(&c->output); + + if (ret == 1) { + /* Start normal processing for the channel. */ + c->type = SSH_CHANNEL_OPEN; + channel_pre_open_13(c, readset, writeset); + } else if (ret == -1) { + /* + * We have received an X11 connection that has bad + * authentication information. + */ + logit("X11 connection rejected because of wrong authentication."); + buffer_clear(&c->input); + buffer_clear(&c->output); + channel_close_fd(&c->sock); + c->sock = -1; + c->type = SSH_CHANNEL_CLOSED; + packet_start(SSH_MSG_CHANNEL_CLOSE); + packet_put_int(c->remote_id); + packet_send(); + } +} + +static void +channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) +{ + int ret = x11_open_helper(&c->output); + + /* c->force_drain = 1; */ + + if (ret == 1) { + c->type = SSH_CHANNEL_OPEN; + channel_pre_open(c, readset, writeset); + } else if (ret == -1) { + logit("X11 connection rejected because of wrong authentication."); + debug2("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); + chan_read_failed(c); + buffer_clear(&c->input); + chan_ibuf_empty(c); + buffer_clear(&c->output); + /* for proto v1, the peer will send an IEOF */ + if (compat20) + chan_write_failed(c); + else + c->type = SSH_CHANNEL_OPEN; + debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); + } +} + +/* try to decode a socks4 header */ +static int +channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) +{ + char *p, *host; + int len, have, i, found; + char username[256]; + struct { + u_int8_t version; + u_int8_t command; + u_int16_t dest_port; + struct in_addr dest_addr; + } s4_req, s4_rsp; + + debug2("channel %d: decode socks4", c->self); + + have = buffer_len(&c->input); + len = sizeof(s4_req); + if (have < len) + return 0; + p = buffer_ptr(&c->input); + for (found = 0, i = len; i < have; i++) { + if (p[i] == '\0') { + found = 1; + break; + } + if (i > 1024) { + /* the peer is probably sending garbage */ + debug("channel %d: decode socks4: too long", + c->self); + return -1; + } + } + if (!found) + return 0; + buffer_get(&c->input, (char *)&s4_req.version, 1); + buffer_get(&c->input, (char *)&s4_req.command, 1); + buffer_get(&c->input, (char *)&s4_req.dest_port, 2); + buffer_get(&c->input, (char *)&s4_req.dest_addr, 4); + have = buffer_len(&c->input); + p = buffer_ptr(&c->input); + len = strlen(p); + debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); + if (len > have) + fatal("channel %d: decode socks4: len %d > have %d", + c->self, len, have); + strlcpy(username, p, sizeof(username)); + buffer_consume(&c->input, len); + buffer_consume(&c->input, 1); /* trailing '\0' */ + + host = inet_ntoa(s4_req.dest_addr); + strlcpy(c->path, host, sizeof(c->path)); + c->host_port = ntohs(s4_req.dest_port); + + debug2("channel %d: dynamic request: socks4 host %s port %u command %u", + c->self, host, c->host_port, s4_req.command); + + if (s4_req.command != 1) { + debug("channel %d: cannot handle: socks4 cn %d", + c->self, s4_req.command); + return -1; + } + s4_rsp.version = 0; /* vn: 0 for reply */ + s4_rsp.command = 90; /* cd: req granted */ + s4_rsp.dest_port = 0; /* ignored */ + s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ + buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); + return 1; +} + +/* try to decode a socks5 header */ +#define SSH_SOCKS5_AUTHDONE 0x1000 +#define SSH_SOCKS5_NOAUTH 0x00 +#define SSH_SOCKS5_IPV4 0x01 +#define SSH_SOCKS5_DOMAIN 0x03 +#define SSH_SOCKS5_IPV6 0x04 +#define SSH_SOCKS5_CONNECT 0x01 +#define SSH_SOCKS5_SUCCESS 0x00 + +static int +channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset) +{ + struct { + u_int8_t version; + u_int8_t command; + u_int8_t reserved; + u_int8_t atyp; + } s5_req, s5_rsp; + u_int16_t dest_port; + u_char *p, dest_addr[255+1]; + int i, have, found, nmethods, addrlen, af; + + debug2("channel %d: decode socks5", c->self); + p = buffer_ptr(&c->input); + if (p[0] != 0x05) + return -1; + have = buffer_len(&c->input); + if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { + /* format: ver | nmethods | methods */ + if (have < 2) + return 0; + nmethods = p[1]; + if (have < nmethods + 2) + return 0; + /* look for method: "NO AUTHENTICATION REQUIRED" */ + for (found = 0, i = 2 ; i < nmethods + 2; i++) { + if (p[i] == SSH_SOCKS5_NOAUTH ) { + found = 1; + break; + } + } + if (!found) { + debug("channel %d: method SSH_SOCKS5_NOAUTH not found", + c->self); + return -1; + } + buffer_consume(&c->input, nmethods + 2); + buffer_put_char(&c->output, 0x05); /* version */ + buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */ + FD_SET(c->sock, writeset); + c->flags |= SSH_SOCKS5_AUTHDONE; + debug2("channel %d: socks5 auth done", c->self); + return 0; /* need more */ + } + debug2("channel %d: socks5 post auth", c->self); + if (have < sizeof(s5_req)+1) + return 0; /* need more */ + memcpy((char *)&s5_req, p, sizeof(s5_req)); + if (s5_req.version != 0x05 || + s5_req.command != SSH_SOCKS5_CONNECT || + s5_req.reserved != 0x00) { + debug2("channel %d: only socks5 connect supported", c->self); + return -1; + } + switch(s5_req.atyp){ + case SSH_SOCKS5_IPV4: + addrlen = 4; + af = AF_INET; + break; + case SSH_SOCKS5_DOMAIN: + addrlen = p[sizeof(s5_req)]; + af = -1; + break; + case SSH_SOCKS5_IPV6: + addrlen = 16; + af = AF_INET6; + break; + default: + debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp); + return -1; + } + if (have < 4 + addrlen + 2) + return 0; + buffer_consume(&c->input, sizeof(s5_req)); + if (s5_req.atyp == SSH_SOCKS5_DOMAIN) + buffer_consume(&c->input, 1); /* host string length */ + buffer_get(&c->input, (char *)&dest_addr, addrlen); + buffer_get(&c->input, (char *)&dest_port, 2); + dest_addr[addrlen] = '\0'; + if (s5_req.atyp == SSH_SOCKS5_DOMAIN) + strlcpy(c->path, (char *)dest_addr, sizeof(c->path)); + else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL) + return -1; + c->host_port = ntohs(dest_port); + + debug2("channel %d: dynamic request: socks5 host %s port %u command %u", + c->self, c->path, c->host_port, s5_req.command); + + s5_rsp.version = 0x05; + s5_rsp.command = SSH_SOCKS5_SUCCESS; + s5_rsp.reserved = 0; /* ignored */ + s5_rsp.atyp = SSH_SOCKS5_IPV4; + ((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY; + dest_port = 0; /* ignored */ + + buffer_append(&c->output, (char *)&s5_rsp, sizeof(s5_rsp)); + buffer_append(&c->output, (char *)&dest_addr, sizeof(struct in_addr)); + buffer_append(&c->output, (char *)&dest_port, sizeof(dest_port)); + return 1; +} + +/* dynamic port forwarding */ +static void +channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) +{ + u_char *p; + int have, ret; + + have = buffer_len(&c->input); + c->delayed = 0; + debug2("channel %d: pre_dynamic: have %d", c->self, have); + /* buffer_dump(&c->input); */ + /* check if the fixed size part of the packet is in buffer. */ + if (have < 3) { + /* need more */ + FD_SET(c->sock, readset); + return; + } + /* try to guess the protocol */ + p = buffer_ptr(&c->input); + switch (p[0]) { + case 0x04: + ret = channel_decode_socks4(c, readset, writeset); + break; + case 0x05: + ret = channel_decode_socks5(c, readset, writeset); + break; + default: + ret = -1; + break; + } + if (ret < 0) { + chan_mark_dead(c); + } else if (ret == 0) { + debug2("channel %d: pre_dynamic: need more", c->self); + /* need more */ + FD_SET(c->sock, readset); + } else { + /* switch to the next state */ + c->type = SSH_CHANNEL_OPENING; + port_open_helper(c, "direct-tcpip"); + } +} + +/* This is our fake X11 server socket. */ +static void +channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) +{ + Channel *nc; + struct sockaddr addr; + int newsock; + socklen_t addrlen; + char buf[16384], *remote_ipaddr; + int remote_port; + + if (FD_ISSET(c->sock, readset)) { + debug("X11 connection requested."); + addrlen = sizeof(addr); + newsock = accept(c->sock, &addr, &addrlen); + if (c->single_connection) { + debug2("single_connection: closing X11 listener."); + channel_close_fd(&c->sock); + chan_mark_dead(c); + } + if (newsock < 0) { + error("accept: %.100s", strerror(errno)); + return; + } + set_nodelay(newsock); + remote_ipaddr = get_peer_ipaddr(newsock); + remote_port = get_peer_port(newsock); + snprintf(buf, sizeof buf, "X11 connection from %.200s port %d", + remote_ipaddr, remote_port); + + nc = channel_new("accepted x11 socket", + SSH_CHANNEL_OPENING, newsock, newsock, -1, + c->local_window_max, c->local_maxpacket, 0, buf, 1); + if (compat20) { + packet_start(SSH2_MSG_CHANNEL_OPEN); + packet_put_cstring("x11"); + packet_put_int(nc->self); + packet_put_int(nc->local_window_max); + packet_put_int(nc->local_maxpacket); + /* originator ipaddr and port */ + packet_put_cstring(remote_ipaddr); + if (datafellows & SSH_BUG_X11FWD) { + debug2("ssh2 x11 bug compat mode"); + } else { + packet_put_int(remote_port); + } + packet_send(); + } else { + packet_start(SSH_SMSG_X11_OPEN); + packet_put_int(nc->self); + if (packet_get_protocol_flags() & + SSH_PROTOFLAG_HOST_IN_FWD_OPEN) + packet_put_cstring(buf); + packet_send(); + } + xfree(remote_ipaddr); + } +} + +static void +port_open_helper(Channel *c, char *rtype) +{ + int direct; + char buf[1024]; + char *remote_ipaddr = get_peer_ipaddr(c->sock); + u_short remote_port = get_peer_port(c->sock); + + direct = (strcmp(rtype, "direct-tcpip") == 0); + + snprintf(buf, sizeof buf, + "%s: listening port %d for %.100s port %d, " + "connect from %.200s port %d", + rtype, c->listening_port, c->path, c->host_port, + remote_ipaddr, remote_port); + + xfree(c->remote_name); + c->remote_name = xstrdup(buf); + + if (compat20) { + packet_start(SSH2_MSG_CHANNEL_OPEN); + packet_put_cstring(rtype); + packet_put_int(c->self); + packet_put_int(c->local_window_max); + packet_put_int(c->local_maxpacket); + if (direct) { + /* target host, port */ + packet_put_cstring(c->path); + packet_put_int(c->host_port); + } else { + /* listen address, port */ + packet_put_cstring(c->path); + packet_put_int(c->listening_port); + } + /* originator host and port */ + packet_put_cstring(remote_ipaddr); + packet_put_int(remote_port); + packet_send(); + } else { + packet_start(SSH_MSG_PORT_OPEN); + packet_put_int(c->self); + packet_put_cstring(c->path); + packet_put_int(c->host_port); + if (packet_get_protocol_flags() & + SSH_PROTOFLAG_HOST_IN_FWD_OPEN) + packet_put_cstring(c->remote_name); + packet_send(); + } + xfree(remote_ipaddr); +} + +/* + * This socket is listening for connections to a forwarded TCP/IP port. + */ +static void +channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) +{ + Channel *nc; + struct sockaddr addr; + int newsock, nextstate; + socklen_t addrlen; + char *rtype; + + if (FD_ISSET(c->sock, readset)) { + debug("Connection to port %d forwarding " + "to %.100s port %d requested.", + c->listening_port, c->path, c->host_port); + + if (c->type == SSH_CHANNEL_RPORT_LISTENER) { + nextstate = SSH_CHANNEL_OPENING; + rtype = "forwarded-tcpip"; + } else { + if (c->host_port == 0) { + nextstate = SSH_CHANNEL_DYNAMIC; + rtype = "dynamic-tcpip"; + } else { + nextstate = SSH_CHANNEL_OPENING; + rtype = "direct-tcpip"; + } + } + + addrlen = sizeof(addr); + newsock = accept(c->sock, &addr, &addrlen); + if (newsock < 0) { + error("accept: %.100s", strerror(errno)); + return; + } + set_nodelay(newsock); + nc = channel_new(rtype, nextstate, newsock, newsock, -1, + c->local_window_max, c->local_maxpacket, 0, rtype, 1); + nc->listening_port = c->listening_port; + nc->host_port = c->host_port; + strlcpy(nc->path, c->path, sizeof(nc->path)); + + if (nextstate == SSH_CHANNEL_DYNAMIC) { + /* + * do not call the channel_post handler until + * this flag has been reset by a pre-handler. + * otherwise the FD_ISSET calls might overflow + */ + nc->delayed = 1; + } else { + port_open_helper(nc, rtype); + } + } +} + +/* + * This is the authentication agent socket listening for connections from + * clients. + */ +static void +channel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset) +{ + Channel *nc; + int newsock; + struct sockaddr addr; + socklen_t addrlen; + + if (FD_ISSET(c->sock, readset)) { + addrlen = sizeof(addr); + newsock = accept(c->sock, &addr, &addrlen); + if (newsock < 0) { + error("accept from auth socket: %.100s", strerror(errno)); + return; + } + nc = channel_new("accepted auth socket", + SSH_CHANNEL_OPENING, newsock, newsock, -1, + c->local_window_max, c->local_maxpacket, + 0, "accepted auth socket", 1); + if (compat20) { + packet_start(SSH2_MSG_CHANNEL_OPEN); + packet_put_cstring("auth-agent@openssh.com"); + packet_put_int(nc->self); + packet_put_int(c->local_window_max); + packet_put_int(c->local_maxpacket); + } else { + packet_start(SSH_SMSG_AGENT_OPEN); + packet_put_int(nc->self); + } + packet_send(); + } +} + +static void +channel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset) +{ + int err = 0; + socklen_t sz = sizeof(err); + + if (FD_ISSET(c->sock, writeset)) { + if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) { + err = errno; + error("getsockopt SO_ERROR failed"); + } + if (err == 0) { + debug("channel %d: connected", c->self); + c->type = SSH_CHANNEL_OPEN; + if (compat20) { + packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); + packet_put_int(c->remote_id); + packet_put_int(c->self); + packet_put_int(c->local_window); + packet_put_int(c->local_maxpacket); + } else { + packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); + packet_put_int(c->remote_id); + packet_put_int(c->self); + } + } else { + debug("channel %d: not connected: %s", + c->self, strerror(err)); + if (compat20) { + packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(c->remote_id); + packet_put_int(SSH2_OPEN_CONNECT_FAILED); + if (!(datafellows & SSH_BUG_OPENFAILURE)) { + packet_put_cstring(strerror(err)); + packet_put_cstring(""); + } + } else { + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(c->remote_id); + } + chan_mark_dead(c); + } + packet_send(); + } +} + +static int +channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) +{ + char buf[16*1024]; + int len; + + if (c->rfd != -1 && + FD_ISSET(c->rfd, readset)) { + len = read(c->rfd, buf, sizeof(buf)); + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + return 1; + if (len <= 0) { + debug2("channel %d: read<=0 rfd %d len %d", + c->self, c->rfd, len); + if (c->type != SSH_CHANNEL_OPEN) { + debug2("channel %d: not open", c->self); + chan_mark_dead(c); + return -1; + } else if (compat13) { + buffer_clear(&c->output); + c->type = SSH_CHANNEL_INPUT_DRAINING; + debug2("channel %d: input draining.", c->self); + } else { + chan_read_failed(c); + } + return -1; + } + if (c->input_filter != NULL) { + if (c->input_filter(c, buf, len) == -1) { + debug2("channel %d: filter stops", c->self); + chan_read_failed(c); + } + } else { + buffer_append(&c->input, buf, len); + } + } + return 1; +} +static int +channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset) +{ + struct termios tio; + u_char *data; + u_int dlen; + int len; + + /* Send buffered output data to the socket. */ + if (c->wfd != -1 && + FD_ISSET(c->wfd, writeset) && + buffer_len(&c->output) > 0) { + data = buffer_ptr(&c->output); + dlen = buffer_len(&c->output); +#ifdef _AIX + /* XXX: Later AIX versions can't push as much data to tty */ + if (compat20 && c->wfd_isatty) + dlen = MIN(dlen, 8*1024); +#endif + len = write(c->wfd, data, dlen); + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + return 1; + if (len <= 0) { + if (c->type != SSH_CHANNEL_OPEN) { + debug2("channel %d: not open", c->self); + chan_mark_dead(c); + return -1; + } else if (compat13) { + buffer_clear(&c->output); + debug2("channel %d: input draining.", c->self); + c->type = SSH_CHANNEL_INPUT_DRAINING; + } else { + chan_write_failed(c); + } + return -1; + } + if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') { + if (tcgetattr(c->wfd, &tio) == 0 && + !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { + /* + * Simulate echo to reduce the impact of + * traffic analysis. We need to match the + * size of a SSH2_MSG_CHANNEL_DATA message + * (4 byte channel id + data) + */ + packet_send_ignore(4 + len); + packet_send(); + } + } + buffer_consume(&c->output, len); + if (compat20 && len > 0) { + c->local_consumed += len; + } + } + return 1; +} +static int +channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset) +{ + char buf[16*1024]; + int len; + +/** XXX handle drain efd, too */ + if (c->efd != -1) { + if (c->extended_usage == CHAN_EXTENDED_WRITE && + FD_ISSET(c->efd, writeset) && + buffer_len(&c->extended) > 0) { + len = write(c->efd, buffer_ptr(&c->extended), + buffer_len(&c->extended)); + debug2("channel %d: written %d to efd %d", + c->self, len, c->efd); + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + return 1; + if (len <= 0) { + debug2("channel %d: closing write-efd %d", + c->self, c->efd); + channel_close_fd(&c->efd); + } else { + buffer_consume(&c->extended, len); + c->local_consumed += len; + } + } else if (c->extended_usage == CHAN_EXTENDED_READ && + FD_ISSET(c->efd, readset)) { + len = read(c->efd, buf, sizeof(buf)); + debug2("channel %d: read %d from efd %d", + c->self, len, c->efd); + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + return 1; + if (len <= 0) { + debug2("channel %d: closing read-efd %d", + c->self, c->efd); + channel_close_fd(&c->efd); + } else { + buffer_append(&c->extended, buf, len); + } + } + } + return 1; +} +static int +channel_handle_ctl(Channel *c, fd_set * readset, fd_set * writeset) +{ + char buf[16]; + int len; + + /* Monitor control fd to detect if the slave client exits */ + if (c->ctl_fd != -1 && FD_ISSET(c->ctl_fd, readset)) { + len = read(c->ctl_fd, buf, sizeof(buf)); + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + return 1; + if (len <= 0) { + debug2("channel %d: ctl read<=0", c->self); + if (c->type != SSH_CHANNEL_OPEN) { + debug2("channel %d: not open", c->self); + chan_mark_dead(c); + return -1; + } else { + chan_read_failed(c); + chan_write_failed(c); + } + return -1; + } else + fatal("%s: unexpected data on ctl fd", __func__); + } + return 1; +} +static int +channel_check_window(Channel *c) +{ + if (c->type == SSH_CHANNEL_OPEN && + !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && + c->local_window < c->local_window_max/2 && + c->local_consumed > 0) { + packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); + packet_put_int(c->remote_id); + packet_put_int(c->local_consumed); + packet_send(); + debug2("channel %d: window %d sent adjust %d", + c->self, c->local_window, + c->local_consumed); + c->local_window += c->local_consumed; + c->local_consumed = 0; + } + return 1; +} + +static void +channel_post_open(Channel *c, fd_set * readset, fd_set * writeset) +{ + if (c->delayed) + return; + channel_handle_rfd(c, readset, writeset); + channel_handle_wfd(c, readset, writeset); + if (!compat20) + return; + channel_handle_efd(c, readset, writeset); + channel_handle_ctl(c, readset, writeset); + channel_check_window(c); +} + +static void +channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) +{ + int len; + + /* Send buffered output data to the socket. */ + if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) { + len = write(c->sock, buffer_ptr(&c->output), + buffer_len(&c->output)); + if (len <= 0) + buffer_clear(&c->output); + else + buffer_consume(&c->output, len); + } +} + +static void +channel_handler_init_20(void) +{ + channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open; + channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; + channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_RPORT_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; + channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; + + channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; + channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; + channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; + channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; + channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; + channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; + channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; +} + +static void +channel_handler_init_13(void) +{ + channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13; + channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_13; + channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining; + channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; + channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; + channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; + + channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; + channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; + channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; + channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; + channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; + channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; + channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; +} + +static void +channel_handler_init_15(void) +{ + channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open; + channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open; + channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; + channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; + channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; + + channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; + channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; + channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; + channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; + channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; + channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; +} + +static void +channel_handler_init(void) +{ + int i; + + for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) { + channel_pre[i] = NULL; + channel_post[i] = NULL; + } + if (compat20) + channel_handler_init_20(); + else if (compat13) + channel_handler_init_13(); + else + channel_handler_init_15(); +} + +/* gc dead channels */ +static void +channel_garbage_collect(Channel *c) +{ + if (c == NULL) + return; + if (c->detach_user != NULL) { + if (!chan_is_dead(c, 0)) + return; + debug2("channel %d: gc: notify user", c->self); + c->detach_user(c->self, NULL); + /* if we still have a callback */ + if (c->detach_user != NULL) + return; + debug2("channel %d: gc: user detached", c->self); + } + if (!chan_is_dead(c, 1)) + return; + debug2("channel %d: garbage collecting", c->self); + channel_free(c); +} + +static void +channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset) +{ + static int did_init = 0; + u_int i; + Channel *c; + + if (!did_init) { + channel_handler_init(); + did_init = 1; + } + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c == NULL) + continue; + if (ftab[c->type] != NULL) + (*ftab[c->type])(c, readset, writeset); + channel_garbage_collect(c); + } +} + +/* + * Allocate/update select bitmasks and add any bits relevant to channels in + * select bitmasks. + */ +void +channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, + u_int *nallocp, int rekeying) +{ + u_int n, sz; + + n = MAX(*maxfdp, channel_max_fd); + + sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); + /* perhaps check sz < nalloc/2 and shrink? */ + if (*readsetp == NULL || sz > *nallocp) { + *readsetp = xrealloc(*readsetp, sz); + *writesetp = xrealloc(*writesetp, sz); + *nallocp = sz; + } + *maxfdp = n; + memset(*readsetp, 0, sz); + memset(*writesetp, 0, sz); + + if (!rekeying) + channel_handler(channel_pre, *readsetp, *writesetp); +} + +/* + * After select, perform any appropriate operations for channels which have + * events pending. + */ +void +channel_after_select(fd_set * readset, fd_set * writeset) +{ + channel_handler(channel_post, readset, writeset); +} + + +/* If there is data to send to the connection, enqueue some of it now. */ + +void +channel_output_poll(void) +{ + Channel *c; + u_int i, len; + + for (i = 0; i < channels_alloc; i++) { + c = channels[i]; + if (c == NULL) + continue; + + /* + * We are only interested in channels that can have buffered + * incoming data. + */ + if (compat13) { + if (c->type != SSH_CHANNEL_OPEN && + c->type != SSH_CHANNEL_INPUT_DRAINING) + continue; + } else { + if (c->type != SSH_CHANNEL_OPEN) + continue; + } + if (compat20 && + (c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) { + /* XXX is this true? */ + debug3("channel %d: will not send data after close", c->self); + continue; + } + + /* Get the amount of buffered data for this channel. */ + if ((c->istate == CHAN_INPUT_OPEN || + c->istate == CHAN_INPUT_WAIT_DRAIN) && + (len = buffer_len(&c->input)) > 0) { + /* + * Send some data for the other side over the secure + * connection. + */ + if (compat20) { + if (len > c->remote_window) + len = c->remote_window; + if (len > c->remote_maxpacket) + len = c->remote_maxpacket; + } else { + if (packet_is_interactive()) { + if (len > 1024) + len = 512; + } else { + /* Keep the packets at reasonable size. */ + if (len > packet_get_maxsize()/2) + len = packet_get_maxsize()/2; + } + } + if (len > 0) { + packet_start(compat20 ? + SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA); + packet_put_int(c->remote_id); + packet_put_string(buffer_ptr(&c->input), len); + packet_send(); + buffer_consume(&c->input, len); + c->remote_window -= len; + } + } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { + if (compat13) + fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3"); + /* + * input-buffer is empty and read-socket shutdown: + * tell peer, that we will not send more data: send IEOF. + * hack for extended data: delay EOF if EFD still in use. + */ + if (CHANNEL_EFD_INPUT_ACTIVE(c)) + debug2("channel %d: ibuf_empty delayed efd %d/(%d)", + c->self, c->efd, buffer_len(&c->extended)); + else + chan_ibuf_empty(c); + } + /* Send extended data, i.e. stderr */ + if (compat20 && + !(c->flags & CHAN_EOF_SENT) && + c->remote_window > 0 && + (len = buffer_len(&c->extended)) > 0 && + c->extended_usage == CHAN_EXTENDED_READ) { + debug2("channel %d: rwin %u elen %u euse %d", + c->self, c->remote_window, buffer_len(&c->extended), + c->extended_usage); + if (len > c->remote_window) + len = c->remote_window; + if (len > c->remote_maxpacket) + len = c->remote_maxpacket; + packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA); + packet_put_int(c->remote_id); + packet_put_int(SSH2_EXTENDED_DATA_STDERR); + packet_put_string(buffer_ptr(&c->extended), len); + packet_send(); + buffer_consume(&c->extended, len); + c->remote_window -= len; + debug2("channel %d: sent ext data %d", c->self, len); + } + } +} + + +/* -- protocol input */ + +void +channel_input_data(int type, u_int32_t seq, void *ctxt) +{ + int id; + char *data; + u_int data_len; + Channel *c; + + /* Get the channel number and verify it. */ + id = packet_get_int(); + c = channel_lookup(id); + if (c == NULL) + packet_disconnect("Received data for nonexistent channel %d.", id); + + /* Ignore any data for non-open channels (might happen on close) */ + if (c->type != SSH_CHANNEL_OPEN && + c->type != SSH_CHANNEL_X11_OPEN) + return; + + /* Get the data. */ + data = packet_get_string(&data_len); + + /* + * Ignore data for protocol > 1.3 if output end is no longer open. + * For protocol 2 the sending side is reducing its window as it sends + * data, so we must 'fake' consumption of the data in order to ensure + * that window updates are sent back. Otherwise the connection might + * deadlock. + */ + if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) { + if (compat20) { + c->local_window -= data_len; + c->local_consumed += data_len; + } + xfree(data); + return; + } + + if (compat20) { + if (data_len > c->local_maxpacket) { + logit("channel %d: rcvd big packet %d, maxpack %d", + c->self, data_len, c->local_maxpacket); + } + if (data_len > c->local_window) { + logit("channel %d: rcvd too much data %d, win %d", + c->self, data_len, c->local_window); + xfree(data); + return; + } + c->local_window -= data_len; + } + packet_check_eom(); + buffer_append(&c->output, data, data_len); + xfree(data); +} + +void +channel_input_extended_data(int type, u_int32_t seq, void *ctxt) +{ + int id; + char *data; + u_int data_len, tcode; + Channel *c; + + /* Get the channel number and verify it. */ + id = packet_get_int(); + c = channel_lookup(id); + + if (c == NULL) + packet_disconnect("Received extended_data for bad channel %d.", id); + if (c->type != SSH_CHANNEL_OPEN) { + logit("channel %d: ext data for non open", id); + return; + } + if (c->flags & CHAN_EOF_RCVD) { + if (datafellows & SSH_BUG_EXTEOF) + debug("channel %d: accepting ext data after eof", id); + else + packet_disconnect("Received extended_data after EOF " + "on channel %d.", id); + } + tcode = packet_get_int(); + if (c->efd == -1 || + c->extended_usage != CHAN_EXTENDED_WRITE || + tcode != SSH2_EXTENDED_DATA_STDERR) { + logit("channel %d: bad ext data", c->self); + return; + } + data = packet_get_string(&data_len); + packet_check_eom(); + if (data_len > c->local_window) { + logit("channel %d: rcvd too much extended_data %d, win %d", + c->self, data_len, c->local_window); + xfree(data); + return; + } + debug2("channel %d: rcvd ext data %d", c->self, data_len); + c->local_window -= data_len; + buffer_append(&c->extended, data, data_len); + xfree(data); +} + +void +channel_input_ieof(int type, u_int32_t seq, void *ctxt) +{ + int id; + Channel *c; + + id = packet_get_int(); + packet_check_eom(); + c = channel_lookup(id); + if (c == NULL) + packet_disconnect("Received ieof for nonexistent channel %d.", id); + chan_rcvd_ieof(c); + + /* XXX force input close */ + if (c->force_drain && c->istate == CHAN_INPUT_OPEN) { + debug("channel %d: FORCE input drain", c->self); + c->istate = CHAN_INPUT_WAIT_DRAIN; + if (buffer_len(&c->input) == 0) + chan_ibuf_empty(c); + } + +} + +void +channel_input_close(int type, u_int32_t seq, void *ctxt) +{ + int id; + Channel *c; + + id = packet_get_int(); + packet_check_eom(); + c = channel_lookup(id); + if (c == NULL) + packet_disconnect("Received close for nonexistent channel %d.", id); + + /* + * 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(c->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 (c->type != SSH_CHANNEL_CLOSED) { + /* + * Not a closed channel - mark it as draining, which will + * cause it to be freed later. + */ + buffer_clear(&c->input); + c->type = SSH_CHANNEL_OUTPUT_DRAINING; + } +} + +/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */ +void +channel_input_oclose(int type, u_int32_t seq, void *ctxt) +{ + int id = packet_get_int(); + Channel *c = channel_lookup(id); + + packet_check_eom(); + if (c == NULL) + packet_disconnect("Received oclose for nonexistent channel %d.", id); + chan_rcvd_oclose(c); +} + +void +channel_input_close_confirmation(int type, u_int32_t seq, void *ctxt) +{ + int id = packet_get_int(); + Channel *c = channel_lookup(id); + + packet_check_eom(); + if (c == NULL) + packet_disconnect("Received close confirmation for " + "out-of-range channel %d.", id); + if (c->type != SSH_CHANNEL_CLOSED) + packet_disconnect("Received close confirmation for " + "non-closed channel %d (type %d).", id, c->type); + channel_free(c); +} + +void +channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt) +{ + int id, remote_id; + Channel *c; + + id = packet_get_int(); + c = channel_lookup(id); + + if (c==NULL || c->type != SSH_CHANNEL_OPENING) + packet_disconnect("Received open confirmation for " + "non-opening channel %d.", id); + remote_id = packet_get_int(); + /* Record the remote channel number and mark that the channel is now open. */ + c->remote_id = remote_id; + c->type = SSH_CHANNEL_OPEN; + + if (compat20) { + c->remote_window = packet_get_int(); + c->remote_maxpacket = packet_get_int(); + if (c->confirm) { + debug2("callback start"); + c->confirm(c->self, c->confirm_ctx); + debug2("callback done"); + } + debug2("channel %d: open confirm rwindow %u rmax %u", c->self, + c->remote_window, c->remote_maxpacket); + } + packet_check_eom(); +} + +static char * +reason2txt(int reason) +{ + switch (reason) { + case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED: + return "administratively prohibited"; + case SSH2_OPEN_CONNECT_FAILED: + return "connect failed"; + case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE: + return "unknown channel type"; + case SSH2_OPEN_RESOURCE_SHORTAGE: + return "resource shortage"; + } + return "unknown reason"; +} + +void +channel_input_open_failure(int type, u_int32_t seq, void *ctxt) +{ + int id, reason; + char *msg = NULL, *lang = NULL; + Channel *c; + + id = packet_get_int(); + c = channel_lookup(id); + + if (c==NULL || c->type != SSH_CHANNEL_OPENING) + packet_disconnect("Received open failure for " + "non-opening channel %d.", id); + if (compat20) { + reason = packet_get_int(); + if (!(datafellows & SSH_BUG_OPENFAILURE)) { + msg = packet_get_string(NULL); + lang = packet_get_string(NULL); + } + logit("channel %d: open failed: %s%s%s", id, + reason2txt(reason), msg ? ": ": "", msg ? msg : ""); + if (msg != NULL) + xfree(msg); + if (lang != NULL) + xfree(lang); + } + packet_check_eom(); + /* Free the channel. This will also close the socket. */ + channel_free(c); +} + +void +channel_input_window_adjust(int type, u_int32_t seq, void *ctxt) +{ + Channel *c; + int id; + u_int adjust; + + if (!compat20) + return; + + /* Get the channel number and verify it. */ + id = packet_get_int(); + c = channel_lookup(id); + + if (c == NULL || c->type != SSH_CHANNEL_OPEN) { + logit("Received window adjust for " + "non-open channel %d.", id); + return; + } + adjust = packet_get_int(); + packet_check_eom(); + debug2("channel %d: rcvd adjust %u", id, adjust); + c->remote_window += adjust; +} + +void +channel_input_port_open(int type, u_int32_t seq, void *ctxt) +{ + Channel *c = NULL; + u_short host_port; + char *host, *originator_string; + int remote_id, sock = -1; + + remote_id = packet_get_int(); + host = packet_get_string(NULL); + host_port = packet_get_int(); + + if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) { + originator_string = packet_get_string(NULL); + } else { + originator_string = xstrdup("unknown (remote did not supply name)"); + } + packet_check_eom(); + sock = channel_connect_to(host, host_port); + if (sock != -1) { + c = channel_new("connected socket", + SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0, + originator_string, 1); + c->remote_id = remote_id; + } + xfree(originator_string); + if (c == NULL) { + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(remote_id); + packet_send(); + } + xfree(host); +} + + +/* -- tcp forwarding */ + +void +channel_set_af(int af) +{ + IPv4or6 = af; +} + +static int +channel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, + const char *host_to_connect, u_short port_to_connect, int gateway_ports) +{ + Channel *c; + int success, sock, on = 1; + struct addrinfo hints, *ai, *aitop; + const char *host; + char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + + success = 0; + host = (type == SSH_CHANNEL_RPORT_LISTENER) ? + listen_addr : host_to_connect; + + if (host == NULL) { + error("No forward host name."); + return success; + } + if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) { + error("Forward host name too long."); + return success; + } + + /* + * getaddrinfo returns a loopback address if the hostname is + * set to NULL and hints.ai_flags is not AI_PASSIVE + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = IPv4or6; + hints.ai_flags = gateway_ports ? AI_PASSIVE : 0; + hints.ai_socktype = SOCK_STREAM; + snprintf(strport, sizeof strport, "%d", listen_port); + if (getaddrinfo(NULL, strport, &hints, &aitop) != 0) + packet_disconnect("getaddrinfo: fatal error"); + + for (ai = aitop; ai; ai = ai->ai_next) { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + continue; + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), + strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + error("channel_setup_fwd_listener: getnameinfo failed"); + continue; + } + /* Create a port to listen for the host. */ + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) { + /* this is no error since kernel may not support ipv6 */ + verbose("socket: %.100s", strerror(errno)); + continue; + } + /* + * Set socket options. + * Allow local port reuse in TIME_WAIT. + */ + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, + sizeof(on)) == -1) + error("setsockopt SO_REUSEADDR: %s", strerror(errno)); + + debug("Local forwarding listening on %s port %s.", ntop, strport); + + /* Bind the socket to the address. */ + if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { + /* address can be in use ipv6 address is already bound */ + if (!ai->ai_next) + error("bind: %.100s", strerror(errno)); + else + verbose("bind: %.100s", strerror(errno)); + + close(sock); + continue; + } + /* Start listening for connections on the socket. */ + if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { + error("listen: %.100s", strerror(errno)); + close(sock); + continue; + } + /* Allocate a channel number for the socket. */ + c = channel_new("port listener", type, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, + 0, "port listener", 1); + strlcpy(c->path, host, sizeof(c->path)); + c->host_port = port_to_connect; + c->listening_port = listen_port; + success = 1; + } + if (success == 0) + error("channel_setup_fwd_listener: cannot listen to port: %d", + listen_port); + freeaddrinfo(aitop); + return success; +} + +int +channel_cancel_rport_listener(const char *host, u_short port) +{ + u_int i; + int found = 0; + + for(i = 0; i < channels_alloc; i++) { + Channel *c = channels[i]; + + if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && + strncmp(c->path, host, sizeof(c->path)) == 0 && + c->listening_port == port) { + debug2("%s: close clannel %d", __func__, i); + channel_free(c); + found = 1; + } + } + + return (found); +} + +/* protocol local port fwd, used by ssh (and sshd in v1) */ +int +channel_setup_local_fwd_listener(u_short listen_port, + const char *host_to_connect, u_short port_to_connect, int gateway_ports) +{ + return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, + NULL, listen_port, host_to_connect, port_to_connect, gateway_ports); +} + +/* protocol v2 remote port fwd, used by sshd */ +int +channel_setup_remote_fwd_listener(const char *listen_address, + u_short listen_port, int gateway_ports) +{ + return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, + listen_address, listen_port, NULL, 0, gateway_ports); +} + +/* + * Initiate forwarding of connections to port "port" on remote host through + * the secure channel to host:port from local side. + */ + +void +channel_request_remote_forwarding(u_short listen_port, + const char *host_to_connect, u_short port_to_connect) +{ + int type, success = 0; + + /* 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"); + + /* Send the forward request to the remote side. */ + if (compat20) { + const char *address_to_bind = "0.0.0.0"; + packet_start(SSH2_MSG_GLOBAL_REQUEST); + packet_put_cstring("tcpip-forward"); + packet_put_char(1); /* boolean: want reply */ + packet_put_cstring(address_to_bind); + packet_put_int(listen_port); + packet_send(); + packet_write_wait(); + /* Assume that server accepts the request */ + success = 1; + } else { + packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); + packet_put_int(listen_port); + packet_put_cstring(host_to_connect); + packet_put_int(port_to_connect); + packet_send(); + packet_write_wait(); + + /* Wait for response from the remote side. */ + type = packet_read(); + switch (type) { + case SSH_SMSG_SUCCESS: + success = 1; + break; + case SSH_SMSG_FAILURE: + logit("Warning: Server denied remote port forwarding."); + break; + default: + /* Unknown packet */ + packet_disconnect("Protocol error for port forward request:" + "received packet type %d.", type); + } + } + if (success) { + permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); + permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; + permitted_opens[num_permitted_opens].listen_port = listen_port; + num_permitted_opens++; + } +} + +/* + * Request cancellation of remote forwarding of connection host:port from + * local side. + */ +void +channel_request_rforward_cancel(u_short port) +{ + int i; + const char *address_to_bind = "0.0.0.0"; + + if (!compat20) + return; + + for (i = 0; i < num_permitted_opens; i++) { + if (permitted_opens[i].host_to_connect != NULL && + permitted_opens[i].listen_port == port) + break; + } + if (i >= num_permitted_opens) { + debug("%s: requested forward not found", __func__); + return; + } + packet_start(SSH2_MSG_GLOBAL_REQUEST); + packet_put_cstring("cancel-tcpip-forward"); + packet_put_char(0); + packet_put_cstring(address_to_bind); + packet_put_int(port); + packet_send(); + + permitted_opens[i].listen_port = 0; + permitted_opens[i].port_to_connect = 0; + free(permitted_opens[i].host_to_connect); + permitted_opens[i].host_to_connect = NULL; +} + +/* + * 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 gateway_ports) +{ + u_short port, host_port; + char *hostname; + + /* Get arguments from the packet. */ + port = packet_get_int(); + hostname = packet_get_string(NULL); + host_port = packet_get_int(); + +#ifndef HAVE_CYGWIN + /* + * Check that an unprivileged user is not trying to forward a + * privileged port. + */ + if (port < IPPORT_RESERVED && !is_root) + packet_disconnect( + "Requested forwarding of port %d but user is not root.", + port); + if (host_port == 0) + packet_disconnect("Dynamic forwarding denied."); +#endif + + /* Initiate forwarding */ + channel_setup_local_fwd_listener(port, hostname, host_port, gateway_ports); + + /* Free the argument string. */ + xfree(hostname); +} + +/* + * Permits opening to any host/port if permitted_opens[] is empty. 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) +{ + if (num_permitted_opens == 0) + all_opens_permitted = 1; +} + +void +channel_add_permitted_opens(char *host, int port) +{ + if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) + fatal("channel_request_remote_forwarding: too many forwards"); + debug("allow port forwarding to host %s port %d", host, port); + + permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); + permitted_opens[num_permitted_opens].port_to_connect = port; + num_permitted_opens++; + + all_opens_permitted = 0; +} + +void +channel_clear_permitted_opens(void) +{ + int i; + + for (i = 0; i < num_permitted_opens; i++) + if (permitted_opens[i].host_to_connect != NULL) + xfree(permitted_opens[i].host_to_connect); + num_permitted_opens = 0; + +} + + +/* return socket to remote host, port */ +static int +connect_to(const char *host, u_short port) +{ + struct addrinfo hints, *ai, *aitop; + char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + int gaierr; + int sock = -1; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = IPv4or6; + hints.ai_socktype = SOCK_STREAM; + snprintf(strport, sizeof strport, "%d", port); + if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { + error("connect_to %.100s: unknown host (%s)", host, + gai_strerror(gaierr)); + return -1; + } + for (ai = aitop; ai; ai = ai->ai_next) { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + continue; + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), + strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + error("connect_to: getnameinfo failed"); + continue; + } + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) { + if (ai->ai_next == NULL) + error("socket: %.100s", strerror(errno)); + else + verbose("socket: %.100s", strerror(errno)); + continue; + } + if (set_nonblock(sock) == -1) + fatal("%s: set_nonblock(%d)", __func__, sock); + if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && + errno != EINPROGRESS) { + error("connect_to %.100s port %s: %.100s", ntop, strport, + strerror(errno)); + close(sock); + continue; /* fail -- try next */ + } + break; /* success */ + + } + freeaddrinfo(aitop); + if (!ai) { + error("connect_to %.100s port %d: failed.", host, port); + return -1; + } + /* success */ + set_nodelay(sock); + return sock; +} + +int +channel_connect_by_listen_address(u_short listen_port) +{ + int i; + + for (i = 0; i < num_permitted_opens; i++) + if (permitted_opens[i].host_to_connect != NULL && + permitted_opens[i].listen_port == listen_port) + return connect_to( + permitted_opens[i].host_to_connect, + permitted_opens[i].port_to_connect); + error("WARNING: Server requests forwarding for unknown listen_port %d", + listen_port); + return -1; +} + +/* Check if connecting to that port is permitted and connect. */ +int +channel_connect_to(const char *host, u_short port) +{ + int i, permit; + + permit = all_opens_permitted; + if (!permit) { + for (i = 0; i < num_permitted_opens; i++) + if (permitted_opens[i].host_to_connect != NULL && + permitted_opens[i].port_to_connect == port && + strcmp(permitted_opens[i].host_to_connect, host) == 0) + permit = 1; + + } + if (!permit) { + logit("Received request to connect to host %.100s port %d, " + "but the request was denied.", host, port); + return -1; + } + return connect_to(host, port); +} + +void +channel_send_window_changes(void) +{ + u_int i; + struct winsize ws; + + for (i = 0; i < channels_alloc; i++) { + if (channels[i] == NULL || + channels[i]->type != SSH_CHANNEL_OPEN) + continue; + if (ioctl(channels[i]->rfd, TIOCGWINSZ, &ws) < 0) + continue; + channel_request_start(i, "window-change", 0); + packet_put_int(ws.ws_col); + packet_put_int(ws.ws_row); + packet_put_int(ws.ws_xpixel); + packet_put_int(ws.ws_ypixel); + packet_send(); + } +} + +/* -- X11 forwarding */ + +/* + * Creates an internet domain socket for listening for X11 connections. + * Returns 0 and a suitable display number for the DISPLAY variable + * stored in display_numberp , or -1 if an error occurs. + */ +int +x11_create_display_inet(int x11_display_offset, int x11_use_localhost, + int single_connection, u_int *display_numberp) +{ + Channel *nc = NULL; + int display_number, sock; + u_short port; + struct addrinfo hints, *ai, *aitop; + char strport[NI_MAXSERV]; + int gaierr, n, num_socks = 0, socks[NUM_SOCKS]; + + for (display_number = x11_display_offset; + display_number < MAX_DISPLAYS; + display_number++) { + port = 6000 + display_number; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = IPv4or6; + hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + snprintf(strport, sizeof strport, "%d", port); + if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) { + error("getaddrinfo: %.100s", gai_strerror(gaierr)); + return -1; + } + for (ai = aitop; ai; ai = ai->ai_next) { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + continue; + sock = socket(ai->ai_family, ai->ai_socktype, + ai->ai_protocol); + if (sock < 0) { + if ((errno != EINVAL) && (errno != EAFNOSUPPORT)) { + error("socket: %.100s", strerror(errno)); + freeaddrinfo(aitop); + return -1; + } else { + debug("x11_create_display_inet: Socket family %d not supported", + ai->ai_family); + continue; + } + } +#ifdef IPV6_V6ONLY + if (ai->ai_family == AF_INET6) { + int on = 1; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) + error("setsockopt IPV6_V6ONLY: %.100s", strerror(errno)); + } +#endif + if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { + debug2("bind port %d: %.100s", port, strerror(errno)); + close(sock); + + if (ai->ai_next) + continue; + + for (n = 0; n < num_socks; n++) { + close(socks[n]); + } + num_socks = 0; + break; + } + socks[num_socks++] = sock; +#ifndef DONT_TRY_OTHER_AF + if (num_socks == NUM_SOCKS) + break; +#else + if (x11_use_localhost) { + if (num_socks == NUM_SOCKS) + break; + } else { + break; + } +#endif + } + freeaddrinfo(aitop); + if (num_socks > 0) + break; + } + if (display_number >= MAX_DISPLAYS) { + error("Failed to allocate internet-domain X11 display socket."); + return -1; + } + /* Start listening for connections on the socket. */ + for (n = 0; n < num_socks; n++) { + sock = socks[n]; + if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { + error("listen: %.100s", strerror(errno)); + close(sock); + return -1; + } + } + + /* Allocate a channel for each socket. */ + for (n = 0; n < num_socks; n++) { + sock = socks[n]; + nc = channel_new("x11 listener", + SSH_CHANNEL_X11_LISTENER, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, + 0, "X11 inet listener", 1); + nc->single_connection = single_connection; + } + + /* Return the display number for the DISPLAY environment variable. */ + *display_numberp = display_number; + return (0); +} + +static int +connect_local_xsocket(u_int dnr) +{ + int sock; + struct sockaddr_un addr; + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + error("socket: %.100s", strerror(errno)); + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, 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; +} + +int +x11_connect_display(void) +{ + int display_number, sock = 0; + const char *display; + char buf[1024], *cp; + struct addrinfo hints, *ai, *aitop; + char strport[NI_MAXSERV]; + int gaierr; + + /* Try to open a socket for the local X server. */ + display = getenv("DISPLAY"); + if (!display) { + error("DISPLAY not set."); + return -1; + } + /* + * 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); + return -1; + } + /* Create a socket. */ + sock = connect_local_xsocket(display_number); + if (sock < 0) + return -1; + + /* OK, we now have a connection to the display. */ + return sock; + } + /* + * Connect to an inet socket. The DISPLAY value is supposedly + * hostname:d[.s], where hostname may also be numeric IP address. + */ + strlcpy(buf, display, sizeof(buf)); + cp = strchr(buf, ':'); + if (!cp) { + error("Could not find ':' in DISPLAY: %.100s", display); + return -1; + } + *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); + return -1; + } + + /* Look up the host address */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = IPv4or6; + hints.ai_socktype = SOCK_STREAM; + snprintf(strport, sizeof strport, "%d", 6000 + display_number); + if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { + error("%.100s: unknown host. (%s)", buf, gai_strerror(gaierr)); + return -1; + } + for (ai = aitop; ai; ai = ai->ai_next) { + /* Create a socket. */ + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) { + debug2("socket: %.100s", strerror(errno)); + continue; + } + /* Connect it to the display. */ + if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { + debug2("connect %.100s port %d: %.100s", buf, + 6000 + display_number, strerror(errno)); + close(sock); + continue; + } + /* Success */ + break; + } + freeaddrinfo(aitop); + if (!ai) { + error("connect %.100s port %d: %.100s", buf, 6000 + display_number, + strerror(errno)); + return -1; + } + set_nodelay(sock); + return sock; +} + +/* + * 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 type, u_int32_t seq, void *ctxt) +{ + Channel *c = NULL; + int remote_id, sock = 0; + char *remote_host; + + debug("Received X11 open request."); + + remote_id = packet_get_int(); + + if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) { + remote_host = packet_get_string(NULL); + } else { + remote_host = xstrdup("unknown (remote did not supply name)"); + } + packet_check_eom(); + + /* Obtain a connection to the real X display. */ + sock = x11_connect_display(); + if (sock != -1) { + /* Allocate a channel for this connection. */ + c = channel_new("connected x11 socket", + SSH_CHANNEL_X11_OPEN, sock, sock, -1, 0, 0, 0, + remote_host, 1); + c->remote_id = remote_id; + c->force_drain = 1; + } + xfree(remote_host); + if (c == NULL) { + /* Send refusal to the remote host. */ + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(remote_id); + } else { + /* Send a confirmation to the remote host. */ + packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); + packet_put_int(remote_id); + packet_put_int(c->self); + } + packet_send(); +} + +/* dummy protocol handler that denies SSH-1 requests (agent/x11) */ +void +deny_input_open(int type, u_int32_t seq, void *ctxt) +{ + int rchan = packet_get_int(); + + switch (type) { + case SSH_SMSG_AGENT_OPEN: + error("Warning: ssh server tried agent forwarding."); + break; + case SSH_SMSG_X11_OPEN: + error("Warning: ssh server tried X11 forwarding."); + break; + default: + error("deny_input_open: type %d", type); + break; + } + error("Warning: this is probably a break in attempt by a malicious server."); + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(rchan); + packet_send(); +} + +/* + * Requests forwarding of X11 connections, generates fake authentication + * data, and enables authentication spoofing. + * This should be called in the client only. + */ +void +x11_request_forwarding_with_spoofing(int client_session_id, + const char *proto, const char *data) +{ + u_int data_len = (u_int) strlen(data) / 2; + u_int i, value, len; + char *new_data; + int screen_number; + const char *cp; + u_int32_t rnd = 0; + + cp = getenv("DISPLAY"); + if (cp) + cp = strchr(cp, ':'); + if (cp) + cp = strchr(cp, '.'); + if (cp) + screen_number = atoi(cp + 1); + else + screen_number = 0; + + /* Save protocol name. */ + x11_saved_proto = xstrdup(proto); + + /* + * Extract real authentication data and generate fake data of the + * same length. + */ + x11_saved_data = xmalloc(data_len); + x11_fake_data = xmalloc(data_len); + for (i = 0; i < data_len; i++) { + if (sscanf(data + 2 * i, "%2x", &value) != 1) + fatal("x11_request_forwarding: bad authentication data: %.100s", data); + if (i % 4 == 0) + rnd = arc4random(); + x11_saved_data[i] = value; + x11_fake_data[i] = rnd & 0xff; + rnd >>= 8; + } + x11_saved_data_len = data_len; + x11_fake_data_len = data_len; + + /* Convert the fake data into hex. */ + len = 2 * data_len + 1; + new_data = xmalloc(len); + for (i = 0; i < data_len; i++) + snprintf(new_data + 2 * i, len - 2 * i, + "%02x", (u_char) x11_fake_data[i]); + + /* Send the request packet. */ + if (compat20) { + channel_request_start(client_session_id, "x11-req", 0); + packet_put_char(0); /* XXX bool single connection */ + } else { + packet_start(SSH_CMSG_X11_REQUEST_FORWARDING); + } + packet_put_cstring(proto); + packet_put_cstring(new_data); + packet_put_int(screen_number); + packet_send(); + packet_write_wait(); + xfree(new_data); +} + + +/* -- agent forwarding */ + +/* Sends a message to the server to request authentication fd forwarding. */ + +void +auth_request_forwarding(void) +{ + packet_start(SSH_CMSG_AGENT_REQUEST_FORWARDING); + packet_send(); + packet_write_wait(); +} diff --git a/crypto/openssh-3.9p1/channels.h b/crypto/openssh-3.9p1/channels.h new file mode 100644 index 0000000000..f8dc8249c2 --- /dev/null +++ b/crypto/openssh-3.9p1/channels.h @@ -0,0 +1,238 @@ +/* $OpenBSD: channels.h,v 1.74 2004/08/11 21:43:04 avsm Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ +/* + * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CHANNEL_H +#define CHANNEL_H + +#include "buffer.h" + +/* Definitions for channel types. */ +#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_SOCKET 6 /* authentication socket */ +#define SSH_CHANNEL_X11_OPEN 7 /* reading first X11 packet */ +#define SSH_CHANNEL_INPUT_DRAINING 8 /* sending remaining data to conn */ +#define SSH_CHANNEL_OUTPUT_DRAINING 9 /* sending remaining data to app */ +#define SSH_CHANNEL_LARVAL 10 /* larval session */ +#define SSH_CHANNEL_RPORT_LISTENER 11 /* Listening to a R-style port */ +#define SSH_CHANNEL_CONNECTING 12 +#define SSH_CHANNEL_DYNAMIC 13 +#define SSH_CHANNEL_ZOMBIE 14 /* Almost dead. */ +#define SSH_CHANNEL_MAX_TYPE 15 + +#define SSH_CHANNEL_PATH_LEN 256 + +struct Channel; +typedef struct Channel Channel; + +typedef void channel_callback_fn(int, void *); +typedef int channel_filter_fn(struct Channel *, char *, int); + +struct Channel { + int type; /* channel type/state */ + int self; /* my own channel identifier */ + int remote_id; /* channel identifier for remote peer */ + u_int istate; /* input from channel (state of receive half) */ + u_int ostate; /* output to channel (state of transmit half) */ + int flags; /* close sent/rcvd */ + int rfd; /* read fd */ + int wfd; /* write fd */ + int efd; /* extended fd */ + int sock; /* sock fd */ + int ctl_fd; /* control fd (client sharing) */ + int isatty; /* rfd is a tty */ + int wfd_isatty; /* wfd is a tty */ + int force_drain; /* force close on iEOF */ + int delayed; /* fdset hack */ + Buffer input; /* data read from socket, to be sent over + * encrypted connection */ + Buffer output; /* data received over encrypted connection for + * send on socket */ + Buffer extended; + char path[SSH_CHANNEL_PATH_LEN]; + /* path for unix domain sockets, or host name for forwards */ + int listening_port; /* port being listened for forwards */ + int host_port; /* remote port to connect for forwards */ + char *remote_name; /* remote hostname */ + + u_int remote_window; + u_int remote_maxpacket; + u_int local_window; + u_int local_window_max; + u_int local_consumed; + u_int local_maxpacket; + int extended_usage; + int single_connection; + + char *ctype; /* type */ + + /* callback */ + channel_callback_fn *confirm; + channel_callback_fn *detach_user; + void *confirm_ctx; + + /* filter */ + channel_filter_fn *input_filter; +}; + +#define CHAN_EXTENDED_IGNORE 0 +#define CHAN_EXTENDED_READ 1 +#define CHAN_EXTENDED_WRITE 2 + +/* default window/packet sizes for tcp/x11-fwd-channel */ +#define CHAN_SES_PACKET_DEFAULT (32*1024) +#define CHAN_SES_WINDOW_DEFAULT (4*CHAN_SES_PACKET_DEFAULT) +#define CHAN_TCP_PACKET_DEFAULT (32*1024) +#define CHAN_TCP_WINDOW_DEFAULT (4*CHAN_TCP_PACKET_DEFAULT) +#define CHAN_X11_PACKET_DEFAULT (16*1024) +#define CHAN_X11_WINDOW_DEFAULT (4*CHAN_X11_PACKET_DEFAULT) + +/* possible input states */ +#define CHAN_INPUT_OPEN 0 +#define CHAN_INPUT_WAIT_DRAIN 1 +#define CHAN_INPUT_WAIT_OCLOSE 2 +#define CHAN_INPUT_CLOSED 3 + +/* possible output states */ +#define CHAN_OUTPUT_OPEN 0 +#define CHAN_OUTPUT_WAIT_DRAIN 1 +#define CHAN_OUTPUT_WAIT_IEOF 2 +#define CHAN_OUTPUT_CLOSED 3 + +#define CHAN_CLOSE_SENT 0x01 +#define CHAN_CLOSE_RCVD 0x02 +#define CHAN_EOF_SENT 0x04 +#define CHAN_EOF_RCVD 0x08 + +/* check whether 'efd' is still in use */ +#define CHANNEL_EFD_INPUT_ACTIVE(c) \ + (compat20 && c->extended_usage == CHAN_EXTENDED_READ && \ + (c->efd != -1 || \ + buffer_len(&c->extended) > 0)) +#define CHANNEL_EFD_OUTPUT_ACTIVE(c) \ + (compat20 && c->extended_usage == CHAN_EXTENDED_WRITE && \ + ((c->efd != -1 && !(c->flags & (CHAN_EOF_RCVD|CHAN_CLOSE_RCVD))) || \ + buffer_len(&c->extended) > 0)) + +/* channel management */ + +Channel *channel_lookup(int); +Channel *channel_new(char *, int, int, int, int, u_int, u_int, int, char *, int); +void channel_set_fds(int, int, int, int, int, int, u_int); +void channel_free(Channel *); +void channel_free_all(void); +void channel_stop_listening(void); + +void channel_send_open(int); +void channel_request_start(int, char *, int); +void channel_register_cleanup(int, channel_callback_fn *); +void channel_register_confirm(int, channel_callback_fn *, void *); +void channel_register_filter(int, channel_filter_fn *); +void channel_cancel_cleanup(int); +int channel_close_fd(int *); +void channel_send_window_changes(void); + +/* protocol handler */ + +void channel_input_close(int, u_int32_t, void *); +void channel_input_close_confirmation(int, u_int32_t, void *); +void channel_input_data(int, u_int32_t, void *); +void channel_input_extended_data(int, u_int32_t, void *); +void channel_input_ieof(int, u_int32_t, void *); +void channel_input_oclose(int, u_int32_t, void *); +void channel_input_open_confirmation(int, u_int32_t, void *); +void channel_input_open_failure(int, u_int32_t, void *); +void channel_input_port_open(int, u_int32_t, void *); +void channel_input_window_adjust(int, u_int32_t, void *); + +/* file descriptor handling (read/write) */ + +void channel_prepare_select(fd_set **, fd_set **, int *, u_int*, int); +void channel_after_select(fd_set *, fd_set *); +void channel_output_poll(void); + +int channel_not_very_much_buffered_data(void); +void channel_close_all(void); +int channel_still_open(void); +char *channel_open_message(void); +int channel_find_open(void); + +/* tcp forwarding */ +void channel_set_af(int af); +void channel_permit_all_opens(void); +void channel_add_permitted_opens(char *, int); +void channel_clear_permitted_opens(void); +void channel_input_port_forward_request(int, int); +int channel_connect_to(const char *, u_short); +int channel_connect_by_listen_address(u_short); +void channel_request_remote_forwarding(u_short, const char *, u_short); +void channel_request_rforward_cancel(u_short port); +int channel_setup_local_fwd_listener(u_short, const char *, u_short, int); +int channel_setup_remote_fwd_listener(const char *, u_short, int); +int channel_cancel_rport_listener(const char *, u_short); + +/* x11 forwarding */ + +int x11_connect_display(void); +int x11_create_display_inet(int, int, int, u_int *); +void x11_input_open(int, u_int32_t, void *); +void x11_request_forwarding_with_spoofing(int, const char *, const char *); +void deny_input_open(int, u_int32_t, void *); + +/* agent forwarding */ + +void auth_request_forwarding(void); + +/* channel close */ + +int chan_is_dead(Channel *, int); +void chan_mark_dead(Channel *); + +/* channel events */ + +void chan_rcvd_oclose(Channel *); +void chan_read_failed(Channel *); +void chan_ibuf_empty(Channel *); + +void chan_rcvd_ieof(Channel *); +void chan_write_failed(Channel *); +void chan_obuf_empty(Channel *); + +#endif diff --git a/crypto/openssh-3.9p1/cipher-3des1.c b/crypto/openssh-3.9p1/cipher-3des1.c new file mode 100644 index 0000000000..f815e8ae52 --- /dev/null +++ b/crypto/openssh-3.9p1/cipher-3des1.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2003 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: cipher-3des1.c,v 1.2 2003/12/22 20:29:55 markus Exp $"); + +#include +#include "xmalloc.h" +#include "log.h" + +#if OPENSSL_VERSION_NUMBER < 0x00906000L +#define SSH_OLD_EVP +#endif + +/* + * This is used by SSH1: + * + * What kind of triple 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. + */ +struct ssh1_3des_ctx +{ + EVP_CIPHER_CTX k1, k2, k3; +}; + +const EVP_CIPHER * evp_ssh1_3des(void); +void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); + +static int +ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, + int enc) +{ + struct ssh1_3des_ctx *c; + u_char *k1, *k2, *k3; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { + c = xmalloc(sizeof(*c)); + EVP_CIPHER_CTX_set_app_data(ctx, c); + } + if (key == NULL) + return (1); + if (enc == -1) + enc = ctx->encrypt; + k1 = k2 = k3 = (u_char *) key; + k2 += 8; + if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) { + if (enc) + k3 += 16; + else + k1 += 16; + } + EVP_CIPHER_CTX_init(&c->k1); + EVP_CIPHER_CTX_init(&c->k2); + EVP_CIPHER_CTX_init(&c->k3); +#ifdef SSH_OLD_EVP + EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc); + EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc); + EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc); +#else + if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 || + EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 || + EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) { + memset(c, 0, sizeof(*c)); + xfree(c); + EVP_CIPHER_CTX_set_app_data(ctx, NULL); + return (0); + } +#endif + return (1); +} + +static int +ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len) +{ + struct ssh1_3des_ctx *c; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { + error("ssh1_3des_cbc: no context"); + return (0); + } +#ifdef SSH_OLD_EVP + EVP_Cipher(&c->k1, dest, (u_char *)src, len); + EVP_Cipher(&c->k2, dest, dest, len); + EVP_Cipher(&c->k3, dest, dest, len); +#else + if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 || + EVP_Cipher(&c->k2, dest, dest, len) == 0 || + EVP_Cipher(&c->k3, dest, dest, len) == 0) + return (0); +#endif + return (1); +} + +static int +ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct ssh1_3des_ctx *c; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { + EVP_CIPHER_CTX_cleanup(&c->k1); + EVP_CIPHER_CTX_cleanup(&c->k2); + EVP_CIPHER_CTX_cleanup(&c->k3); + memset(c, 0, sizeof(*c)); + xfree(c); + EVP_CIPHER_CTX_set_app_data(ctx, NULL); + } + return (1); +} + +void +ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len) +{ + struct ssh1_3des_ctx *c; + + if (len != 24) + fatal("%s: bad 3des iv length: %d", __func__, len); + if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL) + fatal("%s: no 3des context", __func__); + if (doset) { + debug3("%s: Installed 3DES IV", __func__); + memcpy(c->k1.iv, iv, 8); + memcpy(c->k2.iv, iv + 8, 8); + memcpy(c->k3.iv, iv + 16, 8); + } else { + debug3("%s: Copying 3DES IV", __func__); + memcpy(iv, c->k1.iv, 8); + memcpy(iv + 8, c->k2.iv, 8); + memcpy(iv + 16, c->k3.iv, 8); + } +} + +const EVP_CIPHER * +evp_ssh1_3des(void) +{ + static EVP_CIPHER ssh1_3des; + + memset(&ssh1_3des, 0, sizeof(EVP_CIPHER)); + ssh1_3des.nid = NID_undef; + ssh1_3des.block_size = 8; + ssh1_3des.iv_len = 0; + ssh1_3des.key_len = 16; + ssh1_3des.init = ssh1_3des_init; + ssh1_3des.cleanup = ssh1_3des_cleanup; + ssh1_3des.do_cipher = ssh1_3des_cbc; +#ifndef SSH_OLD_EVP + ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH; +#endif + return (&ssh1_3des); +} diff --git a/crypto/openssh-3.9p1/cipher-acss.c b/crypto/openssh-3.9p1/cipher-acss.c new file mode 100644 index 0000000000..3a966a74d5 --- /dev/null +++ b/crypto/openssh-3.9p1/cipher-acss.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2004 The OpenBSD project + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" +#include + +RCSID("$Id: cipher-acss.c,v 1.2 2004/02/06 04:26:11 dtucker Exp $"); + +#if !defined(EVP_CTRL_SET_ACSS_MODE) && (OPENSSL_VERSION_NUMBER >= 0x00907000L) + +#include "acss.h" + +#define data(ctx) ((EVP_ACSS_KEY *)(ctx)->cipher_data) + +typedef struct { + ACSS_KEY ks; +} EVP_ACSS_KEY; + +#define EVP_CTRL_SET_ACSS_MODE 0xff06 +#define EVP_CTRL_SET_ACSS_SUBKEY 0xff07 + +static int +acss_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + acss_setkey(&data(ctx)->ks,key,enc,ACSS_DATA); + return 1; +} + +static int +acss_ciph(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, + unsigned int inl) +{ + acss(&data(ctx)->ks,inl,in,out); + return 1; +} + +static int +acss_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) +{ + switch(type) { + case EVP_CTRL_SET_ACSS_MODE: + data(ctx)->ks.mode = arg; + return 1; + case EVP_CTRL_SET_ACSS_SUBKEY: + acss_setsubkey(&data(ctx)->ks,(unsigned char *)ptr); + return 1; + default: + return -1; + } +} + +const EVP_CIPHER * +evp_acss(void) +{ + static EVP_CIPHER acss_cipher; + + memset(&acss_cipher, 0, sizeof(EVP_CIPHER)); + + acss_cipher.nid = NID_undef; + acss_cipher.block_size = 1; + acss_cipher.key_len = 5; + acss_cipher.init = acss_init_key; + acss_cipher.do_cipher = acss_ciph; + acss_cipher.ctx_size = sizeof(EVP_ACSS_KEY); + acss_cipher.ctrl = acss_ctrl; + + return (&acss_cipher); +} +#endif + diff --git a/crypto/openssh-3.9p1/cipher-aes.c b/crypto/openssh-3.9p1/cipher-aes.c new file mode 100644 index 0000000000..22d500d429 --- /dev/null +++ b/crypto/openssh-3.9p1/cipher-aes.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2003 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +#if OPENSSL_VERSION_NUMBER < 0x00907000L +RCSID("$OpenBSD: cipher-aes.c,v 1.2 2003/11/26 21:44:29 djm Exp $"); + +#include +#include "rijndael.h" +#include "xmalloc.h" +#include "log.h" + +#if OPENSSL_VERSION_NUMBER < 0x00906000L +#define SSH_OLD_EVP +#endif + +#define RIJNDAEL_BLOCKSIZE 16 +struct ssh_rijndael_ctx +{ + rijndael_ctx r_ctx; + u_char r_iv[RIJNDAEL_BLOCKSIZE]; +}; + +const EVP_CIPHER * evp_rijndael(void); +void ssh_rijndael_iv(EVP_CIPHER_CTX *, int, u_char *, u_int); + +static int +ssh_rijndael_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, + int enc) +{ + struct ssh_rijndael_ctx *c; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { + c = xmalloc(sizeof(*c)); + EVP_CIPHER_CTX_set_app_data(ctx, c); + } + if (key != NULL) { + if (enc == -1) + enc = ctx->encrypt; + rijndael_set_key(&c->r_ctx, (u_char *)key, + 8*EVP_CIPHER_CTX_key_length(ctx), enc); + } + if (iv != NULL) + memcpy(c->r_iv, iv, RIJNDAEL_BLOCKSIZE); + return (1); +} + +static int +ssh_rijndael_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, + u_int len) +{ + struct ssh_rijndael_ctx *c; + u_char buf[RIJNDAEL_BLOCKSIZE]; + u_char *cprev, *cnow, *plain, *ivp; + int i, j, blocks = len / RIJNDAEL_BLOCKSIZE; + + if (len == 0) + return (1); + if (len % RIJNDAEL_BLOCKSIZE) + fatal("ssh_rijndael_cbc: bad len %d", len); + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { + error("ssh_rijndael_cbc: no context"); + return (0); + } + if (ctx->encrypt) { + cnow = dest; + plain = (u_char *)src; + cprev = c->r_iv; + for (i = 0; i < blocks; i++, plain+=RIJNDAEL_BLOCKSIZE, + cnow+=RIJNDAEL_BLOCKSIZE) { + for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++) + buf[j] = plain[j] ^ cprev[j]; + rijndael_encrypt(&c->r_ctx, buf, cnow); + cprev = cnow; + } + memcpy(c->r_iv, cprev, RIJNDAEL_BLOCKSIZE); + } else { + cnow = (u_char *) (src+len-RIJNDAEL_BLOCKSIZE); + plain = dest+len-RIJNDAEL_BLOCKSIZE; + + memcpy(buf, cnow, RIJNDAEL_BLOCKSIZE); + for (i = blocks; i > 0; i--, cnow-=RIJNDAEL_BLOCKSIZE, + plain-=RIJNDAEL_BLOCKSIZE) { + rijndael_decrypt(&c->r_ctx, cnow, plain); + ivp = (i == 1) ? c->r_iv : cnow-RIJNDAEL_BLOCKSIZE; + for (j = 0; j < RIJNDAEL_BLOCKSIZE; j++) + plain[j] ^= ivp[j]; + } + memcpy(c->r_iv, buf, RIJNDAEL_BLOCKSIZE); + } + return (1); +} + +static int +ssh_rijndael_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct ssh_rijndael_ctx *c; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { + memset(c, 0, sizeof(*c)); + xfree(c); + EVP_CIPHER_CTX_set_app_data(ctx, NULL); + } + return (1); +} + +void +ssh_rijndael_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, u_int len) +{ + struct ssh_rijndael_ctx *c; + + if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL) + fatal("ssh_rijndael_iv: no context"); + if (doset) + memcpy(c->r_iv, iv, len); + else + memcpy(iv, c->r_iv, len); +} + +const EVP_CIPHER * +evp_rijndael(void) +{ + static EVP_CIPHER rijndal_cbc; + + memset(&rijndal_cbc, 0, sizeof(EVP_CIPHER)); + rijndal_cbc.nid = NID_undef; + rijndal_cbc.block_size = RIJNDAEL_BLOCKSIZE; + rijndal_cbc.iv_len = RIJNDAEL_BLOCKSIZE; + rijndal_cbc.key_len = 16; + rijndal_cbc.init = ssh_rijndael_init; + rijndal_cbc.cleanup = ssh_rijndael_cleanup; + rijndal_cbc.do_cipher = ssh_rijndael_cbc; +#ifndef SSH_OLD_EVP + rijndal_cbc.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; +#endif + return (&rijndal_cbc); +} +#endif /* OPENSSL_VERSION_NUMBER */ diff --git a/crypto/openssh-3.9p1/cipher-bf1.c b/crypto/openssh-3.9p1/cipher-bf1.c new file mode 100644 index 0000000000..5af695c174 --- /dev/null +++ b/crypto/openssh-3.9p1/cipher-bf1.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2003 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: cipher-bf1.c,v 1.1 2003/05/15 03:08:29 markus Exp $"); + +#include +#include "xmalloc.h" +#include "log.h" + +#if OPENSSL_VERSION_NUMBER < 0x00906000L +#define SSH_OLD_EVP +#endif + +/* + * SSH1 uses a variation on Blowfish, all bytes must be swapped before + * and after encryption/decryption. Thus the swap_bytes stuff (yuk). + */ + +const EVP_CIPHER * evp_ssh1_bf(void); + +static void +swap_bytes(const u_char *src, u_char *dst, int n) +{ + u_char c[4]; + + /* Process 4 bytes every lap. */ + for (n = n / 4; n > 0; n--) { + c[3] = *src++; + c[2] = *src++; + c[1] = *src++; + c[0] = *src++; + + *dst++ = c[0]; + *dst++ = c[1]; + *dst++ = c[2]; + *dst++ = c[3]; + } +} + +#ifdef SSH_OLD_EVP +static void bf_ssh1_init (EVP_CIPHER_CTX * ctx, const unsigned char *key, + const unsigned char *iv, int enc) +{ + if (iv != NULL) + memcpy (&(ctx->oiv[0]), iv, 8); + memcpy (&(ctx->iv[0]), &(ctx->oiv[0]), 8); + if (key != NULL) + BF_set_key (&(ctx->c.bf_ks), EVP_CIPHER_CTX_key_length (ctx), + key); +} +#endif + +static int (*orig_bf)(EVP_CIPHER_CTX *, u_char *, const u_char *, u_int) = NULL; + +static int +bf_ssh1_cipher(EVP_CIPHER_CTX *ctx, u_char *out, const u_char *in, u_int len) +{ + int ret; + + swap_bytes(in, out, len); + ret = (*orig_bf)(ctx, out, out, len); + swap_bytes(out, out, len); + return (ret); +} + +const EVP_CIPHER * +evp_ssh1_bf(void) +{ + static EVP_CIPHER ssh1_bf; + + memcpy(&ssh1_bf, EVP_bf_cbc(), sizeof(EVP_CIPHER)); + orig_bf = ssh1_bf.do_cipher; + ssh1_bf.nid = NID_undef; +#ifdef SSH_OLD_EVP + ssh1_bf.init = bf_ssh1_init; +#endif + ssh1_bf.do_cipher = bf_ssh1_cipher; + ssh1_bf.key_len = 32; + return (&ssh1_bf); +} diff --git a/crypto/openssh-3.9p1/cipher-ctr.c b/crypto/openssh-3.9p1/cipher-ctr.c new file mode 100644 index 0000000000..395dabedd5 --- /dev/null +++ b/crypto/openssh-3.9p1/cipher-ctr.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2003 Markus Friedl + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "includes.h" +RCSID("$OpenBSD: cipher-ctr.c,v 1.4 2004/02/06 23:41:13 dtucker Exp $"); + +#include + +#include "log.h" +#include "xmalloc.h" + +#if OPENSSL_VERSION_NUMBER < 0x00906000L +#define SSH_OLD_EVP +#endif + +#if OPENSSL_VERSION_NUMBER < 0x00907000L +#include "rijndael.h" +#define AES_KEY rijndael_ctx +#define AES_BLOCK_SIZE 16 +#define AES_encrypt(a, b, c) rijndael_encrypt(c, a, b) +#define AES_set_encrypt_key(a, b, c) rijndael_set_key(c, (char *)a, b, 1) +#else +#include +#endif + +const EVP_CIPHER *evp_aes_128_ctr(void); +void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int); + +struct ssh_aes_ctr_ctx +{ + AES_KEY aes_ctx; + u_char aes_counter[AES_BLOCK_SIZE]; +}; + +/* + * increment counter 'ctr', + * the counter is of size 'len' bytes and stored in network-byte-order. + * (LSB at ctr[len-1], MSB at ctr[0]) + */ +static void +ssh_ctr_inc(u_char *ctr, u_int len) +{ + int i; + + for (i = len - 1; i >= 0; i--) + if (++ctr[i]) /* continue on overflow */ + return; +} + +static int +ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, + u_int len) +{ + struct ssh_aes_ctr_ctx *c; + u_int n = 0; + u_char buf[AES_BLOCK_SIZE]; + + if (len == 0) + return (1); + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) + return (0); + + while ((len--) > 0) { + if (n == 0) { + AES_encrypt(c->aes_counter, buf, &c->aes_ctx); + ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE); + } + *(dest++) = *(src++) ^ buf[n]; + n = (n + 1) % AES_BLOCK_SIZE; + } + return (1); +} + +static int +ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, + int enc) +{ + struct ssh_aes_ctr_ctx *c; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) { + c = xmalloc(sizeof(*c)); + EVP_CIPHER_CTX_set_app_data(ctx, c); + } + if (key != NULL) + AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, + &c->aes_ctx); + if (iv != NULL) + memcpy(c->aes_counter, iv, AES_BLOCK_SIZE); + return (1); +} + +static int +ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) +{ + struct ssh_aes_ctr_ctx *c; + + if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { + memset(c, 0, sizeof(*c)); + xfree(c); + EVP_CIPHER_CTX_set_app_data(ctx, NULL); + } + return (1); +} + +void +ssh_aes_ctr_iv(EVP_CIPHER_CTX *evp, int doset, u_char * iv, u_int len) +{ + struct ssh_aes_ctr_ctx *c; + + if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL) + fatal("ssh_aes_ctr_iv: no context"); + if (doset) + memcpy(c->aes_counter, iv, len); + else + memcpy(iv, c->aes_counter, len); +} + +const EVP_CIPHER * +evp_aes_128_ctr(void) +{ + static EVP_CIPHER aes_ctr; + + memset(&aes_ctr, 0, sizeof(EVP_CIPHER)); + aes_ctr.nid = NID_undef; + aes_ctr.block_size = AES_BLOCK_SIZE; + aes_ctr.iv_len = AES_BLOCK_SIZE; + aes_ctr.key_len = 16; + aes_ctr.init = ssh_aes_ctr_init; + aes_ctr.cleanup = ssh_aes_ctr_cleanup; + aes_ctr.do_cipher = ssh_aes_ctr; +#ifndef SSH_OLD_EVP + aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV; +#endif + return (&aes_ctr); +} diff --git a/crypto/openssh-3.9p1/cipher.c b/crypto/openssh-3.9p1/cipher.c new file mode 100644 index 0000000000..075a4c5fce --- /dev/null +++ b/crypto/openssh-3.9p1/cipher.c @@ -0,0 +1,437 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + * + * + * Copyright (c) 1999 Niels Provos. All rights reserved. + * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: cipher.c,v 1.71 2004/07/28 09:40:29 markus Exp $"); + +#include "xmalloc.h" +#include "log.h" +#include "cipher.h" + +#include + +#if OPENSSL_VERSION_NUMBER < 0x00906000L +#define SSH_OLD_EVP +#define EVP_CIPHER_CTX_get_app_data(e) ((e)->app_data) +#endif + +#if OPENSSL_VERSION_NUMBER < 0x00907000L +extern const EVP_CIPHER *evp_rijndael(void); +extern void ssh_rijndael_iv(EVP_CIPHER_CTX *, int, u_char *, u_int); +#endif + +#if !defined(EVP_CTRL_SET_ACSS_MODE) +# if (OPENSSL_VERSION_NUMBER >= 0x00907000L) +extern const EVP_CIPHER *evp_acss(void); +# define EVP_acss evp_acss +# define EVP_CTRL_SET_ACSS_MODE xxx /* used below */ +# else +# define EVP_acss NULL /* Don't try to support ACSS on older OpenSSL */ +# endif /* (OPENSSL_VERSION_NUMBER >= 0x00906000L) */ +#endif /* !defined(EVP_CTRL_SET_ACSS_MODE) */ + +extern const EVP_CIPHER *evp_ssh1_bf(void); +extern const EVP_CIPHER *evp_ssh1_3des(void); +extern void ssh1_3des_iv(EVP_CIPHER_CTX *, int, u_char *, int); +extern const EVP_CIPHER *evp_aes_128_ctr(void); +extern void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, int, u_char *, u_int); + +struct Cipher { + char *name; + int number; /* for ssh1 only */ + u_int block_size; + u_int key_len; + const EVP_CIPHER *(*evptype)(void); +} ciphers[] = { + { "none", SSH_CIPHER_NONE, 8, 0, EVP_enc_null }, + { "des", SSH_CIPHER_DES, 8, 8, EVP_des_cbc }, + { "3des", SSH_CIPHER_3DES, 8, 16, evp_ssh1_3des }, + { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, evp_ssh1_bf }, + + { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, EVP_des_ede3_cbc }, + { "blowfish-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_bf_cbc }, + { "cast128-cbc", SSH_CIPHER_SSH2, 8, 16, EVP_cast5_cbc }, + { "arcfour", SSH_CIPHER_SSH2, 8, 16, EVP_rc4 }, +#if OPENSSL_VERSION_NUMBER < 0x00907000L + { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, evp_rijndael }, + { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, evp_rijndael }, + { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, evp_rijndael }, + { "rijndael-cbc@lysator.liu.se", + SSH_CIPHER_SSH2, 16, 32, evp_rijndael }, +#else + { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, EVP_aes_128_cbc }, + { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, EVP_aes_192_cbc }, + { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, EVP_aes_256_cbc }, + { "rijndael-cbc@lysator.liu.se", + SSH_CIPHER_SSH2, 16, 32, EVP_aes_256_cbc }, +#endif +#if OPENSSL_VERSION_NUMBER >= 0x00905000L + { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, evp_aes_128_ctr }, + { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, evp_aes_128_ctr }, + { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, evp_aes_128_ctr }, +#endif +#if defined(EVP_CTRL_SET_ACSS_MODE) + { "acss@openssh.org", SSH_CIPHER_SSH2, 16, 5, EVP_acss }, +#endif + { NULL, SSH_CIPHER_INVALID, 0, 0, NULL } +}; + +/*--*/ + +u_int +cipher_blocksize(const Cipher *c) +{ + return (c->block_size); +} + +u_int +cipher_keylen(const Cipher *c) +{ + return (c->key_len); +} + +u_int +cipher_get_number(const Cipher *c) +{ + return (c->number); +} + +u_int +cipher_mask_ssh1(int client) +{ + u_int mask = 0; + mask |= 1 << SSH_CIPHER_3DES; /* Mandatory */ + mask |= 1 << SSH_CIPHER_BLOWFISH; + if (client) { + mask |= 1 << SSH_CIPHER_DES; + } + return mask; +} + +Cipher * +cipher_by_name(const char *name) +{ + Cipher *c; + for (c = ciphers; c->name != NULL; c++) + if (strcasecmp(c->name, name) == 0) + return c; + return NULL; +} + +Cipher * +cipher_by_number(int id) +{ + Cipher *c; + for (c = ciphers; c->name != NULL; c++) + if (c->number == id) + return c; + return NULL; +} + +#define CIPHER_SEP "," +int +ciphers_valid(const char *names) +{ + Cipher *c; + char *cipher_list, *cp; + char *p; + + if (names == NULL || strcmp(names, "") == 0) + return 0; + cipher_list = cp = xstrdup(names); + for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; + (p = strsep(&cp, CIPHER_SEP))) { + c = cipher_by_name(p); + if (c == NULL || c->number != SSH_CIPHER_SSH2) { + debug("bad cipher %s [%s]", p, names); + xfree(cipher_list); + return 0; + } else { + debug3("cipher ok: %s [%s]", p, names); + } + } + debug3("ciphers ok: [%s]", names); + xfree(cipher_list); + return 1; +} + +/* + * Parses the name of the cipher. Returns the number of the corresponding + * cipher, or -1 on error. + */ + +int +cipher_number(const char *name) +{ + Cipher *c; + if (name == NULL) + return -1; + c = cipher_by_name(name); + return (c==NULL) ? -1 : c->number; +} + +char * +cipher_name(int id) +{ + Cipher *c = cipher_by_number(id); + return (c==NULL) ? "" : c->name; +} + +void +cipher_init(CipherContext *cc, Cipher *cipher, + const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, + int do_encrypt) +{ + static int dowarn = 1; +#ifdef SSH_OLD_EVP + EVP_CIPHER *type; +#else + const EVP_CIPHER *type; +#endif + int klen; + + if (cipher->number == SSH_CIPHER_DES) { + if (dowarn) { + error("Warning: use of DES is strongly discouraged " + "due to cryptographic weaknesses"); + dowarn = 0; + } + if (keylen > 8) + keylen = 8; + } + cc->plaintext = (cipher->number == SSH_CIPHER_NONE); + + if (keylen < cipher->key_len) + fatal("cipher_init: key length %d is insufficient for %s.", + keylen, cipher->name); + if (iv != NULL && ivlen < cipher->block_size) + fatal("cipher_init: iv length %d is insufficient for %s.", + ivlen, cipher->name); + cc->cipher = cipher; + + type = (*cipher->evptype)(); + + EVP_CIPHER_CTX_init(&cc->evp); +#ifdef SSH_OLD_EVP + if (type->key_len > 0 && type->key_len != keylen) { + debug("cipher_init: set keylen (%d -> %d)", + type->key_len, keylen); + type->key_len = keylen; + } + EVP_CipherInit(&cc->evp, type, (u_char *)key, (u_char *)iv, + (do_encrypt == CIPHER_ENCRYPT)); +#else + if (EVP_CipherInit(&cc->evp, type, NULL, (u_char *)iv, + (do_encrypt == CIPHER_ENCRYPT)) == 0) + fatal("cipher_init: EVP_CipherInit failed for %s", + cipher->name); + klen = EVP_CIPHER_CTX_key_length(&cc->evp); + if (klen > 0 && keylen != klen) { + debug2("cipher_init: set keylen (%d -> %d)", klen, keylen); + if (EVP_CIPHER_CTX_set_key_length(&cc->evp, keylen) == 0) + fatal("cipher_init: set keylen failed (%d -> %d)", + klen, keylen); + } + if (EVP_CipherInit(&cc->evp, NULL, (u_char *)key, NULL, -1) == 0) + fatal("cipher_init: EVP_CipherInit: set key failed for %s", + cipher->name); +#endif +} + +void +cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) +{ + if (len % cc->cipher->block_size) + fatal("cipher_encrypt: bad plaintext length %d", len); +#ifdef SSH_OLD_EVP + EVP_Cipher(&cc->evp, dest, (u_char *)src, len); +#else + if (EVP_Cipher(&cc->evp, dest, (u_char *)src, len) == 0) + fatal("evp_crypt: EVP_Cipher failed"); +#endif +} + +void +cipher_cleanup(CipherContext *cc) +{ +#ifdef SSH_OLD_EVP + EVP_CIPHER_CTX_cleanup(&cc->evp); +#else + if (EVP_CIPHER_CTX_cleanup(&cc->evp) == 0) + error("cipher_cleanup: EVP_CIPHER_CTX_cleanup failed"); +#endif +} + +/* + * 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 *cc, Cipher *cipher, + const char *passphrase, int do_encrypt) +{ + MD5_CTX md; + u_char digest[16]; + + MD5_Init(&md); + MD5_Update(&md, (const u_char *)passphrase, strlen(passphrase)); + MD5_Final(digest, &md); + + cipher_init(cc, cipher, digest, 16, NULL, 0, do_encrypt); + + memset(digest, 0, sizeof(digest)); + memset(&md, 0, sizeof(md)); +} + +/* + * Exports an IV from the CipherContext required to export the key + * state back from the unprivileged child to the privileged parent + * process. + */ + +int +cipher_get_keyiv_len(const CipherContext *cc) +{ + Cipher *c = cc->cipher; + int ivlen; + + if (c->number == SSH_CIPHER_3DES) + ivlen = 24; + else + ivlen = EVP_CIPHER_CTX_iv_length(&cc->evp); + return (ivlen); +} + +void +cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len) +{ + Cipher *c = cc->cipher; + int evplen; + + switch (c->number) { + case SSH_CIPHER_SSH2: + case SSH_CIPHER_DES: + case SSH_CIPHER_BLOWFISH: + evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); + if (evplen == 0) + return; + if (evplen != len) + fatal("%s: wrong iv length %d != %d", __func__, + evplen, len); +#if OPENSSL_VERSION_NUMBER < 0x00907000L + if (c->evptype == evp_rijndael) + ssh_rijndael_iv(&cc->evp, 0, iv, len); + else +#endif + if (c->evptype == evp_aes_128_ctr) + ssh_aes_ctr_iv(&cc->evp, 0, iv, len); + else + memcpy(iv, cc->evp.iv, len); + break; + case SSH_CIPHER_3DES: + ssh1_3des_iv(&cc->evp, 0, iv, 24); + break; + default: + fatal("%s: bad cipher %d", __func__, c->number); + } +} + +void +cipher_set_keyiv(CipherContext *cc, u_char *iv) +{ + Cipher *c = cc->cipher; + int evplen = 0; + + switch (c->number) { + case SSH_CIPHER_SSH2: + case SSH_CIPHER_DES: + case SSH_CIPHER_BLOWFISH: + evplen = EVP_CIPHER_CTX_iv_length(&cc->evp); + if (evplen == 0) + return; +#if OPENSSL_VERSION_NUMBER < 0x00907000L + if (c->evptype == evp_rijndael) + ssh_rijndael_iv(&cc->evp, 1, iv, evplen); + else +#endif + if (c->evptype == evp_aes_128_ctr) + ssh_aes_ctr_iv(&cc->evp, 1, iv, evplen); + else + memcpy(cc->evp.iv, iv, evplen); + break; + case SSH_CIPHER_3DES: + ssh1_3des_iv(&cc->evp, 1, iv, 24); + break; + default: + fatal("%s: bad cipher %d", __func__, c->number); + } +} + +#if OPENSSL_VERSION_NUMBER < 0x00907000L +#define EVP_X_STATE(evp) &(evp).c +#define EVP_X_STATE_LEN(evp) sizeof((evp).c) +#else +#define EVP_X_STATE(evp) (evp).cipher_data +#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size +#endif + +int +cipher_get_keycontext(const CipherContext *cc, u_char *dat) +{ + Cipher *c = cc->cipher; + int plen = 0; + + if (c->evptype == EVP_rc4 || c->evptype == EVP_acss) { + plen = EVP_X_STATE_LEN(cc->evp); + if (dat == NULL) + return (plen); + memcpy(dat, EVP_X_STATE(cc->evp), plen); + } + return (plen); +} + +void +cipher_set_keycontext(CipherContext *cc, u_char *dat) +{ + Cipher *c = cc->cipher; + int plen; + + if (c->evptype == EVP_rc4 || c->evptype == EVP_acss) { + plen = EVP_X_STATE_LEN(cc->evp); + memcpy(EVP_X_STATE(cc->evp), dat, plen); + } +} diff --git a/crypto/openssh-3.9p1/cipher.h b/crypto/openssh-3.9p1/cipher.h new file mode 100644 index 0000000000..6bb5719b0b --- /dev/null +++ b/crypto/openssh-3.9p1/cipher.h @@ -0,0 +1,91 @@ +/* $OpenBSD: cipher.h,v 1.35 2004/07/28 09:40:29 markus Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + * + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CIPHER_H +#define CIPHER_H + +#include +/* + * Cipher types for SSH-1. New types can be added, but old types should not + * be removed for compatibility. The maximum allowed value is 31. + */ +#define SSH_CIPHER_SSH2 -3 +#define SSH_CIPHER_INVALID -2 /* No valid cipher selected. */ +#define SSH_CIPHER_NOT_SET -1 /* None selected (invalid number). */ +#define SSH_CIPHER_NONE 0 /* no encryption */ +#define SSH_CIPHER_IDEA 1 /* IDEA CFB */ +#define SSH_CIPHER_DES 2 /* DES CBC */ +#define SSH_CIPHER_3DES 3 /* 3DES CBC */ +#define SSH_CIPHER_BROKEN_TSS 4 /* TRI's Simple Stream encryption CBC */ +#define SSH_CIPHER_BROKEN_RC4 5 /* Alleged RC4 */ +#define SSH_CIPHER_BLOWFISH 6 +#define SSH_CIPHER_RESERVED 7 +#define SSH_CIPHER_MAX 31 + +#define CIPHER_ENCRYPT 1 +#define CIPHER_DECRYPT 0 + +typedef struct Cipher Cipher; +typedef struct CipherContext CipherContext; + +struct Cipher; +struct CipherContext { + int plaintext; + EVP_CIPHER_CTX evp; + Cipher *cipher; +}; + +u_int cipher_mask_ssh1(int); +Cipher *cipher_by_name(const char *); +Cipher *cipher_by_number(int); +int cipher_number(const char *); +char *cipher_name(int); +int ciphers_valid(const char *); +void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, + const u_char *, u_int, int); +void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int); +void cipher_cleanup(CipherContext *); +void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); +u_int cipher_blocksize(const Cipher *); +u_int cipher_keylen(const Cipher *); + +u_int cipher_get_number(const Cipher *); +void cipher_get_keyiv(CipherContext *, u_char *, u_int); +void cipher_set_keyiv(CipherContext *, u_char *); +int cipher_get_keyiv_len(const CipherContext *); +int cipher_get_keycontext(const CipherContext *, u_char *); +void cipher_set_keycontext(CipherContext *, u_char *); +#endif /* CIPHER_H */ diff --git a/crypto/openssh-3.9p1/cleanup.c b/crypto/openssh-3.9p1/cleanup.c new file mode 100644 index 0000000000..11d1d4d9ae --- /dev/null +++ b/crypto/openssh-3.9p1/cleanup.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2003 Markus Friedl + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "includes.h" +RCSID("$OpenBSD: cleanup.c,v 1.1 2003/09/23 20:17:11 markus Exp $"); + +#include "log.h" + +/* default implementation */ +void +cleanup_exit(int i) +{ + _exit(i); +} diff --git a/crypto/openssh-3.9p1/clientloop.c b/crypto/openssh-3.9p1/clientloop.c new file mode 100644 index 0000000000..0b9a0fb29c --- /dev/null +++ b/crypto/openssh-3.9p1/clientloop.c @@ -0,0 +1,1836 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * The main loop for the interactive session (client side). + * + * 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". + * + * + * Copyright (c) 1999 Theo de Raadt. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * SSH2 support added by Markus Friedl. + * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: clientloop.c,v 1.130 2004/08/11 21:43:04 avsm Exp $"); + +#include "ssh.h" +#include "ssh1.h" +#include "ssh2.h" +#include "xmalloc.h" +#include "packet.h" +#include "buffer.h" +#include "compat.h" +#include "channels.h" +#include "dispatch.h" +#include "buffer.h" +#include "bufaux.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "readconf.h" +#include "clientloop.h" +#include "authfd.h" +#include "atomicio.h" +#include "sshpty.h" +#include "misc.h" +#include "monitor_fdpass.h" +#include "match.h" +#include "msg.h" + +/* import options */ +extern Options options; + +/* Flag indicating that stdin should be redirected from /dev/null. */ +extern int stdin_null_flag; + +/* Flag indicating that no shell has been requested */ +extern int no_shell_flag; + +/* Control socket */ +extern int control_fd; + +/* + * Name of the host we are connecting to. This is the name given on the + * command line, or the HostName specified for the user-supplied name in a + * configuration file. + */ +extern char *host; + +/* + * Flag to indicate that we have received a window change signal which has + * not yet been processed. This will cause a message indicating the new + * window size to be sent to the server a little later. This is volatile + * because this is updated in a signal handler. + */ +static volatile sig_atomic_t received_window_change_signal = 0; +static volatile sig_atomic_t received_signal = 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 quit_pending; /* Set to non-zero to quit the client loop. */ +static int escape_char; /* Escape character. */ +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 u_long stdin_bytes, stdout_bytes, stderr_bytes; +static u_int buffer_high;/* Soft max buffer size. */ +static int connection_in; /* Connection to server (input). */ +static int connection_out; /* Connection to server (output). */ +static int need_rekeying; /* Set to non-zero if rekeying is requested. */ +static int session_closed = 0; /* In SSH2: login session closed. */ +static int server_alive_timeouts = 0; + +static void client_init_dispatch(void); +int session_ident = -1; + +struct confirm_ctx { + int want_tty; + int want_subsys; + Buffer cmd; + char *term; + struct termios tio; + char **env; +}; + +/*XXX*/ +extern Kex *xxx_kex; + +void ssh_process_session2_setup(int, int, int, Buffer *); + +/* Restores stdin to blocking mode. */ + +static void +leave_non_blocking(void) +{ + if (in_non_blocking_mode) { + unset_nonblock(fileno(stdin)); + in_non_blocking_mode = 0; + } +} + +/* Puts stdin terminal in non-blocking mode. */ + +static void +enter_non_blocking(void) +{ + in_non_blocking_mode = 1; + set_nonblock(fileno(stdin)); +} + +/* + * Signal handler for the window change signal (SIGWINCH). This just sets a + * flag indicating that the window has changed. + */ + +static void +window_change_handler(int sig) +{ + received_window_change_signal = 1; + signal(SIGWINCH, window_change_handler); +} + +/* + * Signal handler for signals that cause the program to terminate. These + * signals must be trapped to restore terminal modes. + */ + +static void +signal_handler(int sig) +{ + received_signal = sig; + quit_pending = 1; +} + +/* + * Returns current time in seconds from Jan 1, 1970 with the maximum + * available resolution. + */ + +static double +get_current_time(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0; +} + +/* + * This is called when the interactive is entered. This checks if there is + * an EOF coming on stdin. We must check this explicitly, as select() does + * not appear to wake up when redirecting from /dev/null. + */ + +static void +client_check_initial_eof_on_stdin(void) +{ + int len; + char buf[1]; + + /* + * If standard input is to be "redirected from /dev/null", we simply + * mark that we have seen an EOF and send an EOF message to the + * server. Otherwise, we try to read a single character; it appears + * that for some files, such /dev/null, select() never wakes up for + * read for this descriptor, which means that we never get EOF. This + * way we will get the EOF if stdin comes from /dev/null or similar. + */ + if (stdin_null_flag) { + /* Fake EOF on stdin. */ + debug("Sending eof."); + stdin_eof = 1; + packet_start(SSH_CMSG_EOF); + packet_send(); + } else { + enter_non_blocking(); + + /* Check for immediate EOF on stdin. */ + len = read(fileno(stdin), buf, 1); + if (len == 0) { + /* EOF. Record that we have seen it and send EOF to server. */ + debug("Sending eof."); + stdin_eof = 1; + packet_start(SSH_CMSG_EOF); + packet_send(); + } else if (len > 0) { + /* + * Got data. We must store the data in the buffer, + * and also process it as an escape character if + * appropriate. + */ + if ((u_char) buf[0] == escape_char) + escape_pending = 1; + else + buffer_append(&stdin_buffer, buf, 1); + } + leave_non_blocking(); + } +} + + +/* + * Make packets from buffered stdin data, and buffer them for sending to the + * connection. + */ + +static void +client_make_packets_from_stdin_data(void) +{ + u_int len; + + /* Send buffered stdin data to the server. */ + while (buffer_len(&stdin_buffer) > 0 && + packet_not_very_much_data_to_write()) { + len = buffer_len(&stdin_buffer); + /* Keep the packets at reasonable size. */ + if (len > packet_get_maxsize()) + len = packet_get_maxsize(); + packet_start(SSH_CMSG_STDIN_DATA); + packet_put_string(buffer_ptr(&stdin_buffer), len); + packet_send(); + buffer_consume(&stdin_buffer, len); + stdin_bytes += 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. + */ + +static void +client_check_window_change(void) +{ + struct winsize ws; + + if (! received_window_change_signal) + return; + /** XXX race */ + received_window_change_signal = 0; + + debug2("client_check_window_change: changed"); + + if (compat20) { + channel_send_window_changes(); + } else { + if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) + return; + 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(); + } +} + +static void +client_global_request_reply(int type, u_int32_t seq, void *ctxt) +{ + server_alive_timeouts = 0; + client_global_request_reply_fwd(type, seq, ctxt); +} + +static void +server_alive_check(void) +{ + if (++server_alive_timeouts > options.server_alive_count_max) + packet_disconnect("Timeout, server not responding."); + packet_start(SSH2_MSG_GLOBAL_REQUEST); + packet_put_cstring("keepalive@openssh.com"); + packet_put_char(1); /* boolean: want reply */ + packet_send(); +} + +/* + * Waits until the client can do something (some data becomes available on + * one of the file descriptors). + */ +static void +client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, + int *maxfdp, u_int *nallocp, int rekeying) +{ + struct timeval tv, *tvp; + int ret; + + /* Add any selections by the channel mechanism. */ + channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, rekeying); + + if (!compat20) { + /* 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, *readsetp); + /* + * 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), *readsetp); + + /* Select stdout/stderr if have data in buffer. */ + if (buffer_len(&stdout_buffer) > 0) + FD_SET(fileno(stdout), *writesetp); + if (buffer_len(&stderr_buffer) > 0) + FD_SET(fileno(stderr), *writesetp); + } else { + /* channel_prepare_select could have closed the last channel */ + if (session_closed && !channel_still_open() && + !packet_have_data_to_write()) { + /* clear mask since we did not call select() */ + memset(*readsetp, 0, *nallocp); + memset(*writesetp, 0, *nallocp); + return; + } else { + FD_SET(connection_in, *readsetp); + } + } + + /* Select server connection if have data to write to the server. */ + if (packet_have_data_to_write()) + FD_SET(connection_out, *writesetp); + + if (control_fd != -1) + FD_SET(control_fd, *readsetp); + + /* + * Wait for something to happen. This will suspend the process until + * some selected descriptor can be read, written, or has some other + * event pending. + */ + + if (options.server_alive_interval == 0 || !compat20) + tvp = NULL; + else { + tv.tv_sec = options.server_alive_interval; + tv.tv_usec = 0; + tvp = &tv; + } + ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); + if (ret < 0) { + char buf[100]; + + /* + * We have to clear the select masks, because we return. + * We have to return, because the mainloop checks for the flags + * set by the signal handlers. + */ + memset(*readsetp, 0, *nallocp); + memset(*writesetp, 0, *nallocp); + + if (errno == EINTR) + return; + /* Note: we might still have data in the buffers. */ + snprintf(buf, sizeof buf, "select: %s\r\n", strerror(errno)); + buffer_append(&stderr_buffer, buf, strlen(buf)); + quit_pending = 1; + } else if (ret == 0) + server_alive_check(); +} + +static void +client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) +{ + struct winsize oldws, newws; + + /* Flush stdout and stderr buffers. */ + if (buffer_len(bout) > 0) + atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout)); + if (buffer_len(berr) > 0) + atomicio(vwrite, fileno(stderr), buffer_ptr(berr), buffer_len(berr)); + + leave_raw_mode(); + + /* + * Free (and clear) the buffer to reduce the amount of data that gets + * written to swap. + */ + buffer_free(bin); + buffer_free(bout); + buffer_free(berr); + + /* Save old window size. */ + ioctl(fileno(stdin), TIOCGWINSZ, &oldws); + + /* Send the suspend signal to the program itself. */ + kill(getpid(), SIGTSTP); + + /* Check if the window size has changed. */ + if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 && + (oldws.ws_row != newws.ws_row || + oldws.ws_col != newws.ws_col || + oldws.ws_xpixel != newws.ws_xpixel || + oldws.ws_ypixel != newws.ws_ypixel)) + received_window_change_signal = 1; + + /* OK, we have been continued by the user. Reinitialize buffers. */ + buffer_init(bin); + buffer_init(bout); + buffer_init(berr); + + enter_raw_mode(); +} + +static void +client_process_net_input(fd_set * readset) +{ + int len; + char buf[8192]; + + /* + * Read input from the server, and add any such data to the buffer of + * the packet subsystem. + */ + if (FD_ISSET(connection_in, readset)) { + /* Read as much as possible. */ + len = read(connection_in, buf, sizeof(buf)); + if (len == 0) { + /* Received EOF. The remote host has closed the connection. */ + snprintf(buf, sizeof buf, "Connection to %.300s closed by remote host.\r\n", + host); + buffer_append(&stderr_buffer, buf, strlen(buf)); + 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 || errno == EINTR)) + len = 0; + + if (len < 0) { + /* An error has encountered. Perhaps there is a network problem. */ + snprintf(buf, sizeof buf, "Read from remote host %.300s: %.100s\r\n", + host, strerror(errno)); + buffer_append(&stderr_buffer, buf, strlen(buf)); + quit_pending = 1; + return; + } + packet_process_incoming(buf, len); + } +} + +static void +client_subsystem_reply(int type, u_int32_t seq, void *ctxt) +{ + int id; + Channel *c; + + id = packet_get_int(); + packet_check_eom(); + + if ((c = channel_lookup(id)) == NULL) { + error("%s: no channel for id %d", __func__, id); + return; + } + + if (type == SSH2_MSG_CHANNEL_SUCCESS) + debug2("Request suceeded on channel %d", id); + else if (type == SSH2_MSG_CHANNEL_FAILURE) { + error("Request failed on channel %d", id); + channel_free(c); + } +} + +static void +client_extra_session2_setup(int id, void *arg) +{ + struct confirm_ctx *cctx = arg; + Channel *c; + int i; + + if (cctx == NULL) + fatal("%s: cctx == NULL", __func__); + if ((c = channel_lookup(id)) == NULL) + fatal("%s: no channel for id %d", __func__, id); + + client_session2_setup(id, cctx->want_tty, cctx->want_subsys, + cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, + client_subsystem_reply); + + c->confirm_ctx = NULL; + buffer_free(&cctx->cmd); + xfree(cctx->term); + if (cctx->env != NULL) { + for (i = 0; cctx->env[i] != NULL; i++) + xfree(cctx->env[i]); + xfree(cctx->env); + } + xfree(cctx); +} + +static void +client_process_control(fd_set * readset) +{ + Buffer m; + Channel *c; + int client_fd, new_fd[3], ver, i, allowed; + socklen_t addrlen; + struct sockaddr_storage addr; + struct confirm_ctx *cctx; + char *cmd; + u_int len, env_len; + uid_t euid; + gid_t egid; + + /* + * Accept connection on control socket + */ + if (control_fd == -1 || !FD_ISSET(control_fd, readset)) + return; + + memset(&addr, 0, sizeof(addr)); + addrlen = sizeof(addr); + if ((client_fd = accept(control_fd, + (struct sockaddr*)&addr, &addrlen)) == -1) { + error("%s accept: %s", __func__, strerror(errno)); + return; + } + + if (getpeereid(client_fd, &euid, &egid) < 0) { + error("%s getpeereid failed: %s", __func__, strerror(errno)); + close(client_fd); + return; + } + if ((euid != 0) && (getuid() != euid)) { + error("control mode uid mismatch: peer euid %u != uid %u", + (u_int) euid, (u_int) getuid()); + close(client_fd); + return; + } + + allowed = 1; + if (options.control_master == 2) { + char *p, prompt[1024]; + + allowed = 0; + snprintf(prompt, sizeof(prompt), + "Allow shared connection to %s? ", host); + p = read_passphrase(prompt, RP_USE_ASKPASS|RP_ALLOW_EOF); + if (p != NULL) { + /* + * Accept empty responses and responses consisting + * of the word "yes" as affirmative. + */ + if (*p == '\0' || *p == '\n' || + strcasecmp(p, "yes") == 0) + allowed = 1; + xfree(p); + } + } + + unset_nonblock(client_fd); + + buffer_init(&m); + + buffer_put_int(&m, allowed); + buffer_put_int(&m, getpid()); + if (ssh_msg_send(client_fd, /* version */0, &m) == -1) { + error("%s: client msg_send failed", __func__); + close(client_fd); + buffer_free(&m); + return; + } + buffer_clear(&m); + + if (!allowed) { + error("Refused control connection"); + close(client_fd); + buffer_free(&m); + return; + } + + if (ssh_msg_recv(client_fd, &m) == -1) { + error("%s: client msg_recv failed", __func__); + close(client_fd); + buffer_free(&m); + return; + } + + if ((ver = buffer_get_char(&m)) != 0) { + error("%s: wrong client version %d", __func__, ver); + buffer_free(&m); + close(client_fd); + return; + } + + cctx = xmalloc(sizeof(*cctx)); + memset(cctx, 0, sizeof(*cctx)); + + cctx->want_tty = buffer_get_int(&m); + cctx->want_subsys = buffer_get_int(&m); + cctx->term = buffer_get_string(&m, &len); + + cmd = buffer_get_string(&m, &len); + buffer_init(&cctx->cmd); + buffer_append(&cctx->cmd, cmd, strlen(cmd)); + + env_len = buffer_get_int(&m); + env_len = MIN(env_len, 4096); + debug3("%s: receiving %d env vars", __func__, env_len); + if (env_len != 0) { + cctx->env = xmalloc(sizeof(*cctx->env) * (env_len + 1)); + for (i = 0; i < env_len; i++) + cctx->env[i] = buffer_get_string(&m, &len); + cctx->env[i] = NULL; + } + + debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__, + cctx->want_tty, cctx->want_subsys, cmd); + + /* Gather fds from client */ + new_fd[0] = mm_receive_fd(client_fd); + new_fd[1] = mm_receive_fd(client_fd); + new_fd[2] = mm_receive_fd(client_fd); + + debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__, + new_fd[0], new_fd[1], new_fd[2]); + + /* Try to pick up ttymodes from client before it goes raw */ + if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) + error("%s: tcgetattr: %s", __func__, strerror(errno)); + + buffer_clear(&m); + if (ssh_msg_send(client_fd, /* version */0, &m) == -1) { + error("%s: client msg_send failed", __func__); + close(client_fd); + close(new_fd[0]); + close(new_fd[1]); + close(new_fd[2]); + buffer_free(&m); + return; + } + buffer_free(&m); + + /* enable nonblocking unless tty */ + if (!isatty(new_fd[0])) + set_nonblock(new_fd[0]); + if (!isatty(new_fd[1])) + set_nonblock(new_fd[1]); + if (!isatty(new_fd[2])) + set_nonblock(new_fd[2]); + + set_nonblock(client_fd); + + c = channel_new("session", SSH_CHANNEL_OPENING, + new_fd[0], new_fd[1], new_fd[2], + CHAN_SES_WINDOW_DEFAULT, CHAN_SES_PACKET_DEFAULT, + CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); + + /* XXX */ + c->ctl_fd = client_fd; + + debug3("%s: channel_new: %d", __func__, c->self); + + channel_send_open(c->self); + channel_register_confirm(c->self, client_extra_session2_setup, cctx); +} + +static void +process_cmdline(void) +{ + void (*handler)(int); + char *s, *cmd; + u_short fwd_port, fwd_host_port; + char buf[1024], sfwd_port[6], sfwd_host_port[6]; + int delete = 0; + int local = 0; + + leave_raw_mode(); + handler = signal(SIGINT, SIG_IGN); + cmd = s = read_passphrase("\r\nssh> ", RP_ECHO); + if (s == NULL) + goto out; + while (*s && isspace(*s)) + s++; + if (*s == '-') + s++; /* Skip cmdline '-', if any */ + if (*s == '\0') + goto out; + + if (*s == 'h' || *s == 'H' || *s == '?') { + logit("Commands:"); + logit(" -Lport:host:hostport Request local forward"); + logit(" -Rport:host:hostport Request remote forward"); + logit(" -KRhostport Cancel remote forward"); + goto out; + } + + if (*s == 'K') { + delete = 1; + s++; + } + if (*s != 'L' && *s != 'R') { + logit("Invalid command."); + goto out; + } + if (*s == 'L') + local = 1; + if (local && delete) { + logit("Not supported."); + goto out; + } + if ((!local || delete) && !compat20) { + logit("Not supported for SSH protocol version 1."); + goto out; + } + + s++; + while (*s && isspace(*s)) + s++; + + if (delete) { + if (sscanf(s, "%5[0-9]", sfwd_host_port) != 1) { + logit("Bad forwarding specification."); + goto out; + } + if ((fwd_host_port = a2port(sfwd_host_port)) == 0) { + logit("Bad forwarding port(s)."); + goto out; + } + channel_request_rforward_cancel(fwd_host_port); + } else { + if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]", + sfwd_port, buf, sfwd_host_port) != 3 && + sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]", + sfwd_port, buf, sfwd_host_port) != 3) { + logit("Bad forwarding specification."); + goto out; + } + if ((fwd_port = a2port(sfwd_port)) == 0 || + (fwd_host_port = a2port(sfwd_host_port)) == 0) { + logit("Bad forwarding port(s)."); + goto out; + } + if (local) { + if (channel_setup_local_fwd_listener(fwd_port, buf, + fwd_host_port, options.gateway_ports) < 0) { + logit("Port forwarding failed."); + goto out; + } + } else + channel_request_remote_forwarding(fwd_port, buf, + fwd_host_port); + logit("Forwarding port."); + } + +out: + signal(SIGINT, handler); + enter_raw_mode(); + if (cmd) + xfree(cmd); +} + +/* process the characters one by one */ +static int +process_escapes(Buffer *bin, Buffer *bout, Buffer *berr, char *buf, int len) +{ + char string[1024]; + pid_t pid; + int bytes = 0; + u_int i; + u_char ch; + char *s; + + for (i = 0; i < len; i++) { + /* Get one character at a time. */ + ch = buf[i]; + + if (escape_pending) { + /* We have previously seen an escape character. */ + /* Clear the flag now. */ + escape_pending = 0; + + /* Process the escaped character. */ + switch (ch) { + case '.': + /* Terminate the connection. */ + snprintf(string, sizeof string, "%c.\r\n", escape_char); + buffer_append(berr, string, strlen(string)); + + quit_pending = 1; + return -1; + + case 'Z' - 64: + /* Suspend the program. */ + /* Print a message to that effect to the user. */ + snprintf(string, sizeof string, "%c^Z [suspend ssh]\r\n", escape_char); + buffer_append(berr, string, strlen(string)); + + /* Restore terminal modes and suspend. */ + client_suspend_self(bin, bout, berr); + + /* We have been continued. */ + continue; + + case 'B': + if (compat20) { + snprintf(string, sizeof string, + "%cB\r\n", escape_char); + buffer_append(berr, string, + strlen(string)); + channel_request_start(session_ident, + "break", 0); + packet_put_int(1000); + packet_send(); + } + continue; + + case 'R': + if (compat20) { + if (datafellows & SSH_BUG_NOREKEY) + logit("Server does not support re-keying"); + else + need_rekeying = 1; + } + continue; + + case '&': + /* + * Detach the program (continue to serve connections, + * but put in background and no more new connections). + */ + /* Restore tty modes. */ + leave_raw_mode(); + + /* Stop listening for new connections. */ + channel_stop_listening(); + + snprintf(string, sizeof string, + "%c& [backgrounded]\n", escape_char); + buffer_append(berr, string, strlen(string)); + + /* 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. */ + if (compat20) { + buffer_append(bin, "\004", 1); + /* fake EOF on stdin */ + return -1; + } else 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(bin) == 0) { + packet_start(SSH_CMSG_EOF); + packet_send(); + } + } + continue; + + case '?': + snprintf(string, sizeof string, +"%c?\r\n\ +Supported escape sequences:\r\n\ +%c. - terminate connection\r\n\ +%cB - send a BREAK to the remote system\r\n\ +%cC - open a command line\r\n\ +%cR - Request rekey (SSH protocol 2 only)\r\n\ +%c^Z - suspend ssh\r\n\ +%c# - list forwarded connections\r\n\ +%c& - background ssh (when waiting for connections to terminate)\r\n\ +%c? - this message\r\n\ +%c%c - send the escape character by typing it twice\r\n\ +(Note that escapes are only recognized immediately after newline.)\r\n", + escape_char, escape_char, escape_char, escape_char, + escape_char, escape_char, escape_char, escape_char, + escape_char, escape_char, escape_char); + buffer_append(berr, string, strlen(string)); + continue; + + case '#': + snprintf(string, sizeof string, "%c#\r\n", escape_char); + buffer_append(berr, string, strlen(string)); + s = channel_open_message(); + buffer_append(berr, s, strlen(s)); + xfree(s); + continue; + + case 'C': + process_cmdline(); + continue; + + default: + if (ch != escape_char) { + buffer_put_char(bin, escape_char); + bytes++; + } + /* Escaped characters fall through here */ + 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'); + buffer_put_char(bin, ch); + bytes++; + } + return bytes; +} + +static void +client_process_input(fd_set * readset) +{ + int len; + char buf[8192]; + + /* 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 && (errno == EAGAIN || errno == EINTR)) + return; /* we'll try again later */ + if (len <= 0) { + /* + * Received EOF or error. They are treated + * similarly, except that an error message is printed + * if it was an error condition. + */ + if (len < 0) { + snprintf(buf, sizeof buf, "read: %.100s\r\n", strerror(errno)); + buffer_append(&stderr_buffer, buf, strlen(buf)); + } + /* 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 == SSH_ESCAPECHAR_NONE) { + /* + * Normal successful read, and no escape character. + * Just append the data to buffer. + */ + buffer_append(&stdin_buffer, buf, len); + } else { + /* + * Normal, successful read. But we have an escape character + * and have to process the characters one by one. + */ + if (process_escapes(&stdin_buffer, &stdout_buffer, + &stderr_buffer, buf, len) == -1) + return; + } + } +} + +static 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 == EINTR || errno == EAGAIN) + len = 0; + else { + /* + * An error or EOF was encountered. Put an + * error message to stderr buffer. + */ + snprintf(buf, sizeof buf, "write stdout: %.50s\r\n", strerror(errno)); + buffer_append(&stderr_buffer, buf, strlen(buf)); + quit_pending = 1; + return; + } + } + /* Consume printed data from the buffer. */ + buffer_consume(&stdout_buffer, len); + stdout_bytes += 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 == EINTR || 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); + stderr_bytes += len; + } +} + +/* + * Get packets from the connection input buffer, and process them as long as + * there are packets available. + * + * 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. + */ + +static void +client_process_buffered_input_packets(void) +{ + dispatch_run(DISPATCH_NONBLOCK, &quit_pending, compat20 ? xxx_kex : NULL); +} + +/* scan buf[] for '~' before sending data to the peer */ + +static int +simple_escape_filter(Channel *c, char *buf, int len) +{ + /* XXX we assume c->extended is writeable */ + return process_escapes(&c->input, &c->output, &c->extended, buf, len); +} + +static void +client_channel_closed(int id, void *arg) +{ + channel_cancel_cleanup(id); + session_closed = 1; + leave_raw_mode(); +} + +/* + * 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 != SSH_ESCAPECHAR_NONE, 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, int ssh2_chan_id) +{ + fd_set *readset = NULL, *writeset = NULL; + double start_time, total_time; + int max_fd = 0, max_fd2 = 0, len, rekeying = 0; + u_int nalloc = 0; + 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 = MAX(connection_in, connection_out); + if (control_fd != -1) + max_fd = MAX(max_fd, control_fd); + + if (!compat20) { + /* enable nonblocking unless tty */ + if (!isatty(fileno(stdin))) + set_nonblock(fileno(stdin)); + if (!isatty(fileno(stdout))) + set_nonblock(fileno(stdout)); + if (!isatty(fileno(stderr))) + set_nonblock(fileno(stderr)); + max_fd = MAX(max_fd, fileno(stdin)); + max_fd = MAX(max_fd, fileno(stdout)); + max_fd = MAX(max_fd, fileno(stderr)); + } + 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); + + client_init_dispatch(); + + /* + * Set signal handlers, (e.g. to restore non-blocking mode) + * but don't overwrite SIG_IGN, matches behaviour from rsh(1) + */ + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, signal_handler); + if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) + signal(SIGQUIT, signal_handler); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, signal_handler); + if (have_pty) + signal(SIGWINCH, window_change_handler); + + if (have_pty) + enter_raw_mode(); + + if (compat20) { + session_ident = ssh2_chan_id; + if (escape_char != SSH_ESCAPECHAR_NONE) + channel_register_filter(session_ident, + simple_escape_filter); + if (session_ident != -1) + channel_register_cleanup(session_ident, + client_channel_closed); + } else { + /* Check if we should immediately send eof on stdin. */ + client_check_initial_eof_on_stdin(); + } + + /* Main loop of the client for the interactive session mode. */ + while (!quit_pending) { + + /* Process buffered packets sent by the server. */ + client_process_buffered_input_packets(); + + if (compat20 && session_closed && !channel_still_open()) + break; + + rekeying = (xxx_kex != NULL && !xxx_kex->done); + + if (rekeying) { + debug("rekeying in progress"); + } else { + /* + * Make packets of buffered stdin data, and buffer + * them for sending to the server. + */ + if (!compat20) + client_make_packets_from_stdin_data(); + + /* + * Make packets from buffered channel data, and + * enqueue 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). + */ + max_fd2 = max_fd; + client_wait_until_can_do_something(&readset, &writeset, + &max_fd2, &nalloc, rekeying); + + if (quit_pending) + break; + + /* Do channel operations unless rekeying in progress. */ + if (!rekeying) { + channel_after_select(readset, writeset); + if (need_rekeying || packet_need_rekeying()) { + debug("need rekeying"); + xxx_kex->done = 0; + kex_send_kexinit(xxx_kex); + need_rekeying = 0; + } + } + + /* Buffer input from the connection. */ + client_process_net_input(readset); + + /* Accept control connections. */ + client_process_control(readset); + + if (quit_pending) + break; + + if (!compat20) { + /* Buffer data from stdin */ + 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(); + } + if (readset) + xfree(readset); + if (writeset) + xfree(writeset); + + /* Terminate the session. */ + + /* Stop watching for window change. */ + if (have_pty) + signal(SIGWINCH, SIG_DFL); + + channel_free_all(); + + if (have_pty) + leave_raw_mode(); + + /* restore blocking io */ + if (!isatty(fileno(stdin))) + unset_nonblock(fileno(stdin)); + if (!isatty(fileno(stdout))) + unset_nonblock(fileno(stdout)); + if (!isatty(fileno(stderr))) + unset_nonblock(fileno(stderr)); + + /* + * If there was no shell or command requested, there will be no remote + * exit status to be returned. In that case, clear error code if the + * connection was deliberately terminated at this end. + */ + if (no_shell_flag && received_signal == SIGTERM) { + received_signal = 0; + exit_status = 0; + } + + if (received_signal) + fatal("Killed by signal %d.", (int) received_signal); + + /* + * In interactive mode (with pseudo tty) display a message indicating + * that the connection has been closed. + */ + if (have_pty && options.log_level != SYSLOG_LEVEL_QUIET) { + snprintf(buf, sizeof buf, "Connection to %.64s closed.\r\n", host); + buffer_append(&stderr_buffer, buf, 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); + stdout_bytes += 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); + stderr_bytes += len; + } + + /* 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; +} + +/*********/ + +static void +client_input_stdout_data(int type, u_int32_t seq, void *ctxt) +{ + u_int data_len; + char *data = packet_get_string(&data_len); + packet_check_eom(); + buffer_append(&stdout_buffer, data, data_len); + memset(data, 0, data_len); + xfree(data); +} +static void +client_input_stderr_data(int type, u_int32_t seq, void *ctxt) +{ + u_int data_len; + char *data = packet_get_string(&data_len); + packet_check_eom(); + buffer_append(&stderr_buffer, data, data_len); + memset(data, 0, data_len); + xfree(data); +} +static void +client_input_exit_status(int type, u_int32_t seq, void *ctxt) +{ + exit_status = packet_get_int(); + packet_check_eom(); + /* 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; +} +static void +client_input_agent_open(int type, u_int32_t seq, void *ctxt) +{ + Channel *c = NULL; + int remote_id, sock; + + /* Read the remote channel number from the message. */ + remote_id = packet_get_int(); + packet_check_eom(); + + /* + * Get a connection to the local authentication agent (this may again + * get forwarded). + */ + sock = ssh_get_authentication_socket(); + + /* + * If we could not connect the agent, send an error message back to + * the server. This should never happen unless the agent dies, + * because authentication forwarding is only enabled if we have an + * agent. + */ + if (sock >= 0) { + c = channel_new("", SSH_CHANNEL_OPEN, sock, sock, + -1, 0, 0, 0, "authentication agent connection", 1); + c->remote_id = remote_id; + c->force_drain = 1; + } + if (c == NULL) { + packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(remote_id); + } else { + /* Send a confirmation to the remote host. */ + debug("Forwarding authentication connection."); + packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION); + packet_put_int(remote_id); + packet_put_int(c->self); + } + packet_send(); +} + +static Channel * +client_request_forwarded_tcpip(const char *request_type, int rchan) +{ + Channel *c = NULL; + char *listen_address, *originator_address; + int listen_port, originator_port; + int sock; + + /* Get rest of the packet */ + listen_address = packet_get_string(NULL); + listen_port = packet_get_int(); + originator_address = packet_get_string(NULL); + originator_port = packet_get_int(); + packet_check_eom(); + + debug("client_request_forwarded_tcpip: listen %s port %d, originator %s port %d", + listen_address, listen_port, originator_address, originator_port); + + sock = channel_connect_by_listen_address(listen_port); + if (sock < 0) { + xfree(originator_address); + xfree(listen_address); + return NULL; + } + c = channel_new("forwarded-tcpip", + SSH_CHANNEL_CONNECTING, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, + originator_address, 1); + xfree(originator_address); + xfree(listen_address); + return c; +} + +static Channel * +client_request_x11(const char *request_type, int rchan) +{ + Channel *c = NULL; + char *originator; + int originator_port; + int sock; + + if (!options.forward_x11) { + error("Warning: ssh server tried X11 forwarding."); + error("Warning: this is probably a break in attempt by a malicious server."); + return NULL; + } + originator = packet_get_string(NULL); + if (datafellows & SSH_BUG_X11FWD) { + debug2("buggy server: x11 request w/o originator_port"); + originator_port = 0; + } else { + originator_port = packet_get_int(); + } + packet_check_eom(); + /* XXX check permission */ + debug("client_request_x11: request from %s %d", originator, + originator_port); + xfree(originator); + sock = x11_connect_display(); + if (sock < 0) + return NULL; + c = channel_new("x11", + SSH_CHANNEL_X11_OPEN, sock, sock, -1, + CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); + c->force_drain = 1; + return c; +} + +static Channel * +client_request_agent(const char *request_type, int rchan) +{ + Channel *c = NULL; + int sock; + + if (!options.forward_agent) { + error("Warning: ssh server tried agent forwarding."); + error("Warning: this is probably a break in attempt by a malicious server."); + return NULL; + } + sock = ssh_get_authentication_socket(); + if (sock < 0) + return NULL; + c = channel_new("authentication agent connection", + SSH_CHANNEL_OPEN, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_WINDOW_DEFAULT, 0, + "authentication agent connection", 1); + c->force_drain = 1; + return c; +} + +/* XXXX move to generic input handler */ +static void +client_input_channel_open(int type, u_int32_t seq, void *ctxt) +{ + Channel *c = NULL; + char *ctype; + int rchan; + u_int rmaxpack, rwindow, len; + + ctype = packet_get_string(&len); + rchan = packet_get_int(); + rwindow = packet_get_int(); + rmaxpack = packet_get_int(); + + debug("client_input_channel_open: ctype %s rchan %d win %d max %d", + ctype, rchan, rwindow, rmaxpack); + + if (strcmp(ctype, "forwarded-tcpip") == 0) { + c = client_request_forwarded_tcpip(ctype, rchan); + } else if (strcmp(ctype, "x11") == 0) { + c = client_request_x11(ctype, rchan); + } else if (strcmp(ctype, "auth-agent@openssh.com") == 0) { + c = client_request_agent(ctype, rchan); + } +/* XXX duplicate : */ + if (c != NULL) { + debug("confirm %s", ctype); + c->remote_id = rchan; + c->remote_window = rwindow; + c->remote_maxpacket = rmaxpack; + if (c->type != SSH_CHANNEL_CONNECTING) { + packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); + packet_put_int(c->remote_id); + packet_put_int(c->self); + packet_put_int(c->local_window); + packet_put_int(c->local_maxpacket); + packet_send(); + } + } else { + debug("failure %s", ctype); + packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(rchan); + packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); + if (!(datafellows & SSH_BUG_OPENFAILURE)) { + packet_put_cstring("open failed"); + packet_put_cstring(""); + } + packet_send(); + } + xfree(ctype); +} +static void +client_input_channel_req(int type, u_int32_t seq, void *ctxt) +{ + Channel *c = NULL; + int exitval, id, reply, success = 0; + char *rtype; + + id = packet_get_int(); + rtype = packet_get_string(NULL); + reply = packet_get_char(); + + debug("client_input_channel_req: channel %d rtype %s reply %d", + id, rtype, reply); + + if (id == -1) { + error("client_input_channel_req: request for channel -1"); + } else if ((c = channel_lookup(id)) == NULL) { + error("client_input_channel_req: channel %d: unknown channel", id); + } else if (strcmp(rtype, "exit-status") == 0) { + exitval = packet_get_int(); + if (id == session_ident) { + success = 1; + exit_status = exitval; + } else if (c->ctl_fd == -1) { + error("client_input_channel_req: unexpected channel %d", + session_ident); + } else { + atomicio(vwrite, c->ctl_fd, &exitval, sizeof(exitval)); + success = 1; + } + packet_check_eom(); + } + if (reply) { + packet_start(success ? + SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); + packet_put_int(id); + packet_send(); + } + xfree(rtype); +} +static void +client_input_global_request(int type, u_int32_t seq, void *ctxt) +{ + char *rtype; + int want_reply; + int success = 0; + + rtype = packet_get_string(NULL); + want_reply = packet_get_char(); + debug("client_input_global_request: rtype %s want_reply %d", + rtype, want_reply); + if (want_reply) { + packet_start(success ? + SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); + packet_send(); + packet_write_wait(); + } + xfree(rtype); +} + +void +client_session2_setup(int id, int want_tty, int want_subsystem, + const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env, + dispatch_fn *subsys_repl) +{ + int len; + + debug2("%s: id %d", __func__, id); + + if (want_tty) { + struct winsize ws; + struct termios tio; + + /* Store window size in the packet. */ + if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) + memset(&ws, 0, sizeof(ws)); + + channel_request_start(id, "pty-req", 0); + packet_put_cstring(term != NULL ? term : ""); + packet_put_int(ws.ws_col); + packet_put_int(ws.ws_row); + packet_put_int(ws.ws_xpixel); + packet_put_int(ws.ws_ypixel); + tio = get_saved_tio(); + tty_make_modes(-1, tiop != NULL ? tiop : &tio); + packet_send(); + /* XXX wait for reply */ + } + + /* Transfer any environment variables from client to server */ + if (options.num_send_env != 0 && env != NULL) { + int i, j, matched; + char *name, *val; + + debug("Sending environment."); + for (i = 0; env[i] != NULL; i++) { + /* Split */ + name = xstrdup(env[i]); + if ((val = strchr(name, '=')) == NULL) { + free(name); + continue; + } + *val++ = '\0'; + + matched = 0; + for (j = 0; j < options.num_send_env; j++) { + if (match_pattern(name, options.send_env[j])) { + matched = 1; + break; + } + } + if (!matched) { + debug3("Ignored env %s", name); + free(name); + continue; + } + + debug("Sending env %s = %s", name, val); + channel_request_start(id, "env", 0); + packet_put_cstring(name); + packet_put_cstring(val); + packet_send(); + free(name); + } + } + + len = buffer_len(cmd); + if (len > 0) { + if (len > 900) + len = 900; + if (want_subsystem) { + debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd)); + channel_request_start(id, "subsystem", subsys_repl != NULL); + if (subsys_repl != NULL) { + /* register callback for reply */ + /* XXX we assume that client_loop has already been called */ + dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl); + dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl); + } + } else { + debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd)); + channel_request_start(id, "exec", 0); + } + packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); + packet_send(); + } else { + channel_request_start(id, "shell", 0); + packet_send(); + } +} + +static void +client_init_dispatch_20(void) +{ + dispatch_init(&dispatch_protocol_error); + + dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); + dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); + dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof); + dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data); + dispatch_set(SSH2_MSG_CHANNEL_OPEN, &client_input_channel_open); + dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); + dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); + dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &client_input_channel_req); + dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); + dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &client_input_global_request); + + /* rekeying */ + dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); + + /* global request reply messages */ + dispatch_set(SSH2_MSG_REQUEST_FAILURE, &client_global_request_reply); + dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply); +} +static void +client_init_dispatch_13(void) +{ + dispatch_init(NULL); + dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); + dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); + dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); + dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); + dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); + dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); + dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status); + dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data); + dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data); + + dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ? + &client_input_agent_open : &deny_input_open); + dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ? + &x11_input_open : &deny_input_open); +} +static void +client_init_dispatch_15(void) +{ + client_init_dispatch_13(); + dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); + dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose); +} +static void +client_init_dispatch(void) +{ + if (compat20) + client_init_dispatch_20(); + else if (compat13) + client_init_dispatch_13(); + else + client_init_dispatch_15(); +} + +/* client specific fatal cleanup */ +void +cleanup_exit(int i) +{ + leave_raw_mode(); + leave_non_blocking(); + if (options.control_path != NULL && control_fd != -1) + unlink(options.control_path); + _exit(i); +} diff --git a/crypto/openssh-3.9p1/clientloop.h b/crypto/openssh-3.9p1/clientloop.h new file mode 100644 index 0000000000..9992d5938b --- /dev/null +++ b/crypto/openssh-3.9p1/clientloop.h @@ -0,0 +1,42 @@ +/* $OpenBSD: clientloop.h,v 1.11 2004/07/11 17:48:47 deraadt Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Client side main loop for the interactive session. */ +int client_loop(int, int, int); +void client_global_request_reply_fwd(int, u_int32_t, void *); +void client_session2_setup(int, int, int, const char *, struct termios *, + int, Buffer *, char **, dispatch_fn *); diff --git a/crypto/openssh-3.9p1/compat.c b/crypto/openssh-3.9p1/compat.c new file mode 100644 index 0000000000..2fdebe7fa2 --- /dev/null +++ b/crypto/openssh-3.9p1/compat.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: compat.c,v 1.70 2003/11/02 11:01:03 markus Exp $"); + +#include "buffer.h" +#include "packet.h" +#include "xmalloc.h" +#include "compat.h" +#include "log.h" +#include "match.h" + +int compat13 = 0; +int compat20 = 0; +int datafellows = 0; + +void +enable_compat20(void) +{ + debug("Enabling compatibility mode for protocol 2.0"); + compat20 = 1; +} +void +enable_compat13(void) +{ + debug("Enabling compatibility mode for protocol 1.3"); + compat13 = 1; +} +/* datafellows bug compatibility */ +void +compat_datafellows(const char *version) +{ + int i; + static struct { + char *pat; + int bugs; + } check[] = { + { "OpenSSH-2.0*," + "OpenSSH-2.1*," + "OpenSSH_2.1*," + "OpenSSH_2.2*", SSH_OLD_SESSIONID|SSH_BUG_BANNER| + SSH_OLD_DHGEX|SSH_BUG_NOREKEY| + SSH_BUG_EXTEOF}, + { "OpenSSH_2.3.0*", SSH_BUG_BANNER|SSH_BUG_BIGENDIANAES| + SSH_OLD_DHGEX|SSH_BUG_NOREKEY| + SSH_BUG_EXTEOF}, + { "OpenSSH_2.3.*", SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| + SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, + { "OpenSSH_2.5.0p1*," + "OpenSSH_2.5.1p1*", + SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX| + SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, + { "OpenSSH_2.5.0*," + "OpenSSH_2.5.1*," + "OpenSSH_2.5.2*", SSH_OLD_DHGEX|SSH_BUG_NOREKEY| + SSH_BUG_EXTEOF}, + { "OpenSSH_2.5.3*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, + { "OpenSSH_2.*," + "OpenSSH_3.0*," + "OpenSSH_3.1*", SSH_BUG_EXTEOF}, + { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, + { "OpenSSH*", 0 }, + { "*MindTerm*", 0 }, + { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| + SSH_OLD_SESSIONID|SSH_BUG_DEBUG| + SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE| + SSH_BUG_FIRSTKEX }, + { "2.1 *", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| + SSH_OLD_SESSIONID|SSH_BUG_DEBUG| + SSH_BUG_RSASIGMD5|SSH_BUG_HBSERVICE| + SSH_BUG_FIRSTKEX }, + { "2.0.13*," + "2.0.14*," + "2.0.15*," + "2.0.16*," + "2.0.17*," + "2.0.18*," + "2.0.19*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| + SSH_OLD_SESSIONID|SSH_BUG_DEBUG| + SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| + SSH_BUG_PKOK|SSH_BUG_RSASIGMD5| + SSH_BUG_HBSERVICE|SSH_BUG_OPENFAILURE| + SSH_BUG_DUMMYCHAN|SSH_BUG_FIRSTKEX }, + { "2.0.11*," + "2.0.12*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| + SSH_OLD_SESSIONID|SSH_BUG_DEBUG| + SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| + SSH_BUG_PKAUTH|SSH_BUG_PKOK| + SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE| + SSH_BUG_DUMMYCHAN|SSH_BUG_FIRSTKEX }, + { "2.0.*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| + SSH_OLD_SESSIONID|SSH_BUG_DEBUG| + SSH_BUG_PKSERVICE|SSH_BUG_X11FWD| + SSH_BUG_PKAUTH|SSH_BUG_PKOK| + SSH_BUG_RSASIGMD5|SSH_BUG_OPENFAILURE| + SSH_BUG_DERIVEKEY|SSH_BUG_DUMMYCHAN| + SSH_BUG_FIRSTKEX }, + { "2.2.0*," + "2.3.0*", SSH_BUG_HMAC|SSH_BUG_DEBUG| + SSH_BUG_RSASIGMD5|SSH_BUG_FIRSTKEX }, + { "2.3.*", SSH_BUG_DEBUG|SSH_BUG_RSASIGMD5| + SSH_BUG_FIRSTKEX }, + { "2.4", SSH_OLD_SESSIONID }, /* Van Dyke */ + { "2.*", SSH_BUG_DEBUG|SSH_BUG_FIRSTKEX }, + { "3.0.*", SSH_BUG_DEBUG }, + { "3.0 SecureCRT*", SSH_OLD_SESSIONID }, + { "1.7 SecureFX*", SSH_OLD_SESSIONID }, + { "1.2.18*," + "1.2.19*," + "1.2.20*," + "1.2.21*," + "1.2.22*", SSH_BUG_IGNOREMSG }, + { "1.3.2*", /* F-Secure */ + SSH_BUG_IGNOREMSG }, + { "*SSH Compatible Server*", /* Netscreen */ + SSH_BUG_PASSWORDPAD }, + { "*OSU_0*," + "OSU_1.0*," + "OSU_1.1*," + "OSU_1.2*," + "OSU_1.3*," + "OSU_1.4*," + "OSU_1.5alpha1*," + "OSU_1.5alpha2*," + "OSU_1.5alpha3*", SSH_BUG_PASSWORDPAD }, + { "*SSH_Version_Mapper*", + SSH_BUG_SCANNER }, + { "Probe-*", + SSH_BUG_PROBE }, + { NULL, 0 } + }; + + /* process table, return first match */ + for (i = 0; check[i].pat; i++) { + if (match_pattern_list(version, check[i].pat, + strlen(check[i].pat), 0) == 1) { + debug("match: %s pat %s", version, check[i].pat); + datafellows = check[i].bugs; + return; + } + } + debug("no match: %s", version); +} + +#define SEP "," +int +proto_spec(const char *spec) +{ + char *s, *p, *q; + int ret = SSH_PROTO_UNKNOWN; + + if (spec == NULL) + return ret; + q = s = xstrdup(spec); + for ((p = strsep(&q, SEP)); p && *p != '\0'; (p = strsep(&q, SEP))) { + switch (atoi(p)) { + case 1: + if (ret == SSH_PROTO_UNKNOWN) + ret |= SSH_PROTO_1_PREFERRED; + ret |= SSH_PROTO_1; + break; + case 2: + ret |= SSH_PROTO_2; + break; + default: + logit("ignoring bad proto spec: '%s'.", p); + break; + } + } + xfree(s); + return ret; +} + +char * +compat_cipher_proposal(char *cipher_prop) +{ + Buffer b; + char *orig_prop, *fix_ciphers; + char *cp, *tmp; + + if (!(datafellows & SSH_BUG_BIGENDIANAES)) + return(cipher_prop); + + buffer_init(&b); + tmp = orig_prop = xstrdup(cipher_prop); + while ((cp = strsep(&tmp, ",")) != NULL) { + if (strncmp(cp, "aes", 3) != 0) { + if (buffer_len(&b) > 0) + buffer_append(&b, ",", 1); + buffer_append(&b, cp, strlen(cp)); + } + } + buffer_append(&b, "\0", 1); + fix_ciphers = xstrdup(buffer_ptr(&b)); + buffer_free(&b); + xfree(orig_prop); + debug2("Original cipher proposal: %s", cipher_prop); + debug2("Compat cipher proposal: %s", fix_ciphers); + if (!*fix_ciphers) + fatal("No available ciphers found."); + + return(fix_ciphers); +} diff --git a/crypto/openssh-3.9p1/compat.h b/crypto/openssh-3.9p1/compat.h new file mode 100644 index 0000000000..5efb5c29e3 --- /dev/null +++ b/crypto/openssh-3.9p1/compat.h @@ -0,0 +1,68 @@ +/* $OpenBSD: compat.h,v 1.38 2004/07/11 17:48:47 deraadt Exp $ */ + +/* + * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef COMPAT_H +#define COMPAT_H + +#define SSH_PROTO_UNKNOWN 0x00 +#define SSH_PROTO_1 0x01 +#define SSH_PROTO_1_PREFERRED 0x02 +#define SSH_PROTO_2 0x04 + +#define SSH_BUG_SIGBLOB 0x00000001 +#define SSH_BUG_PKSERVICE 0x00000002 +#define SSH_BUG_HMAC 0x00000004 +#define SSH_BUG_X11FWD 0x00000008 +#define SSH_OLD_SESSIONID 0x00000010 +#define SSH_BUG_PKAUTH 0x00000020 +#define SSH_BUG_DEBUG 0x00000040 +#define SSH_BUG_BANNER 0x00000080 +#define SSH_BUG_IGNOREMSG 0x00000100 +#define SSH_BUG_PKOK 0x00000200 +#define SSH_BUG_PASSWORDPAD 0x00000400 +#define SSH_BUG_SCANNER 0x00000800 +#define SSH_BUG_BIGENDIANAES 0x00001000 +#define SSH_BUG_RSASIGMD5 0x00002000 +#define SSH_OLD_DHGEX 0x00004000 +#define SSH_BUG_NOREKEY 0x00008000 +#define SSH_BUG_HBSERVICE 0x00010000 +#define SSH_BUG_OPENFAILURE 0x00020000 +#define SSH_BUG_DERIVEKEY 0x00040000 +#define SSH_BUG_DUMMYCHAN 0x00100000 +#define SSH_BUG_EXTEOF 0x00200000 +#define SSH_BUG_PROBE 0x00400000 +#define SSH_BUG_FIRSTKEX 0x00800000 + +void enable_compat13(void); +void enable_compat20(void); +void compat_datafellows(const char *); +int proto_spec(const char *); +char *compat_cipher_proposal(char *); + +extern int compat13; +extern int compat20; +extern int datafellows; +#endif diff --git a/crypto/openssh-3.9p1/compress.c b/crypto/openssh-3.9p1/compress.c new file mode 100644 index 0000000000..0d1c7e55e8 --- /dev/null +++ b/crypto/openssh-3.9p1/compress.c @@ -0,0 +1,162 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Interface to packet compression for ssh. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: compress.c,v 1.21 2004/01/13 19:45:15 markus Exp $"); + +#include "log.h" +#include "buffer.h" +#include "zlib.h" +#include "compress.h" + +z_stream incoming_stream; +z_stream outgoing_stream; +static int compress_init_send_called = 0; +static int compress_init_recv_called = 0; +static int inflate_failed = 0; +static int deflate_failed = 0; + +/* + * Initializes compression; level is compression level from 1 to 9 + * (as in gzip). + */ + +void +buffer_compress_init_send(int level) +{ + if (compress_init_send_called == 1) + deflateEnd(&outgoing_stream); + compress_init_send_called = 1; + debug("Enabling compression at level %d.", level); + if (level < 1 || level > 9) + fatal("Bad compression level %d.", level); + deflateInit(&outgoing_stream, level); +} +void +buffer_compress_init_recv(void) +{ + if (compress_init_recv_called == 1) + inflateEnd(&incoming_stream); + compress_init_recv_called = 1; + inflateInit(&incoming_stream); +} + +/* Frees any data structures allocated for compression. */ + +void +buffer_compress_uninit(void) +{ + debug("compress outgoing: raw data %llu, compressed %llu, factor %.2f", + (unsigned long long)outgoing_stream.total_in, + (unsigned long long)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 %llu, compressed %llu, factor %.2f", + (unsigned long long)incoming_stream.total_out, + (unsigned long long)incoming_stream.total_in, + incoming_stream.total_out == 0 ? 0.0 : + (double) incoming_stream.total_in / incoming_stream.total_out); + if (compress_init_recv_called == 1 && inflate_failed == 0) + inflateEnd(&incoming_stream); + if (compress_init_send_called == 1 && deflate_failed == 0) + 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) +{ + u_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; + default: + deflate_failed = 1; + 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) +{ + u_char buf[4096]; + int status; + + incoming_stream.next_in = buffer_ptr(input_buffer); + incoming_stream.avail_in = buffer_len(input_buffer); + + for (;;) { + /* Set up fixed-size output buffer. */ + incoming_stream.next_out = buf; + incoming_stream.avail_out = sizeof(buf); + + status = inflate(&incoming_stream, Z_PARTIAL_FLUSH); + switch (status) { + case Z_OK: + buffer_append(output_buffer, buf, + sizeof(buf) - incoming_stream.avail_out); + break; + 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; + default: + inflate_failed = 1; + fatal("buffer_uncompress: inflate returned %d", status); + /* NOTREACHED */ + } + } +} diff --git a/crypto/openssh-3.9p1/compress.h b/crypto/openssh-3.9p1/compress.h new file mode 100644 index 0000000000..e364f4bdc5 --- /dev/null +++ b/crypto/openssh-3.9p1/compress.h @@ -0,0 +1,25 @@ +/* $OpenBSD: compress.h,v 1.11 2002/03/04 17:27:39 stevesk Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Interface to packet compression for ssh. + * + * 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". + */ + +#ifndef COMPRESS_H +#define COMPRESS_H + +void buffer_compress_init_send(int); +void buffer_compress_init_recv(void); +void buffer_compress_uninit(void); +void buffer_compress(Buffer *, Buffer *); +void buffer_uncompress(Buffer *, Buffer *); + +#endif /* COMPRESS_H */ diff --git a/crypto/openssh-3.9p1/crc32.c b/crypto/openssh-3.9p1/crc32.c new file mode 100644 index 0000000000..ac627b57a5 --- /dev/null +++ b/crypto/openssh-3.9p1/crc32.c @@ -0,0 +1,105 @@ +/* $OpenBSD: crc32.c,v 1.9 2003/02/12 21:39:50 markus Exp $ */ + +/* + * Copyright (c) 2003 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +#include "crc32.h" + +static const u_int32_t crc32tab[] = { + 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 +}; + +u_int32_t +ssh_crc32(const u_char *buf, u_int32_t size) +{ + u_int32_t i, crc; + + crc = 0; + for (i = 0; i < size; i++) + crc = crc32tab[(crc ^ buf[i]) & 0xff] ^ (crc >> 8); + return crc; +} diff --git a/crypto/openssh-3.9p1/crc32.h b/crypto/openssh-3.9p1/crc32.h new file mode 100644 index 0000000000..a2fb58493a --- /dev/null +++ b/crypto/openssh-3.9p1/crc32.h @@ -0,0 +1,30 @@ +/* $OpenBSD: crc32.h,v 1.14 2003/02/12 21:39:50 markus Exp $ */ + +/* + * Copyright (c) 2003 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SSH_CRC32_H +#define SSH_CRC32_H +u_int32_t ssh_crc32(const u_char *, u_int32_t); +#endif diff --git a/crypto/openssh-3.9p1/deattack.c b/crypto/openssh-3.9p1/deattack.c new file mode 100644 index 0000000000..8b55d66868 --- /dev/null +++ b/crypto/openssh-3.9p1/deattack.c @@ -0,0 +1,156 @@ +/* + * Cryptographic attack detector for ssh - source code + * + * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina. + * + * All rights reserved. Redistribution and use in source and binary + * forms, with or without modification, are permitted provided that + * this copyright notice is retained. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR + * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS + * SOFTWARE. + * + * Ariel Futoransky + * + */ + +#include "includes.h" +RCSID("$OpenBSD: deattack.c,v 1.19 2003/09/18 08:49:45 markus Exp $"); + +#include "deattack.h" +#include "log.h" +#include "crc32.h" +#include "getput.h" +#include "xmalloc.h" +#include "deattack.h" + +/* SSH Constants */ +#define SSH_MAXBLOCKS (32 * 1024) +#define SSH_BLOCKSIZE (8) + +/* Hashing constants */ +#define HASH_MINSIZE (8 * 1024) +#define HASH_ENTRYSIZE (2) +#define HASH_FACTOR(x) ((x)*3/2) +#define HASH_UNUSEDCHAR (0xff) +#define HASH_UNUSED (0xffff) +#define HASH_IV (0xfffe) + +#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE) + + +/* Hash function (Input keys are cipher results) */ +#define HASH(x) GET_32BIT(x) + +#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE)) + +static void +crc_update(u_int32_t *a, u_int32_t b) +{ + b ^= *a; + *a = ssh_crc32((u_char *) &b, sizeof(b)); +} + +/* detect if a block is used in a particular pattern */ +static int +check_crc(u_char *S, u_char *buf, u_int32_t len, + u_char *IV) +{ + u_int32_t crc; + u_char *c; + + crc = 0; + if (IV && !CMP(S, IV)) { + crc_update(&crc, 1); + crc_update(&crc, 0); + } + for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) { + if (!CMP(S, c)) { + crc_update(&crc, 1); + crc_update(&crc, 0); + } else { + crc_update(&crc, 0); + crc_update(&crc, 0); + } + } + return (crc == 0); +} + + +/* Detect a crc32 compensation attack on a packet */ +int +detect_attack(u_char *buf, u_int32_t len, u_char *IV) +{ + static u_int16_t *h = (u_int16_t *) NULL; + static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE; + u_int32_t i, j; + u_int32_t l; + u_char *c; + u_char *d; + + if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) || + len % SSH_BLOCKSIZE != 0) { + fatal("detect_attack: bad length %d", len); + } + for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2) + ; + + if (h == NULL) { + debug("Installing crc compensation attack detector."); + h = (u_int16_t *) xmalloc(l * HASH_ENTRYSIZE); + n = l; + } else { + if (l > n) { + h = (u_int16_t *) xrealloc(h, l * HASH_ENTRYSIZE); + n = l; + } + } + + if (len <= HASH_MINBLOCKS) { + for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) { + if (IV && (!CMP(c, IV))) { + if ((check_crc(c, buf, len, IV))) + return (DEATTACK_DETECTED); + else + break; + } + for (d = buf; d < c; d += SSH_BLOCKSIZE) { + if (!CMP(c, d)) { + if ((check_crc(c, buf, len, IV))) + return (DEATTACK_DETECTED); + else + break; + } + } + } + return (DEATTACK_OK); + } + memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE); + + if (IV) + h[HASH(IV) & (n - 1)] = HASH_IV; + + for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) { + for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED; + i = (i + 1) & (n - 1)) { + if (h[i] == HASH_IV) { + if (!CMP(c, IV)) { + if (check_crc(c, buf, len, IV)) + return (DEATTACK_DETECTED); + else + break; + } + } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) { + if (check_crc(c, buf, len, IV)) + return (DEATTACK_DETECTED); + else + break; + } + } + h[i] = j; + } + return (DEATTACK_OK); +} diff --git a/crypto/openssh-3.9p1/deattack.h b/crypto/openssh-3.9p1/deattack.h new file mode 100644 index 0000000000..ddccdea505 --- /dev/null +++ b/crypto/openssh-3.9p1/deattack.h @@ -0,0 +1,30 @@ +/* $OpenBSD: deattack.h,v 1.7 2001/06/26 17:27:23 markus Exp $ */ + +/* + * Cryptographic attack detector for ssh - Header file + * + * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina. + * + * All rights reserved. Redistribution and use in source and binary + * forms, with or without modification, are permitted provided that + * this copyright notice is retained. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR + * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS + * SOFTWARE. + * + * Ariel Futoransky + * + */ + +#ifndef _DEATTACK_H +#define _DEATTACK_H + +/* Return codes */ +#define DEATTACK_OK 0 +#define DEATTACK_DETECTED 1 + +int detect_attack(u_char *, u_int32_t, u_char[8]); +#endif diff --git a/crypto/openssh-3.9p1/defines.h b/crypto/openssh-3.9p1/defines.h new file mode 100644 index 0000000000..8c1d9c4099 --- /dev/null +++ b/crypto/openssh-3.9p1/defines.h @@ -0,0 +1,649 @@ +/* + * Copyright (c) 1999-2003 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEFINES_H +#define _DEFINES_H + +/* $Id: defines.h,v 1.117 2004/06/22 03:27:16 dtucker Exp $ */ + + +/* Constants */ + +#ifndef SHUT_RDWR +enum +{ + SHUT_RD = 0, /* No more receptions. */ + SHUT_WR, /* No more transmissions. */ + SHUT_RDWR /* No more receptions or transmissions. */ +}; +# define SHUT_RD SHUT_RD +# define SHUT_WR SHUT_WR +# define SHUT_RDWR SHUT_RDWR +#endif + +#ifndef IPTOS_LOWDELAY +# define IPTOS_LOWDELAY 0x10 +# define IPTOS_THROUGHPUT 0x08 +# define IPTOS_RELIABILITY 0x04 +# define IPTOS_LOWCOST 0x02 +# define IPTOS_MINCOST IPTOS_LOWCOST +#endif /* IPTOS_LOWDELAY */ + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# else /* PATH_MAX */ +# define MAXPATHLEN 64 /* Should be safe */ +# endif /* PATH_MAX */ +#endif /* MAXPATHLEN */ + +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + +#ifndef NGROUPS_MAX /* Disable groupaccess if NGROUP_MAX is not set */ +#ifdef NGROUPS +#define NGROUPS_MAX NGROUPS +#else +#define NGROUPS_MAX 0 +#endif +#endif + +#ifndef O_NONBLOCK /* Non Blocking Open */ +# define O_NONBLOCK 00004 +#endif + +#ifndef S_ISDIR +# define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR)) +#endif /* S_ISDIR */ + +#ifndef S_ISREG +# define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG)) +#endif /* S_ISREG */ + +#ifndef S_ISLNK +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#endif /* S_ISLNK */ + +#ifndef S_IXUSR +# define S_IXUSR 0000100 /* execute/search permission, */ +# define S_IXGRP 0000010 /* execute/search permission, */ +# define S_IXOTH 0000001 /* execute/search permission, */ +# define _S_IWUSR 0000200 /* write permission, */ +# define S_IWUSR _S_IWUSR /* write permission, owner */ +# define S_IWGRP 0000020 /* write permission, group */ +# define S_IWOTH 0000002 /* write permission, other */ +# define S_IRUSR 0000400 /* read permission, owner */ +# define S_IRGRP 0000040 /* read permission, group */ +# define S_IROTH 0000004 /* read permission, other */ +# define S_IRWXU 0000700 /* read, write, execute */ +# define S_IRWXG 0000070 /* read, write, execute */ +# define S_IRWXO 0000007 /* read, write, execute */ +#endif /* S_IXUSR */ + +#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS) +#define MAP_ANON MAP_ANONYMOUS +#endif + +#ifndef MAP_FAILED +# define MAP_FAILED ((void *)-1) +#endif + +/* *-*-nto-qnx doesn't define this constant in the system headers */ +#ifdef MISSING_NFDBITS +# define NFDBITS (8 * sizeof(unsigned long)) +#endif + +/* +SCO Open Server 3 has INADDR_LOOPBACK defined in rpc/rpc.h but +including rpc/rpc.h breaks Solaris 6 +*/ +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK ((u_long)0x7f000001) +#endif + +#ifndef __unused +#define __unused +#endif + +/* Types */ + +/* If sys/types.h does not supply intXX_t, supply them ourselves */ +/* (or die trying) */ + + +#ifndef HAVE_U_INT +typedef unsigned int u_int; +#endif + +#ifndef HAVE_INTXX_T +# if (SIZEOF_CHAR == 1) +typedef char int8_t; +# else +# error "8 bit int type not found." +# endif +# if (SIZEOF_SHORT_INT == 2) +typedef short int int16_t; +# else +# ifdef _UNICOS +# if (SIZEOF_SHORT_INT == 4) +typedef short int16_t; +# else +typedef long int16_t; +# endif +# else +# error "16 bit int type not found." +# endif /* _UNICOS */ +# endif +# if (SIZEOF_INT == 4) +typedef int int32_t; +# else +# ifdef _UNICOS +typedef long int32_t; +# else +# error "32 bit int type not found." +# endif /* _UNICOS */ +# endif +#endif + +/* If sys/types.h does not supply u_intXX_t, supply them ourselves */ +#ifndef HAVE_U_INTXX_T +# ifdef HAVE_UINTXX_T +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +# define HAVE_U_INTXX_T 1 +# else +# if (SIZEOF_CHAR == 1) +typedef unsigned char u_int8_t; +# else +# error "8 bit int type not found." +# endif +# if (SIZEOF_SHORT_INT == 2) +typedef unsigned short int u_int16_t; +# else +# ifdef _UNICOS +# if (SIZEOF_SHORT_INT == 4) +typedef unsigned short u_int16_t; +# else +typedef unsigned long u_int16_t; +# endif +# else +# error "16 bit int type not found." +# endif +# endif +# if (SIZEOF_INT == 4) +typedef unsigned int u_int32_t; +# else +# ifdef _UNICOS +typedef unsigned long u_int32_t; +# else +# error "32 bit int type not found." +# endif +# endif +# endif +#define __BIT_TYPES_DEFINED__ +#endif + +/* 64-bit types */ +#ifndef HAVE_INT64_T +# if (SIZEOF_LONG_INT == 8) +typedef long int int64_t; +# else +# if (SIZEOF_LONG_LONG_INT == 8) +typedef long long int int64_t; +# endif +# endif +#endif +#ifndef HAVE_U_INT64_T +# if (SIZEOF_LONG_INT == 8) +typedef unsigned long int u_int64_t; +# else +# if (SIZEOF_LONG_LONG_INT == 8) +typedef unsigned long long int u_int64_t; +# endif +# endif +#endif + +#ifndef HAVE_U_CHAR +typedef unsigned char u_char; +# define HAVE_U_CHAR +#endif /* HAVE_U_CHAR */ + +#ifndef SIZE_T_MAX +#define SIZE_T_MAX ULONG_MAX +#endif /* SIZE_T_MAX */ + +#ifndef HAVE_SIZE_T +typedef unsigned int size_t; +# define HAVE_SIZE_T +# define SIZE_T_MAX UINT_MAX +#endif /* HAVE_SIZE_T */ + +#ifndef HAVE_SSIZE_T +typedef int ssize_t; +# define HAVE_SSIZE_T +#endif /* HAVE_SSIZE_T */ + +#ifndef HAVE_CLOCK_T +typedef long clock_t; +# define HAVE_CLOCK_T +#endif /* HAVE_CLOCK_T */ + +#ifndef HAVE_SA_FAMILY_T +typedef int sa_family_t; +# define HAVE_SA_FAMILY_T +#endif /* HAVE_SA_FAMILY_T */ + +#ifndef HAVE_PID_T +typedef int pid_t; +# define HAVE_PID_T +#endif /* HAVE_PID_T */ + +#ifndef HAVE_SIG_ATOMIC_T +typedef int sig_atomic_t; +# define HAVE_SIG_ATOMIC_T +#endif /* HAVE_SIG_ATOMIC_T */ + +#ifndef HAVE_MODE_T +typedef int mode_t; +# define HAVE_MODE_T +#endif /* HAVE_MODE_T */ + +#if !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE___SS_FAMILY_IN_SS) +# define ss_family __ss_family +#endif /* !defined(HAVE_SS_FAMILY_IN_SS) && defined(HAVE_SA_FAMILY_IN_SS) */ + +#ifndef HAVE_SYS_UN_H +struct sockaddr_un { + short sun_family; /* AF_UNIX */ + char sun_path[108]; /* path name (gag) */ +}; +#endif /* HAVE_SYS_UN_H */ + +#if defined(BROKEN_SYS_TERMIO_H) && !defined(_STRUCT_WINSIZE) +#define _STRUCT_WINSIZE +struct winsize { + unsigned short ws_row; /* rows, in characters */ + unsigned short ws_col; /* columns, in character */ + unsigned short ws_xpixel; /* horizontal size, pixels */ + unsigned short ws_ypixel; /* vertical size, pixels */ +}; +#endif + +/* *-*-nto-qnx does not define this type in the system headers */ +#ifdef MISSING_FD_MASK + typedef unsigned long int fd_mask; +#endif + +/* Paths */ + +#ifndef _PATH_BSHELL +# define _PATH_BSHELL "/bin/sh" +#endif +#ifndef _PATH_CSHELL +# define _PATH_CSHELL "/bin/csh" +#endif +#ifndef _PATH_SHELLS +# define _PATH_SHELLS "/etc/shells" +#endif + +#ifdef USER_PATH +# ifdef _PATH_STDPATH +# undef _PATH_STDPATH +# endif +# define _PATH_STDPATH USER_PATH +#endif + +#ifndef _PATH_STDPATH +# define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" +#endif + +#ifndef SUPERUSER_PATH +# define SUPERUSER_PATH _PATH_STDPATH +#endif + +#ifndef _PATH_DEVNULL +# define _PATH_DEVNULL "/dev/null" +#endif + +#ifndef MAIL_DIRECTORY +# define MAIL_DIRECTORY "/var/spool/mail" +#endif + +#ifndef MAILDIR +# define MAILDIR MAIL_DIRECTORY +#endif + +#if !defined(_PATH_MAILDIR) && defined(MAILDIR) +# define _PATH_MAILDIR MAILDIR +#endif /* !defined(_PATH_MAILDIR) && defined(MAILDIR) */ + +#ifndef _PATH_NOLOGIN +# define _PATH_NOLOGIN "/etc/nologin" +#endif + +/* Define this to be the path of the xauth program. */ +#ifdef XAUTH_PATH +#define _PATH_XAUTH XAUTH_PATH +#endif /* XAUTH_PATH */ + +/* derived from XF4/xc/lib/dps/Xlibnet.h */ +#ifndef X_UNIX_PATH +# ifdef __hpux +# define X_UNIX_PATH "/var/spool/sockets/X11/%u" +# else +# define X_UNIX_PATH "/tmp/.X11-unix/X%u" +# endif +#endif /* X_UNIX_PATH */ +#define _PATH_UNIX_X X_UNIX_PATH + +#ifndef _PATH_TTY +# define _PATH_TTY "/dev/tty" +#endif + +/* Macros */ + +#if defined(HAVE_LOGIN_GETCAPBOOL) && defined(HAVE_LOGIN_CAP_H) +# define HAVE_LOGIN_CAP +#endif + +#ifndef MAX +# define MAX(a,b) (((a)>(b))?(a):(b)) +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef roundup +# define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +#endif + +#ifndef timersub +#define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +#ifndef TIMEVAL_TO_TIMESPEC +#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ +} +#endif + +#ifndef TIMESPEC_TO_TIMEVAL +#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ + (tv)->tv_sec = (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ +} +#endif + +#ifndef __P +# define __P(x) x +#endif + +#if !defined(IN6_IS_ADDR_V4MAPPED) +# define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) +#endif /* !defined(IN6_IS_ADDR_V4MAPPED) */ + +#if !defined(__GNUC__) || (__GNUC__ < 2) +# define __attribute__(x) +#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */ + +#ifndef __dead +# define __dead __attribute__((noreturn)) +#endif + +/* *-*-nto-qnx doesn't define this macro in the system headers */ +#ifdef MISSING_HOWMANY +# define howmany(x,y) (((x)+((y)-1))/(y)) +#endif + +#ifndef OSSH_ALIGNBYTES +#define OSSH_ALIGNBYTES (sizeof(int) - 1) +#endif +#ifndef __CMSG_ALIGN +#define __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES) +#endif + +/* Length of the contents of a control message of length len */ +#ifndef CMSG_LEN +#define CMSG_LEN(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) +#endif + +/* Length of the space taken up by a padded control message of length len */ +#ifndef CMSG_SPACE +#define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len)) +#endif + +/* given pointer to struct cmsghdr, return pointer to data */ +#ifndef CMSG_DATA +#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + __CMSG_ALIGN(sizeof(struct cmsghdr))) +#endif /* CMSG_DATA */ + +/* + * RFC 2292 requires to check msg_controllen, in case that the kernel returns + * an empty list for some reasons. + */ +#ifndef CMSG_FIRSTHDR +#define CMSG_FIRSTHDR(mhdr) \ + ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ + (struct cmsghdr *)(mhdr)->msg_control : \ + (struct cmsghdr *)NULL) +#endif /* CMSG_FIRSTHDR */ + +#ifndef offsetof +# define offsetof(type, member) ((size_t) &((type *)0)->member) +#endif + +/* Function replacement / compatibility hacks */ + +#if !defined(HAVE_GETADDRINFO) && (defined(HAVE_OGETADDRINFO) || defined(HAVE_NGETADDRINFO)) +# define HAVE_GETADDRINFO +#endif + +#ifndef HAVE_GETOPT_OPTRESET +# undef getopt +# undef opterr +# undef optind +# undef optopt +# undef optreset +# undef optarg +# define getopt(ac, av, o) BSDgetopt(ac, av, o) +# define opterr BSDopterr +# define optind BSDoptind +# define optopt BSDoptopt +# define optreset BSDoptreset +# define optarg BSDoptarg +#endif + +/* In older versions of libpam, pam_strerror takes a single argument */ +#ifdef HAVE_OLD_PAM +# define PAM_STRERROR(a,b) pam_strerror((b)) +#else +# define PAM_STRERROR(a,b) pam_strerror((a),(b)) +#endif + +#ifdef PAM_SUN_CODEBASE +# define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member) +#else +# define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member) +#endif + +#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GETADDRINFO) +# undef HAVE_GETADDRINFO +#endif +#if defined(BROKEN_GETADDRINFO) && defined(HAVE_FREEADDRINFO) +# undef HAVE_FREEADDRINFO +#endif +#if defined(BROKEN_GETADDRINFO) && defined(HAVE_GAI_STRERROR) +# undef HAVE_GAI_STRERROR +#endif + +#if defined(BROKEN_UPDWTMPX) && defined(HAVE_UPDWTMPX) +# undef HAVE_UPDWTMPX +#endif + +#if !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) +# define memmove(s1, s2, n) bcopy((s2), (s1), (n)) +#endif /* !defined(HAVE_MEMMOVE) && defined(HAVE_BCOPY) */ + +#if defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) +# define USE_VHANGUP +#endif /* defined(HAVE_VHANGUP) && !defined(HAVE_DEV_PTMX) */ + +#ifndef GETPGRP_VOID +# define getpgrp() getpgrp(0) +#endif + +/* OPENSSL_free() is Free() in versions before OpenSSL 0.9.6 */ +#if !defined(OPENSSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x0090600f) +# define OPENSSL_free(x) Free(x) +#endif + +#if !defined(HAVE___func__) && defined(HAVE___FUNCTION__) +# define __func__ __FUNCTION__ +#elif !defined(HAVE___func__) +# define __func__ "" +#endif + +#if defined(KRB5) && !defined(HEIMDAL) +# define krb5_get_err_text(context,code) error_message(code) +#endif + +#if defined(SKEYCHALLENGE_4ARG) +# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c,d) +#else +# define _compat_skeychallenge(a,b,c,d) skeychallenge(a,b,c) +#endif + +/* Maximum number of file descriptors available */ +#ifdef HAVE_SYSCONF +# define SSH_SYSFDMAX sysconf(_SC_OPEN_MAX) +#else +# define SSH_SYSFDMAX 10000 +#endif + + +/* + * Define this to use pipes instead of socketpairs for communicating with the + * client program. Socketpairs do not seem to work on all systems. + * + * configure.ac sets this for a few OS's which are known to have problems + * but you may need to set it yourself + */ +/* #define USE_PIPES 1 */ + +/** + ** login recorder definitions + **/ + +/* FIXME: put default paths back in */ +#ifndef UTMP_FILE +# ifdef _PATH_UTMP +# define UTMP_FILE _PATH_UTMP +# else +# ifdef CONF_UTMP_FILE +# define UTMP_FILE CONF_UTMP_FILE +# endif +# endif +#endif +#ifndef WTMP_FILE +# ifdef _PATH_WTMP +# define WTMP_FILE _PATH_WTMP +# else +# ifdef CONF_WTMP_FILE +# define WTMP_FILE CONF_WTMP_FILE +# endif +# endif +#endif +/* pick up the user's location for lastlog if given */ +#ifndef LASTLOG_FILE +# ifdef _PATH_LASTLOG +# define LASTLOG_FILE _PATH_LASTLOG +# else +# ifdef CONF_LASTLOG_FILE +# define LASTLOG_FILE CONF_LASTLOG_FILE +# endif +# endif +#endif + +#if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) +# define USE_SHADOW +#endif + +/* The login() library function in libutil is first choice */ +#if defined(HAVE_LOGIN) && !defined(DISABLE_LOGIN) +# define USE_LOGIN + +#else +/* Simply select your favourite login types. */ +/* Can't do if-else because some systems use several... */ +# if defined(UTMPX_FILE) && !defined(DISABLE_UTMPX) +# define USE_UTMPX +# endif +# if defined(UTMP_FILE) && !defined(DISABLE_UTMP) +# define USE_UTMP +# endif +# if defined(WTMPX_FILE) && !defined(DISABLE_WTMPX) +# define USE_WTMPX +# endif +# if defined(WTMP_FILE) && !defined(DISABLE_WTMP) +# define USE_WTMP +# endif + +#endif + +#ifndef UT_LINESIZE +# define UT_LINESIZE 8 +#endif + +/* I hope that the presence of LASTLOG_FILE is enough to detect this */ +#if defined(LASTLOG_FILE) && !defined(DISABLE_LASTLOG) +# define USE_LASTLOG +#endif + +#ifdef HAVE_OSF_SIA +# ifdef USE_SHADOW +# undef USE_SHADOW +# endif +# define CUSTOM_SYS_AUTH_PASSWD 1 +#endif + +/** end of login recorder definitions */ + +#endif /* _DEFINES_H */ diff --git a/crypto/openssh-3.9p1/dh.c b/crypto/openssh-3.9p1/dh.c new file mode 100644 index 0000000000..044d869fb8 --- /dev/null +++ b/crypto/openssh-3.9p1/dh.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: dh.c,v 1.31 2004/08/04 10:37:52 djm Exp $"); + +#include "xmalloc.h" + +#include +#include +#include + +#include "buffer.h" +#include "cipher.h" +#include "kex.h" +#include "dh.h" +#include "pathnames.h" +#include "log.h" +#include "misc.h" + +static int +parse_prime(int linenum, char *line, struct dhgroup *dhg) +{ + char *cp, *arg; + char *strsize, *gen, *prime; + + cp = line; + arg = strdelim(&cp); + /* Ignore leading whitespace */ + if (*arg == '\0') + arg = strdelim(&cp); + if (!arg || !*arg || *arg == '#') + return 0; + + /* time */ + if (cp == NULL || *arg == '\0') + goto fail; + arg = strsep(&cp, " "); /* type */ + if (cp == NULL || *arg == '\0') + goto fail; + arg = strsep(&cp, " "); /* tests */ + if (cp == NULL || *arg == '\0') + goto fail; + arg = strsep(&cp, " "); /* tries */ + if (cp == NULL || *arg == '\0') + goto fail; + strsize = strsep(&cp, " "); /* size */ + if (cp == NULL || *strsize == '\0' || + (dhg->size = atoi(strsize)) == 0) + goto fail; + /* The whole group is one bit larger */ + dhg->size++; + gen = strsep(&cp, " "); /* gen */ + if (cp == NULL || *gen == '\0') + goto fail; + prime = strsep(&cp, " "); /* prime */ + if (cp != NULL || *prime == '\0') + goto fail; + + if ((dhg->g = BN_new()) == NULL) + fatal("parse_prime: BN_new failed"); + if ((dhg->p = BN_new()) == NULL) + fatal("parse_prime: BN_new failed"); + if (BN_hex2bn(&dhg->g, gen) == 0) + goto failclean; + + if (BN_hex2bn(&dhg->p, prime) == 0) + goto failclean; + + if (BN_num_bits(dhg->p) != dhg->size) + goto failclean; + + if (BN_is_zero(dhg->g) || BN_is_one(dhg->g)) + goto failclean; + + return (1); + + failclean: + BN_clear_free(dhg->g); + BN_clear_free(dhg->p); + fail: + error("Bad prime description in line %d", linenum); + return (0); +} + +DH * +choose_dh(int min, int wantbits, int max) +{ + FILE *f; + char line[4096]; + int best, bestcount, which; + int linenum; + struct dhgroup dhg; + + if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL && + (f = fopen(_PATH_DH_PRIMES, "r")) == NULL) { + logit("WARNING: %s does not exist, using fixed modulus", + _PATH_DH_MODULI); + return (dh_new_group14()); + } + + linenum = 0; + best = bestcount = 0; + while (fgets(line, sizeof(line), f)) { + linenum++; + if (!parse_prime(linenum, line, &dhg)) + continue; + BN_clear_free(dhg.g); + BN_clear_free(dhg.p); + + if (dhg.size > max || dhg.size < min) + continue; + + if ((dhg.size > wantbits && dhg.size < best) || + (dhg.size > best && best < wantbits)) { + best = dhg.size; + bestcount = 0; + } + if (dhg.size == best) + bestcount++; + } + rewind(f); + + if (bestcount == 0) { + fclose(f); + logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES); + return (dh_new_group14()); + } + + linenum = 0; + which = arc4random() % bestcount; + while (fgets(line, sizeof(line), f)) { + if (!parse_prime(linenum, line, &dhg)) + continue; + if ((dhg.size > max || dhg.size < min) || + dhg.size != best || + linenum++ != which) { + BN_clear_free(dhg.g); + BN_clear_free(dhg.p); + continue; + } + break; + } + fclose(f); + if (linenum != which+1) + fatal("WARNING: line %d disappeared in %s, giving up", + which, _PATH_DH_PRIMES); + + return (dh_new_group(dhg.g, dhg.p)); +} + +/* diffie-hellman-groupN-sha1 */ + +int +dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) +{ + int i; + int n = BN_num_bits(dh_pub); + int bits_set = 0; + + if (dh_pub->neg) { + logit("invalid public DH value: negativ"); + return 0; + } + for (i = 0; i <= n; i++) + if (BN_is_bit_set(dh_pub, i)) + bits_set++; + debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); + + /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ + if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1)) + return 1; + logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); + return 0; +} + +void +dh_gen_key(DH *dh, int need) +{ + int i, bits_set, tries = 0; + + if (dh->p == NULL) + fatal("dh_gen_key: dh->p == NULL"); + if (need > INT_MAX / 2 || 2 * need >= BN_num_bits(dh->p)) + fatal("dh_gen_key: group too small: %d (2*need %d)", + BN_num_bits(dh->p), 2*need); + do { + if (dh->priv_key != NULL) + BN_clear_free(dh->priv_key); + if ((dh->priv_key = BN_new()) == NULL) + fatal("dh_gen_key: BN_new failed"); + /* generate a 2*need bits random private exponent */ + if (!BN_rand(dh->priv_key, 2*need, 0, 0)) + fatal("dh_gen_key: BN_rand failed"); + if (DH_generate_key(dh) == 0) + fatal("DH_generate_key"); + for (i = 0, bits_set = 0; i <= BN_num_bits(dh->priv_key); i++) + if (BN_is_bit_set(dh->priv_key, i)) + bits_set++; + debug2("dh_gen_key: priv key bits set: %d/%d", + bits_set, BN_num_bits(dh->priv_key)); + if (tries++ > 10) + fatal("dh_gen_key: too many bad keys: giving up"); + } while (!dh_pub_is_valid(dh, dh->pub_key)); +} + +DH * +dh_new_group_asc(const char *gen, const char *modulus) +{ + DH *dh; + + if ((dh = DH_new()) == NULL) + fatal("dh_new_group_asc: DH_new"); + + if (BN_hex2bn(&dh->p, modulus) == 0) + fatal("BN_hex2bn p"); + if (BN_hex2bn(&dh->g, gen) == 0) + fatal("BN_hex2bn g"); + + return (dh); +} + +/* + * This just returns the group, we still need to generate the exchange + * value. + */ + +DH * +dh_new_group(BIGNUM *gen, BIGNUM *modulus) +{ + DH *dh; + + if ((dh = DH_new()) == NULL) + fatal("dh_new_group: DH_new"); + dh->p = modulus; + dh->g = gen; + + return (dh); +} + +DH * +dh_new_group1(void) +{ + static char *gen = "2", *group1 = + "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" + "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" + "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" + "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" + "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" + "FFFFFFFF" "FFFFFFFF"; + + return (dh_new_group_asc(gen, group1)); +} + +DH * +dh_new_group14(void) +{ + static char *gen = "2", *group14 = + "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" + "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD" + "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245" + "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" + "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D" + "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F" + "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D" + "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B" + "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9" + "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510" + "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF"; + + return (dh_new_group_asc(gen, group14)); +} + +/* + * Estimates the group order for a Diffie-Hellman group that has an + * attack complexity approximately the same as O(2**bits). Estimate + * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) + */ + +int +dh_estimate(int bits) +{ + + if (bits <= 128) + return (1024); /* O(2**86) */ + if (bits <= 192) + return (2048); /* O(2**116) */ + return (4096); /* O(2**156) */ +} diff --git a/crypto/openssh-3.9p1/dh.h b/crypto/openssh-3.9p1/dh.h new file mode 100644 index 0000000000..723dd08e4f --- /dev/null +++ b/crypto/openssh-3.9p1/dh.h @@ -0,0 +1,49 @@ +/* $OpenBSD: dh.h,v 1.8 2004/06/13 12:53:24 djm Exp $ */ + +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef DH_H +#define DH_H + +struct dhgroup { + int size; + BIGNUM *g; + BIGNUM *p; +}; + +DH *choose_dh(int, int, int); +DH *dh_new_group_asc(const char *, const char *); +DH *dh_new_group(BIGNUM *, BIGNUM *); +DH *dh_new_group1(void); +DH *dh_new_group14(void); + +void dh_gen_key(DH *, int); +int dh_pub_is_valid(DH *, BIGNUM *); + +int dh_estimate(int); + +#define DH_GRP_MIN 1024 +#define DH_GRP_MAX 8192 + +#endif diff --git a/crypto/openssh-3.9p1/dispatch.c b/crypto/openssh-3.9p1/dispatch.c new file mode 100644 index 0000000000..c5ff65031f --- /dev/null +++ b/crypto/openssh-3.9p1/dispatch.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: dispatch.c,v 1.16 2003/04/08 20:21:28 itojun Exp $"); + +#include "ssh1.h" +#include "ssh2.h" +#include "log.h" +#include "dispatch.h" +#include "packet.h" +#include "compat.h" + +#define DISPATCH_MIN 0 +#define DISPATCH_MAX 255 + +dispatch_fn *dispatch[DISPATCH_MAX]; + +void +dispatch_protocol_error(int type, u_int32_t seq, void *ctxt) +{ + logit("dispatch_protocol_error: type %d seq %u", type, seq); + if (!compat20) + fatal("protocol error"); + packet_start(SSH2_MSG_UNIMPLEMENTED); + packet_put_int(seq); + packet_send(); + packet_write_wait(); +} +void +dispatch_protocol_ignore(int type, u_int32_t seq, void *ctxt) +{ + logit("dispatch_protocol_ignore: type %d seq %u", type, seq); +} +void +dispatch_init(dispatch_fn *dflt) +{ + u_int i; + for (i = 0; i < DISPATCH_MAX; i++) + dispatch[i] = dflt; +} +void +dispatch_range(u_int from, u_int to, dispatch_fn *fn) +{ + u_int i; + + for (i = from; i <= to; i++) { + if (i >= DISPATCH_MAX) + break; + dispatch[i] = fn; + } +} +void +dispatch_set(int type, dispatch_fn *fn) +{ + dispatch[type] = fn; +} +void +dispatch_run(int mode, int *done, void *ctxt) +{ + for (;;) { + int type; + u_int32_t seqnr; + + if (mode == DISPATCH_BLOCK) { + type = packet_read_seqnr(&seqnr); + } else { + type = packet_read_poll_seqnr(&seqnr); + if (type == SSH_MSG_NONE) + return; + } + if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL) + (*dispatch[type])(type, seqnr, ctxt); + else + packet_disconnect("protocol error: rcvd type %d", type); + if (done != NULL && *done) + return; + } +} diff --git a/crypto/openssh-3.9p1/dispatch.h b/crypto/openssh-3.9p1/dispatch.h new file mode 100644 index 0000000000..a82e2165b3 --- /dev/null +++ b/crypto/openssh-3.9p1/dispatch.h @@ -0,0 +1,38 @@ +/* $OpenBSD: dispatch.h,v 1.9 2002/01/11 13:39:36 markus Exp $ */ + +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +enum { + DISPATCH_BLOCK, + DISPATCH_NONBLOCK +}; + +typedef void dispatch_fn(int, u_int32_t, void *); + +void dispatch_init(dispatch_fn *); +void dispatch_set(int, dispatch_fn *); +void dispatch_range(u_int, u_int, dispatch_fn *); +void dispatch_run(int, int *, void *); +void dispatch_protocol_error(int, u_int32_t, void *); +void dispatch_protocol_ignore(int, u_int32_t, void *); diff --git a/crypto/openssh-3.9p1/dns.c b/crypto/openssh-3.9p1/dns.c new file mode 100644 index 0000000000..140ab60429 --- /dev/null +++ b/crypto/openssh-3.9p1/dns.c @@ -0,0 +1,275 @@ +/* $OpenBSD: dns.c,v 1.10 2004/06/21 17:36:31 avsm Exp $ */ + +/* + * Copyright (c) 2003 Wesley Griffin. All rights reserved. + * Copyright (c) 2003 Jakob Schlyter. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "includes.h" + +#include +#ifdef LWRES +#include +#include +#else /* LWRES */ +#include +#endif /* LWRES */ + +#include "xmalloc.h" +#include "key.h" +#include "dns.h" +#include "log.h" +#include "uuencode.h" + +extern char *__progname; +RCSID("$OpenBSD: dns.c,v 1.10 2004/06/21 17:36:31 avsm Exp $"); + +#ifndef LWRES +static const char *errset_text[] = { + "success", /* 0 ERRSET_SUCCESS */ + "out of memory", /* 1 ERRSET_NOMEMORY */ + "general failure", /* 2 ERRSET_FAIL */ + "invalid parameter", /* 3 ERRSET_INVAL */ + "name does not exist", /* 4 ERRSET_NONAME */ + "data does not exist", /* 5 ERRSET_NODATA */ +}; + +static const char * +dns_result_totext(unsigned int res) +{ + switch (res) { + case ERRSET_SUCCESS: + return errset_text[ERRSET_SUCCESS]; + case ERRSET_NOMEMORY: + return errset_text[ERRSET_NOMEMORY]; + case ERRSET_FAIL: + return errset_text[ERRSET_FAIL]; + case ERRSET_INVAL: + return errset_text[ERRSET_INVAL]; + case ERRSET_NONAME: + return errset_text[ERRSET_NONAME]; + case ERRSET_NODATA: + return errset_text[ERRSET_NODATA]; + default: + return "unknown error"; + } +} +#endif /* LWRES */ + + +/* + * Read SSHFP parameters from key buffer. + */ +static int +dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, + u_char **digest, u_int *digest_len, const Key *key) +{ + int success = 0; + + switch (key->type) { + case KEY_RSA: + *algorithm = SSHFP_KEY_RSA; + break; + case KEY_DSA: + *algorithm = SSHFP_KEY_DSA; + break; + default: + *algorithm = SSHFP_KEY_RESERVED; + } + + if (*algorithm) { + *digest_type = SSHFP_HASH_SHA1; + *digest = key_fingerprint_raw(key, SSH_FP_SHA1, digest_len); + success = 1; + } else { + *digest_type = SSHFP_HASH_RESERVED; + *digest = NULL; + *digest_len = 0; + success = 0; + } + + return success; +} + +/* + * Read SSHFP parameters from rdata buffer. + */ +static int +dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type, + u_char **digest, u_int *digest_len, u_char *rdata, int rdata_len) +{ + int success = 0; + + *algorithm = SSHFP_KEY_RESERVED; + *digest_type = SSHFP_HASH_RESERVED; + + if (rdata_len >= 2) { + *algorithm = rdata[0]; + *digest_type = rdata[1]; + *digest_len = rdata_len - 2; + + if (*digest_len > 0) { + *digest = (u_char *) xmalloc(*digest_len); + memcpy(*digest, rdata + 2, *digest_len); + } else { + *digest = NULL; + } + + success = 1; + } + + return success; +} + + +/* + * Verify the given hostname, address and host key using DNS. + * Returns 0 if lookup succeeds, -1 otherwise + */ +int +verify_host_key_dns(const char *hostname, struct sockaddr *address, + const Key *hostkey, int *flags) +{ + int counter; + int result; + struct rrsetinfo *fingerprints = NULL; + + u_int8_t hostkey_algorithm; + u_int8_t hostkey_digest_type; + u_char *hostkey_digest; + u_int hostkey_digest_len; + + u_int8_t dnskey_algorithm; + u_int8_t dnskey_digest_type; + u_char *dnskey_digest; + u_int dnskey_digest_len; + + *flags = 0; + + debug3("verify_hostkey_dns"); + if (hostkey == NULL) + fatal("No key to look up!"); + + result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, + DNS_RDATATYPE_SSHFP, 0, &fingerprints); + if (result) { + verbose("DNS lookup error: %s", dns_result_totext(result)); + return -1; + } + + if (fingerprints->rri_flags & RRSET_VALIDATED) { + *flags |= DNS_VERIFY_SECURE; + debug("found %d secure fingerprints in DNS", + fingerprints->rri_nrdatas); + } else { + debug("found %d insecure fingerprints in DNS", + fingerprints->rri_nrdatas); + } + + /* Initialize host key parameters */ + if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, + &hostkey_digest, &hostkey_digest_len, hostkey)) { + error("Error calculating host key fingerprint."); + freerrset(fingerprints); + return -1; + } + + if (fingerprints->rri_nrdatas) + *flags |= DNS_VERIFY_FOUND; + + for (counter = 0 ; counter < fingerprints->rri_nrdatas ; counter++) { + /* + * Extract the key from the answer. Ignore any badly + * formatted fingerprints. + */ + if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type, + &dnskey_digest, &dnskey_digest_len, + fingerprints->rri_rdatas[counter].rdi_data, + fingerprints->rri_rdatas[counter].rdi_length)) { + verbose("Error parsing fingerprint from DNS."); + continue; + } + + /* Check if the current key is the same as the given key */ + if (hostkey_algorithm == dnskey_algorithm && + hostkey_digest_type == dnskey_digest_type) { + + if (hostkey_digest_len == dnskey_digest_len && + memcmp(hostkey_digest, dnskey_digest, + hostkey_digest_len) == 0) { + + *flags |= DNS_VERIFY_MATCH; + } + } + } + + freerrset(fingerprints); + + if (*flags & DNS_VERIFY_FOUND) + if (*flags & DNS_VERIFY_MATCH) + debug("matching host key fingerprint found in DNS"); + else + debug("mismatching host key fingerprint found in DNS"); + else + debug("no host key fingerprint found in DNS"); + + return 0; +} + + +/* + * Export the fingerprint of a key as a DNS resource record + */ +int +export_dns_rr(const char *hostname, const Key *key, FILE *f, int generic) +{ + u_int8_t rdata_pubkey_algorithm = 0; + u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; + u_char *rdata_digest; + u_int rdata_digest_len; + + int i; + int success = 0; + + if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, + &rdata_digest, &rdata_digest_len, key)) { + + if (generic) + fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", hostname, + DNS_RDATATYPE_SSHFP, 2 + rdata_digest_len, + rdata_pubkey_algorithm, rdata_digest_type); + else + fprintf(f, "%s IN SSHFP %d %d ", hostname, + rdata_pubkey_algorithm, rdata_digest_type); + + for (i = 0; i < rdata_digest_len; i++) + fprintf(f, "%02x", rdata_digest[i]); + fprintf(f, "\n"); + success = 1; + } else { + error("dns_export_rr: unsupported algorithm"); + } + + return success; +} diff --git a/crypto/openssh-3.9p1/dns.h b/crypto/openssh-3.9p1/dns.h new file mode 100644 index 0000000000..c5da22ef61 --- /dev/null +++ b/crypto/openssh-3.9p1/dns.h @@ -0,0 +1,56 @@ +/* $OpenBSD: dns.h,v 1.5 2003/11/12 16:39:58 jakob Exp $ */ + +/* + * Copyright (c) 2003 Wesley Griffin. All rights reserved. + * Copyright (c) 2003 Jakob Schlyter. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "includes.h" + +#ifndef DNS_H +#define DNS_H + +enum sshfp_types { + SSHFP_KEY_RESERVED, + SSHFP_KEY_RSA, + SSHFP_KEY_DSA +}; + +enum sshfp_hashes { + SSHFP_HASH_RESERVED, + SSHFP_HASH_SHA1 +}; + +#define DNS_RDATACLASS_IN 1 +#define DNS_RDATATYPE_SSHFP 44 + +#define DNS_VERIFY_FOUND 0x00000001 +#define DNS_VERIFY_MATCH 0x00000002 +#define DNS_VERIFY_SECURE 0x00000004 + + +int verify_host_key_dns(const char *, struct sockaddr *, const Key *, int *); +int export_dns_rr(const char *, const Key *, FILE *, int); + +#endif /* DNS_H */ diff --git a/crypto/openssh-3.9p1/entropy.c b/crypto/openssh-3.9p1/entropy.c new file mode 100644 index 0000000000..0997174b62 --- /dev/null +++ b/crypto/openssh-3.9p1/entropy.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2001 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#include +#include + +#include "ssh.h" +#include "misc.h" +#include "xmalloc.h" +#include "atomicio.h" +#include "pathnames.h" +#include "log.h" + +/* + * Portable OpenSSH PRNG seeding: + * If OpenSSL has not "internally seeded" itself (e.g. pulled data from + * /dev/random), then we execute a "ssh-rand-helper" program which + * collects entropy and writes it to stdout. The child program must + * write at least RANDOM_SEED_SIZE bytes. The child is run with stderr + * attached, so error/debugging output should be visible. + * + * XXX: we should tell the child how many bytes we need. + */ + +RCSID("$Id: entropy.c,v 1.48 2003/11/21 12:56:47 djm Exp $"); + +#ifndef OPENSSL_PRNG_ONLY +#define RANDOM_SEED_SIZE 48 +static uid_t original_uid, original_euid; +#endif + +void +seed_rng(void) +{ +#ifndef OPENSSL_PRNG_ONLY + int devnull; + int p[2]; + pid_t pid; + int ret; + unsigned char buf[RANDOM_SEED_SIZE]; + mysig_t old_sigchld; + + if (RAND_status() == 1) { + debug3("RNG is ready, skipping seeding"); + return; + } + + debug3("Seeding PRNG from %s", SSH_RAND_HELPER); + + if ((devnull = open("/dev/null", O_RDWR)) == -1) + fatal("Couldn't open /dev/null: %s", strerror(errno)); + if (pipe(p) == -1) + fatal("pipe: %s", strerror(errno)); + + old_sigchld = signal(SIGCHLD, SIG_DFL); + if ((pid = fork()) == -1) + fatal("Couldn't fork: %s", strerror(errno)); + if (pid == 0) { + dup2(devnull, STDIN_FILENO); + dup2(p[1], STDOUT_FILENO); + /* Keep stderr open for errors */ + close(p[0]); + close(p[1]); + close(devnull); + + if (original_uid != original_euid && + ( seteuid(getuid()) == -1 || + setuid(original_uid) == -1) ) { + fprintf(stderr, "(rand child) setuid(%li): %s\n", + (long int)original_uid, strerror(errno)); + _exit(1); + } + + execl(SSH_RAND_HELPER, "ssh-rand-helper", NULL); + fprintf(stderr, "(rand child) Couldn't exec '%s': %s\n", + SSH_RAND_HELPER, strerror(errno)); + _exit(1); + } + + close(devnull); + close(p[1]); + + memset(buf, '\0', sizeof(buf)); + ret = atomicio(read, p[0], buf, sizeof(buf)); + if (ret == -1) + fatal("Couldn't read from ssh-rand-helper: %s", + strerror(errno)); + if (ret != sizeof(buf)) + fatal("ssh-rand-helper child produced insufficient data"); + + close(p[0]); + + if (waitpid(pid, &ret, 0) == -1) + fatal("Couldn't wait for ssh-rand-helper completion: %s", + strerror(errno)); + signal(SIGCHLD, old_sigchld); + + /* We don't mind if the child exits upon a SIGPIPE */ + if (!WIFEXITED(ret) && + (!WIFSIGNALED(ret) || WTERMSIG(ret) != SIGPIPE)) + fatal("ssh-rand-helper terminated abnormally"); + if (WEXITSTATUS(ret) != 0) + fatal("ssh-rand-helper exit with exit status %d", ret); + + RAND_add(buf, sizeof(buf), sizeof(buf)); + memset(buf, '\0', sizeof(buf)); + +#endif /* OPENSSL_PRNG_ONLY */ + if (RAND_status() != 1) + fatal("PRNG is not seeded"); +} + +void +init_rng(void) +{ + /* + * OpenSSL version numbers: MNNFFPPS: major minor fix patch status + * We match major, minor, fix and status (not patch) + */ + if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) + fatal("OpenSSL version mismatch. Built against %lx, you " + "have %lx", OPENSSL_VERSION_NUMBER, SSLeay()); + +#ifndef OPENSSL_PRNG_ONLY + if ((original_uid = getuid()) == -1) + fatal("getuid: %s", strerror(errno)); + if ((original_euid = geteuid()) == -1) + fatal("geteuid: %s", strerror(errno)); +#endif +} + diff --git a/crypto/openssh-3.9p1/entropy.h b/crypto/openssh-3.9p1/entropy.h new file mode 100644 index 0000000000..5f63c1f1fc --- /dev/null +++ b/crypto/openssh-3.9p1/entropy.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1999-2000 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $Id: entropy.h,v 1.4 2001/02/09 01:55:36 djm Exp $ */ + +#ifndef _RANDOMS_H +#define _RANDOMS_H + +void seed_rng(void); +void init_rng(void); + +#endif /* _RANDOMS_H */ diff --git a/crypto/openssh-3.9p1/envpass.sh b/crypto/openssh-3.9p1/envpass.sh new file mode 100644 index 0000000000..67044d421c --- /dev/null +++ b/crypto/openssh-3.9p1/envpass.sh @@ -0,0 +1,44 @@ +# $OpenBSD: envpass.sh,v 1.1 2004/04/27 09:47:30 djm Exp $ +# Placed in the Public Domain. + +tid="environment passing" + +# NB accepted env vars are in test-exec.sh (_XXX_TEST_* and _XXX_TEST) + +trace "pass env, don't accept" +verbose "test $tid: pass env, don't accept" +_TEST_ENV=blah ${SSH} -oSendEnv="*" -F $OBJ/ssh_proxy otherhost \ + '[ -z "$_TEST_ENV" ]' +r=$? +if [ $r -ne 0 ]; then + fail "environment found" +fi + +trace "don't pass env, accept" +verbose "test $tid: don't pass env, accept" +${SSH} -F $OBJ/ssh_proxy otherhost \ + '[ -z "$_XXX_TEST_A" -a -z "$_XXX_TEST_B" ]' +r=$? +if [ $r -ne 0 ]; then + fail "environment found" +fi + +trace "pass single env, accept single env" +verbose "test $tid: pass single env, accept single env" +_XXX_TEST=blah ${SSH} -oSendEnv="_XXX_TEST" -F $OBJ/ssh_proxy otherhost \ + '[ "x$_XXX_TEST" = "xblah" ]' +r=$? +if [ $r -ne 0 ]; then + fail "environment not found" +fi + +trace "pass multiple env, accept multiple env" +verbose "test $tid: pass multiple env, accept multiple env" +_XXX_TEST_A=1 _XXX_TEST_B=2 ${SSH} -oSendEnv="_XXX_TEST_*" \ + -F $OBJ/ssh_proxy otherhost \ + '[ "x$_XXX_TEST_A" = "x1" -a "x$_XXX_TEST_B" = "x2" ]' +r=$? +if [ $r -ne 0 ]; then + fail "environment not found" +fi + diff --git a/crypto/openssh-3.9p1/fatal.c b/crypto/openssh-3.9p1/fatal.c new file mode 100644 index 0000000000..ae1aaac6ed --- /dev/null +++ b/crypto/openssh-3.9p1/fatal.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: fatal.c,v 1.2 2003/09/23 20:17:11 markus Exp $"); + +#include "log.h" + +/* Fatal messages. This function never returns. */ + +void +fatal(const char *fmt,...) +{ + va_list args; + va_start(args, fmt); + do_log(SYSLOG_LEVEL_FATAL, fmt, args); + va_end(args); + cleanup_exit(255); +} diff --git a/crypto/openssh-3.9p1/getput.h b/crypto/openssh-3.9p1/getput.h new file mode 100644 index 0000000000..20cf8f20b3 --- /dev/null +++ b/crypto/openssh-3.9p1/getput.h @@ -0,0 +1,58 @@ +/* $OpenBSD: getput.h,v 1.8 2002/03/04 17:27:39 stevesk Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Macros for storing and retrieving data in msb first and lsb first order. + * + * 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". + */ + +#ifndef GETPUT_H +#define GETPUT_H + +/*------------ macros for storing/extracting msb first words -------------*/ + +#define GET_64BIT(cp) (((u_int64_t)(u_char)(cp)[0] << 56) | \ + ((u_int64_t)(u_char)(cp)[1] << 48) | \ + ((u_int64_t)(u_char)(cp)[2] << 40) | \ + ((u_int64_t)(u_char)(cp)[3] << 32) | \ + ((u_int64_t)(u_char)(cp)[4] << 24) | \ + ((u_int64_t)(u_char)(cp)[5] << 16) | \ + ((u_int64_t)(u_char)(cp)[6] << 8) | \ + ((u_int64_t)(u_char)(cp)[7])) + +#define GET_32BIT(cp) (((u_long)(u_char)(cp)[0] << 24) | \ + ((u_long)(u_char)(cp)[1] << 16) | \ + ((u_long)(u_char)(cp)[2] << 8) | \ + ((u_long)(u_char)(cp)[3])) + +#define GET_16BIT(cp) (((u_long)(u_char)(cp)[0] << 8) | \ + ((u_long)(u_char)(cp)[1])) + +#define PUT_64BIT(cp, value) do { \ + (cp)[0] = (value) >> 56; \ + (cp)[1] = (value) >> 48; \ + (cp)[2] = (value) >> 40; \ + (cp)[3] = (value) >> 32; \ + (cp)[4] = (value) >> 24; \ + (cp)[5] = (value) >> 16; \ + (cp)[6] = (value) >> 8; \ + (cp)[7] = (value); } while (0) + +#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) + +#endif /* GETPUT_H */ diff --git a/crypto/openssh-3.9p1/groupaccess.c b/crypto/openssh-3.9p1/groupaccess.c new file mode 100644 index 0000000000..f50879f83a --- /dev/null +++ b/crypto/openssh-3.9p1/groupaccess.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: groupaccess.c,v 1.6 2003/04/08 20:21:28 itojun Exp $"); + +#include "groupaccess.h" +#include "xmalloc.h" +#include "match.h" +#include "log.h" + +static int ngroups; +static char **groups_byname; + +/* + * Initialize group access list for user with primary (base) and + * supplementary groups. Return the number of groups in the list. + */ +int +ga_init(const char *user, gid_t base) +{ + gid_t *groups_bygid; + int i, j; + struct group *gr; + + if (ngroups > 0) + ga_free(); + + ngroups = NGROUPS_MAX; +#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) + ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX)); +#endif + + groups_bygid = xmalloc(ngroups * sizeof(*groups_bygid)); + groups_byname = xmalloc(ngroups * sizeof(*groups_byname)); + + if (getgrouplist(user, base, groups_bygid, &ngroups) == -1) + logit("getgrouplist: groups list too small"); + for (i = 0, j = 0; i < ngroups; i++) + if ((gr = getgrgid(groups_bygid[i])) != NULL) + groups_byname[j++] = xstrdup(gr->gr_name); + xfree(groups_bygid); + return (ngroups = j); +} + +/* + * Return 1 if one of user's groups is contained in groups. + * Return 0 otherwise. Use match_pattern() for string comparison. + */ +int +ga_match(char * const *groups, int n) +{ + int i, j; + + for (i = 0; i < ngroups; i++) + for (j = 0; j < n; j++) + if (match_pattern(groups_byname[i], groups[j])) + return 1; + return 0; +} + +/* + * Free memory allocated for group access list. + */ +void +ga_free(void) +{ + int i; + + if (ngroups > 0) { + for (i = 0; i < ngroups; i++) + xfree(groups_byname[i]); + ngroups = 0; + xfree(groups_byname); + } +} diff --git a/crypto/openssh-3.9p1/groupaccess.h b/crypto/openssh-3.9p1/groupaccess.h new file mode 100644 index 0000000000..ede4805c2c --- /dev/null +++ b/crypto/openssh-3.9p1/groupaccess.h @@ -0,0 +1,36 @@ +/* $OpenBSD: groupaccess.h,v 1.4 2001/06/26 17:27:23 markus Exp $ */ + +/* + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GROUPACCESS_H +#define GROUPACCESS_H + +#include + +int ga_init(const char *, gid_t); +int ga_match(char * const *, int); +void ga_free(void); + +#endif diff --git a/crypto/openssh-3.9p1/gss-genr.c b/crypto/openssh-3.9p1/gss-genr.c new file mode 100644 index 0000000000..3f5727b3ed --- /dev/null +++ b/crypto/openssh-3.9p1/gss-genr.c @@ -0,0 +1,281 @@ +/* $OpenBSD: gss-genr.c,v 1.3 2003/11/21 11:57:03 djm Exp $ */ + +/* + * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#ifdef GSSAPI + +#include "xmalloc.h" +#include "bufaux.h" +#include "compat.h" +#include "log.h" +#include "monitor_wrap.h" +#include "ssh2.h" + +#include "ssh-gss.h" + +extern u_char *session_id2; +extern u_int session_id2_len; + +/* Check that the OID in a data stream matches that in the context */ +int +ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) +{ + return (ctx != NULL && ctx->oid != GSS_C_NO_OID && + ctx->oid->length == len && + memcmp(ctx->oid->elements, data, len) == 0); +} + +/* Set the contexts OID from a data stream */ +void +ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len) +{ + if (ctx->oid != GSS_C_NO_OID) { + xfree(ctx->oid->elements); + xfree(ctx->oid); + } + ctx->oid = xmalloc(sizeof(gss_OID_desc)); + ctx->oid->length = len; + ctx->oid->elements = xmalloc(len); + memcpy(ctx->oid->elements, data, len); +} + +/* Set the contexts OID */ +void +ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid) +{ + ssh_gssapi_set_oid_data(ctx, oid->elements, oid->length); +} + +/* All this effort to report an error ... */ +void +ssh_gssapi_error(Gssctxt *ctxt) +{ + debug("%s", ssh_gssapi_last_error(ctxt, NULL, NULL)); +} + +char * +ssh_gssapi_last_error(Gssctxt *ctxt, + OM_uint32 *major_status, OM_uint32 *minor_status) +{ + OM_uint32 lmin; + gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; + OM_uint32 ctx; + Buffer b; + char *ret; + + buffer_init(&b); + + if (major_status != NULL) + *major_status = ctxt->major; + if (minor_status != NULL) + *minor_status = ctxt->minor; + + ctx = 0; + /* The GSSAPI error */ + do { + gss_display_status(&lmin, ctxt->major, + GSS_C_GSS_CODE, GSS_C_NULL_OID, &ctx, &msg); + + buffer_append(&b, msg.value, msg.length); + buffer_put_char(&b, '\n'); + + gss_release_buffer(&lmin, &msg); + } while (ctx != 0); + + /* The mechanism specific error */ + do { + gss_display_status(&lmin, ctxt->minor, + GSS_C_MECH_CODE, GSS_C_NULL_OID, &ctx, &msg); + + buffer_append(&b, msg.value, msg.length); + buffer_put_char(&b, '\n'); + + gss_release_buffer(&lmin, &msg); + } while (ctx != 0); + + buffer_put_char(&b, '\0'); + ret = xmalloc(buffer_len(&b)); + buffer_get(&b, ret, buffer_len(&b)); + buffer_free(&b); + return (ret); +} + +/* + * Initialise our GSSAPI context. We use this opaque structure to contain all + * of the data which both the client and server need to persist across + * {accept,init}_sec_context calls, so that when we do it from the userauth + * stuff life is a little easier + */ +void +ssh_gssapi_build_ctx(Gssctxt **ctx) +{ + *ctx = xmalloc(sizeof (Gssctxt)); + (*ctx)->major = 0; + (*ctx)->minor = 0; + (*ctx)->context = GSS_C_NO_CONTEXT; + (*ctx)->name = GSS_C_NO_NAME; + (*ctx)->oid = GSS_C_NO_OID; + (*ctx)->creds = GSS_C_NO_CREDENTIAL; + (*ctx)->client = GSS_C_NO_NAME; + (*ctx)->client_creds = GSS_C_NO_CREDENTIAL; +} + +/* Delete our context, providing it has been built correctly */ +void +ssh_gssapi_delete_ctx(Gssctxt **ctx) +{ + OM_uint32 ms; + + if ((*ctx) == NULL) + return; + if ((*ctx)->context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER); + if ((*ctx)->name != GSS_C_NO_NAME) + gss_release_name(&ms, &(*ctx)->name); + if ((*ctx)->oid != GSS_C_NO_OID) { + xfree((*ctx)->oid->elements); + xfree((*ctx)->oid); + (*ctx)->oid = GSS_C_NO_OID; + } + if ((*ctx)->creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&ms, &(*ctx)->creds); + if ((*ctx)->client != GSS_C_NO_NAME) + gss_release_name(&ms, &(*ctx)->client); + if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&ms, &(*ctx)->client_creds); + + xfree(*ctx); + *ctx = NULL; +} + +/* + * Wrapper to init_sec_context + * Requires that the context contains: + * oid + * server name (from ssh_gssapi_import_name) + */ +OM_uint32 +ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, + gss_buffer_desc* send_tok, OM_uint32 *flags) +{ + int deleg_flag = 0; + + if (deleg_creds) { + deleg_flag = GSS_C_DELEG_FLAG; + debug("Delegating credentials"); + } + + ctx->major = gss_init_sec_context(&ctx->minor, + GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid, + GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, + 0, NULL, recv_tok, NULL, send_tok, flags, NULL); + + if (GSS_ERROR(ctx->major)) + ssh_gssapi_error(ctx); + + return (ctx->major); +} + +/* Create a service name for the given host */ +OM_uint32 +ssh_gssapi_import_name(Gssctxt *ctx, const char *host) +{ + gss_buffer_desc gssbuf; + + gssbuf.length = sizeof("host@") + strlen(host); + gssbuf.value = xmalloc(gssbuf.length); + snprintf(gssbuf.value, gssbuf.length, "host@%s", host); + + if ((ctx->major = gss_import_name(&ctx->minor, + &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) + ssh_gssapi_error(ctx); + + xfree(gssbuf.value); + return (ctx->major); +} + +/* Acquire credentials for a server running on the current host. + * Requires that the context structure contains a valid OID + */ + +/* Returns a GSSAPI error code */ +OM_uint32 +ssh_gssapi_acquire_cred(Gssctxt *ctx) +{ + OM_uint32 status; + char lname[MAXHOSTNAMELEN]; + gss_OID_set oidset; + + gss_create_empty_oid_set(&status, &oidset); + gss_add_oid_set_member(&status, ctx->oid, &oidset); + + if (gethostname(lname, MAXHOSTNAMELEN)) + return (-1); + + if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname))) + return (ctx->major); + + if ((ctx->major = gss_acquire_cred(&ctx->minor, + ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL))) + ssh_gssapi_error(ctx); + + gss_release_oid_set(&status, &oidset); + return (ctx->major); +} + +OM_uint32 +ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) +{ + if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, + GSS_C_QOP_DEFAULT, buffer, hash))) + ssh_gssapi_error(ctx); + + return (ctx->major); +} + +void +ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service, + const char *context) +{ + buffer_init(b); + buffer_put_string(b, session_id2, session_id2_len); + buffer_put_char(b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(b, user); + buffer_put_cstring(b, service); + buffer_put_cstring(b, context); +} + +OM_uint32 +ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) { + if (*ctx) + ssh_gssapi_delete_ctx(ctx); + ssh_gssapi_build_ctx(ctx); + ssh_gssapi_set_oid(*ctx, oid); + return (ssh_gssapi_acquire_cred(*ctx)); +} + +#endif /* GSSAPI */ diff --git a/crypto/openssh-3.9p1/gss-serv-krb5.c b/crypto/openssh-3.9p1/gss-serv-krb5.c new file mode 100644 index 0000000000..91d87f798f --- /dev/null +++ b/crypto/openssh-3.9p1/gss-serv-krb5.c @@ -0,0 +1,218 @@ +/* $OpenBSD: gss-serv-krb5.c,v 1.3 2004/07/21 10:36:23 djm Exp $ */ + +/* + * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#ifdef GSSAPI +#ifdef KRB5 + +#include "auth.h" +#include "xmalloc.h" +#include "log.h" +#include "servconf.h" + +#include "ssh-gss.h" + +extern ServerOptions options; + +#ifdef HEIMDAL +# include +#else +# ifdef HAVE_GSSAPI_KRB5 +# include +# elif HAVE_GSSAPI_GSSAPI_KRB5 +# include +# endif +#endif + +static krb5_context krb_context = NULL; + +/* Initialise the krb5 library, for the stuff that GSSAPI won't do */ + +static int +ssh_gssapi_krb5_init(void) +{ + krb5_error_code problem; + + if (krb_context != NULL) + return 1; + + problem = krb5_init_context(&krb_context); + if (problem) { + logit("Cannot initialize krb5 context"); + return 0; + } +#ifdef KRB5_INIT_ETS + krb5_init_ets(krb_context); +#endif + + return 1; +} + +/* Check if this user is OK to login. This only works with krb5 - other + * GSSAPI mechanisms will need their own. + * Returns true if the user is OK to log in, otherwise returns 0 + */ + +static int +ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +{ + krb5_principal princ; + int retval; + + if (ssh_gssapi_krb5_init() == 0) + return 0; + + if ((retval = krb5_parse_name(krb_context, client->exportedname.value, + &princ))) { + logit("krb5_parse_name(): %.100s", + krb5_get_err_text(krb_context, retval)); + return 0; + } + if (krb5_kuserok(krb_context, princ, name)) { + retval = 1; + logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", + name, (char *)client->displayname.value); + } else + retval = 0; + + krb5_free_principal(krb_context, princ); + return retval; +} + + +/* This writes out any forwarded credentials from the structure populated + * during userauth. Called after we have setuid to the user */ + +static void +ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +{ + krb5_ccache ccache; + krb5_error_code problem; + krb5_principal princ; + OM_uint32 maj_status, min_status; + int len; + + if (client->creds == NULL) { + debug("No credentials stored"); + return; + } + + if (ssh_gssapi_krb5_init() == 0) + return; + +#ifdef HEIMDAL + if ((problem = krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache))) { + logit("krb5_cc_gen_new(): %.100s", + krb5_get_err_text(krb_context, problem)); + return; + } +#else + { + int tmpfd; + char ccname[40]; + mode_t old_umask; + + snprintf(ccname, sizeof(ccname), + "FILE:/tmp/krb5cc_%d_XXXXXX", geteuid()); + + old_umask = umask(0177); + tmpfd = mkstemp(ccname + strlen("FILE:")); + umask(old_umask); + if (tmpfd == -1) { + logit("mkstemp(): %.100s", strerror(errno)); + problem = errno; + return; + } + if (fchmod(tmpfd, S_IRUSR | S_IWUSR) == -1) { + logit("fchmod(): %.100s", strerror(errno)); + close(tmpfd); + problem = errno; + return; + } + close(tmpfd); + if ((problem = krb5_cc_resolve(krb_context, ccname, &ccache))) { + logit("krb5_cc_resolve(): %.100s", + krb5_get_err_text(krb_context, problem)); + return; + } + } +#endif /* #ifdef HEIMDAL */ + + if ((problem = krb5_parse_name(krb_context, + client->exportedname.value, &princ))) { + logit("krb5_parse_name(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_cc_destroy(krb_context, ccache); + return; + } + + if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) { + logit("krb5_cc_initialize(): %.100s", + krb5_get_err_text(krb_context, problem)); + krb5_free_principal(krb_context, princ); + krb5_cc_destroy(krb_context, ccache); + return; + } + + krb5_free_principal(krb_context, princ); + + if ((maj_status = gss_krb5_copy_ccache(&min_status, + client->creds, ccache))) { + logit("gss_krb5_copy_ccache() failed"); + krb5_cc_destroy(krb_context, ccache); + return; + } + + client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); + client->store.envvar = "KRB5CCNAME"; + len = strlen(client->store.filename) + 6; + client->store.envval = xmalloc(len); + snprintf(client->store.envval, len, "FILE:%s", client->store.filename); + +#ifdef USE_PAM + if (options.use_pam) + do_pam_putenv(client->store.envvar, client->store.envval); +#endif + + krb5_cc_close(krb_context, ccache); + + return; +} + +ssh_gssapi_mech gssapi_kerberos_mech = { + "toWM5Slw5Ew8Mqkay+al2g==", + "Kerberos", + {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, + NULL, + &ssh_gssapi_krb5_userok, + NULL, + &ssh_gssapi_krb5_storecreds +}; + +#endif /* KRB5 */ + +#endif /* GSSAPI */ diff --git a/crypto/openssh-3.9p1/gss-serv.c b/crypto/openssh-3.9p1/gss-serv.c new file mode 100644 index 0000000000..de32a3f2ea --- /dev/null +++ b/crypto/openssh-3.9p1/gss-serv.c @@ -0,0 +1,300 @@ +/* $OpenBSD: gss-serv.c,v 1.5 2003/11/17 11:06:07 markus Exp $ */ + +/* + * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#ifdef GSSAPI + +#include "bufaux.h" +#include "compat.h" +#include "auth.h" +#include "log.h" +#include "channels.h" +#include "session.h" +#include "servconf.h" +#include "monitor_wrap.h" +#include "xmalloc.h" +#include "getput.h" + +#include "ssh-gss.h" + +extern ServerOptions options; + +static ssh_gssapi_client gssapi_client = + { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, + GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}}; + +ssh_gssapi_mech gssapi_null_mech = + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; + +#ifdef KRB5 +extern ssh_gssapi_mech gssapi_kerberos_mech; +#endif + +ssh_gssapi_mech* supported_mechs[]= { +#ifdef KRB5 + &gssapi_kerberos_mech, +#endif + &gssapi_null_mech, +}; + +/* Unpriviledged */ +void +ssh_gssapi_supported_oids(gss_OID_set *oidset) +{ + int i = 0; + OM_uint32 min_status; + int present; + gss_OID_set supported; + + gss_create_empty_oid_set(&min_status, oidset); + gss_indicate_mechs(&min_status, &supported); + + while (supported_mechs[i]->name != NULL) { + if (GSS_ERROR(gss_test_oid_set_member(&min_status, + &supported_mechs[i]->oid, supported, &present))) + present = 0; + if (present) + gss_add_oid_set_member(&min_status, + &supported_mechs[i]->oid, oidset); + i++; + } +} + + +/* Wrapper around accept_sec_context + * Requires that the context contains: + * oid + * credentials (from ssh_gssapi_acquire_cred) + */ +/* Priviledged */ +OM_uint32 +ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok, + gss_buffer_desc *send_tok, OM_uint32 *flags) +{ + OM_uint32 status; + gss_OID mech; + + ctx->major = gss_accept_sec_context(&ctx->minor, + &ctx->context, ctx->creds, recv_tok, + GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech, + send_tok, flags, NULL, &ctx->client_creds); + + if (GSS_ERROR(ctx->major)) + ssh_gssapi_error(ctx); + + if (ctx->client_creds) + debug("Received some client credentials"); + else + debug("Got no client credentials"); + + status = ctx->major; + + /* Now, if we're complete and we have the right flags, then + * we flag the user as also having been authenticated + */ + + if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) && + (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) { + if (ssh_gssapi_getclient(ctx, &gssapi_client)) + fatal("Couldn't convert client name"); + } + + return (status); +} + +/* + * This parses an exported name, extracting the mechanism specific portion + * to use for ACL checking. It verifies that the name belongs the mechanism + * originally selected. + */ +static OM_uint32 +ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name) +{ + char *tok; + OM_uint32 offset; + OM_uint32 oidl; + + tok=ename->value; + + /* + * Check that ename is long enough for all of the fixed length + * header, and that the initial ID bytes are correct + */ + + if (ename->length<6 || memcmp(tok,"\x04\x01", 2)!=0) + return GSS_S_FAILURE; + + /* + * Extract the OID, and check it. Here GSSAPI breaks with tradition + * and does use the OID type and length bytes. To confuse things + * there are two lengths - the first including these, and the + * second without. + */ + + oidl = GET_16BIT(tok+2); /* length including next two bytes */ + oidl = oidl-2; /* turn it into the _real_ length of the variable OID */ + + /* + * Check the BER encoding for correct type and length, that the + * string is long enough and that the OID matches that in our context + */ + if (tok[4] != 0x06 || tok[5] != oidl || + ename->length < oidl+6 || + !ssh_gssapi_check_oid(ctx,tok+6,oidl)) + return GSS_S_FAILURE; + + offset = oidl+6; + + if (ename->length < offset+4) + return GSS_S_FAILURE; + + name->length = GET_32BIT(tok+offset); + offset += 4; + + if (ename->length < offset+name->length) + return GSS_S_FAILURE; + + name->value = xmalloc(name->length+1); + memcpy(name->value,tok+offset,name->length); + ((char *)name->value)[name->length] = 0; + + return GSS_S_COMPLETE; +} + +/* Extract the client details from a given context. This can only reliably + * be called once for a context */ + +/* Priviledged (called from accept_secure_ctx) */ +OM_uint32 +ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) +{ + int i = 0; + + gss_buffer_desc ename; + + client->mech = NULL; + + while (supported_mechs[i]->name != NULL) { + if (supported_mechs[i]->oid.length == ctx->oid->length && + (memcmp(supported_mechs[i]->oid.elements, + ctx->oid->elements, ctx->oid->length) == 0)) + client->mech = supported_mechs[i]; + i++; + } + + if (client->mech == NULL) + return GSS_S_FAILURE; + + if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, + &client->displayname, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + + if ((ctx->major = gss_export_name(&ctx->minor, ctx->client, + &ename))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } + + if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename, + &client->exportedname))) { + return (ctx->major); + } + + /* We can't copy this structure, so we just move the pointer to it */ + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; + return (ctx->major); +} + +/* As user - called on fatal/exit */ +void +ssh_gssapi_cleanup_creds(void) +{ + if (gssapi_client.store.filename != NULL) { + /* Unlink probably isn't sufficient */ + debug("removing gssapi cred file\"%s\"", gssapi_client.store.filename); + unlink(gssapi_client.store.filename); + } +} + +/* As user */ +void +ssh_gssapi_storecreds(void) +{ + if (gssapi_client.mech && gssapi_client.mech->storecreds) { + (*gssapi_client.mech->storecreds)(&gssapi_client); + } else + debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); +} + +/* This allows GSSAPI methods to do things to the childs environment based + * on the passed authentication process and credentials. + */ +/* As user */ +void +ssh_gssapi_do_child(char ***envp, u_int *envsizep) +{ + + if (gssapi_client.store.envvar != NULL && + gssapi_client.store.envval != NULL) { + + debug("Setting %s to %s", gssapi_client.store.envvar, + gssapi_client.store.envval); + child_set_env(envp, envsizep, gssapi_client.store.envvar, + gssapi_client.store.envval); + } +} + +/* Priviledged */ +int +ssh_gssapi_userok(char *user) +{ + if (gssapi_client.exportedname.length == 0 || + gssapi_client.exportedname.value == NULL) { + debug("No suitable client data"); + return 0; + } + if (gssapi_client.mech && gssapi_client.mech->userok) + return ((*gssapi_client.mech->userok)(&gssapi_client, user)); + else + debug("ssh_gssapi_userok: Unknown GSSAPI mechanism"); + return (0); +} + +/* Priviledged */ +OM_uint32 +ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) +{ + ctx->major = gss_verify_mic(&ctx->minor, ctx->context, + gssbuf, gssmic, NULL); + + return (ctx->major); +} + +#endif diff --git a/crypto/openssh-3.9p1/hostfile.c b/crypto/openssh-3.9p1/hostfile.c new file mode 100644 index 0000000000..88c0549127 --- /dev/null +++ b/crypto/openssh-3.9p1/hostfile.c @@ -0,0 +1,232 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Functions for manipulating the known hosts files. + * + * 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". + * + * + * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved. + * Copyright (c) 1999 Niels Provos. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: hostfile.c,v 1.32 2003/11/10 16:23:41 jakob Exp $"); + +#include "packet.h" +#include "match.h" +#include "key.h" +#include "hostfile.h" +#include "log.h" + +/* + * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the + * pointer over the key. Skips any whitespace at the beginning and at end. + */ + +int +hostfile_read_key(char **cpp, u_int *bitsp, Key *ret) +{ + char *cp; + + /* Skip leading whitespace. */ + for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) + ; + + if (key_read(ret, &cp) != 1) + return 0; + + /* Skip trailing whitespace. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Return results. */ + *cpp = cp; + *bitsp = key_size(ret); + return 1; +} + +static int +hostfile_check_key(int bits, const Key *key, const char *host, const char *filename, int linenum) +{ + if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) + return 1; + if (bits != BN_num_bits(key->rsa->n)) { + logit("Warning: %s, line %d: keysize mismatch for host %s: " + "actual %d vs. announced %d.", + filename, linenum, host, BN_num_bits(key->rsa->n), bits); + logit("Warning: replace %d with %d in %s, line %d.", + bits, BN_num_bits(key->rsa->n), filename, linenum); + } + return 1; +} + +/* + * 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. + * + * If no 'key' has been specified and a key of type 'keytype' is known + * for the specified host, then HOST_FOUND is returned. + */ + +static HostStatus +check_host_in_hostfile_by_key_or_type(const char *filename, + const char *host, const Key *key, int keytype, Key *found, int *numret) +{ + FILE *f; + char line[8192]; + int linenum = 0; + u_int kbits; + char *cp, *cp2; + HostStatus end_return; + + debug3("check_host_in_hostfile: filename %s", filename); + + /* Open the file containing the list of known hosts. */ + f = fopen(filename, "r"); + if (!f) + return HOST_NEW; + + /* + * 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 through the file. */ + while (fgets(line, sizeof(line), f)) { + cp = line; + linenum++; + + /* Skip any leading whitespace, comments and empty lines. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + 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, (u_int) (cp2 - cp)) != 1) + 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 (!hostfile_read_key(&cp, &kbits, found)) + continue; + + if (numret != NULL) + *numret = linenum; + + if (key == NULL) { + /* we found a key of the requested type */ + if (found->type == keytype) + return HOST_FOUND; + continue; + } + + if (!hostfile_check_key(kbits, found, host, filename, linenum)) + continue; + + /* Check if the current key is the same as the given key. */ + if (key_equal(key, found)) { + /* Ok, they match. */ + debug3("check_host_in_hostfile: match line %d", linenum); + 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. */ + fclose(f); + + /* + * Return either HOST_NEW or HOST_CHANGED, depending on whether we + * saw a different key for the host. + */ + return end_return; +} + +HostStatus +check_host_in_hostfile(const char *filename, const char *host, const Key *key, + Key *found, int *numret) +{ + if (key == NULL) + fatal("no key to look up"); + return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0, + found, numret)); +} + +int +lookup_key_in_hostfile_by_type(const char *filename, const char *host, + int keytype, Key *found, int *numret) +{ + return (check_host_in_hostfile_by_key_or_type(filename, host, NULL, + keytype, found, numret) == HOST_FOUND); +} + +/* + * 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, const Key *key) +{ + FILE *f; + int success = 0; + if (key == NULL) + return 1; /* XXX ? */ + f = fopen(filename, "a"); + if (!f) + return 0; + fprintf(f, "%s ", host); + if (key_write(key, f)) { + success = 1; + } else { + error("add_host_to_hostfile: saving key in %s failed", filename); + } + fprintf(f, "\n"); + fclose(f); + return success; +} diff --git a/crypto/openssh-3.9p1/hostfile.h b/crypto/openssh-3.9p1/hostfile.h new file mode 100644 index 0000000000..efcddc9f9c --- /dev/null +++ b/crypto/openssh-3.9p1/hostfile.h @@ -0,0 +1,28 @@ +/* $OpenBSD: hostfile.h,v 1.14 2003/11/10 16:23:41 jakob Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ +#ifndef HOSTFILE_H +#define HOSTFILE_H + +typedef enum { + HOST_OK, HOST_NEW, HOST_CHANGED, HOST_FOUND +} HostStatus; + +int hostfile_read_key(char **, u_int *, Key *); +HostStatus check_host_in_hostfile(const char *, const char *, + const Key *, Key *, int *); +int add_host_to_hostfile(const char *, const char *, const Key *); +int lookup_key_in_hostfile_by_type(const char *, const char *, + int, Key *, int *); + +#endif diff --git a/crypto/openssh-3.9p1/includes.h b/crypto/openssh-3.9p1/includes.h new file mode 100644 index 0000000000..3a6b4c32bb --- /dev/null +++ b/crypto/openssh-3.9p1/includes.h @@ -0,0 +1,204 @@ +/* $OpenBSD: includes.h,v 1.18 2004/06/13 15:03:02 djm Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * This file includes most of the needed system headers. + * + * 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". + */ + +#ifndef INCLUDES_H +#define INCLUDES_H + +#define RCSID(msg) \ +static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } + +#include "config.h" + +#include +#include +#include +#include /* For O_NONBLOCK */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIMITS_H +# include /* For PATH_MAX */ +#endif +#ifdef HAVE_GETOPT_H +# include +#endif +#ifdef HAVE_BSTRING_H +# include +#endif +#if defined(HAVE_GLOB_H) && defined(GLOB_HAS_ALTDIRFUNC) && \ + defined(GLOB_HAS_GL_MATCHC) +# include +#endif +#ifdef HAVE_NETGROUP_H +# include +#endif +#ifdef HAVE_ENDIAN_H +# include +#endif +#ifdef HAVE_TTYENT_H +# include +#endif +#ifdef HAVE_UTIME_H +# include +#endif +#ifdef HAVE_MAILLOCK_H +# include /* For _PATH_MAILDIR */ +#endif +#ifdef HAVE_NEXT +# include +#endif +#define __USE_GNU /* before unistd.h, activate extra prototypes for glibc */ +#include /* For STDIN_FILENO, etc */ +#include /* Struct winsize */ + +/* + *-*-nto-qnx needs these headers for strcasecmp and LASTLOG_FILE respectively + */ +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_LOGIN_H +# include +#endif + +#ifdef HAVE_UTMP_H +# include +#endif +#ifdef HAVE_UTMPX_H +# ifdef HAVE_TV_IN_UTMPX +# include +# endif +# include +#endif +#ifdef HAVE_LASTLOG_H +# include +#endif +#ifdef HAVE_PATHS_H +# include /* For _PATH_XXX */ +#endif + +#include +#include +#include +#include +#ifdef HAVE_SYS_TIME_H +# include /* For timersub */ +#endif +#include +#ifdef HAVE_SYS_SELECT_H +# include +#endif +#ifdef HAVE_SYS_BSDTTY_H +# include +#endif +#include /* For MAXPATHLEN and roundup() */ +#ifdef HAVE_SYS_UN_H +# include /* For sockaddr_un */ +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_SYS_BITYPES_H +# include /* For u_intXX_t */ +#endif +#ifdef HAVE_SYS_CDEFS_H +# include /* For __P() */ +#endif +#ifdef HAVE_SYS_STAT_H +# include /* For S_* constants and macros */ +#endif +#ifdef HAVE_SYS_SYSMACROS_H +# include /* For MIN, MAX, etc */ +#endif +#ifdef HAVE_SYS_MMAN_H +#include /* for MAP_ANONYMOUS */ +#endif +#ifdef HAVE_SYS_STRTIO_H +#include /* for TIOCCBRK on HP-UX */ +#endif +#if defined(HAVE_SYS_PTMS_H) && defined(HAVE_DEV_PTMX) +# if defined(HAVE_SYS_STREAM_H) +# include /* reqd for queue_t on Solaris 2.5.1 */ +# endif +#include /* for grantpt() and friends */ +#endif + +#include /* For typedefs */ +#include /* For IPv6 macros */ +#include /* For IPTOS macros */ +#include +#include +#if defined(HAVE_NETDB_H) +# include +#endif +#ifdef HAVE_RPC_TYPES_H +# include /* For INADDR_LOOPBACK */ +#endif +#ifdef USE_PAM +#if defined(HAVE_SECURITY_PAM_APPL_H) +# include +#elif defined (HAVE_PAM_PAM_APPL_H) +# include +#endif +#endif +#ifdef HAVE_READPASSPHRASE_H +# include +#endif + +#ifdef HAVE_IA_H +# include +#endif + +#ifdef HAVE_TMPDIR_H +# include +#endif + +#ifdef HAVE_LIBUTIL_H +# include /* Openpty on FreeBSD at least */ +#endif + +#if defined(KRB5) && defined(USE_AFS) +# include +# include +#endif + +/* + * On HP-UX 11.11, shadow.h and prot.h provide conflicting declarations + * of getspnam when _INCLUDE__STDC__ is defined, so we unset it here. + */ +#ifdef __hpux +# ifdef _INCLUDE__STDC__ +# undef _INCLUDE__STDC__ +# endif +#endif + +#include /* For OPENSSL_VERSION_NUMBER */ + +#include "defines.h" + +#include "version.h" +#include "openbsd-compat/openbsd-compat.h" +#include "openbsd-compat/bsd-nextstep.h" + +#include "entropy.h" + +#endif /* INCLUDES_H */ diff --git a/crypto/openssh-3.9p1/kex.c b/crypto/openssh-3.9p1/kex.c new file mode 100644 index 0000000000..a668346c39 --- /dev/null +++ b/crypto/openssh-3.9p1/kex.c @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: kex.c,v 1.60 2004/06/21 17:36:31 avsm Exp $"); + +#include + +#include "ssh2.h" +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" +#include "packet.h" +#include "compat.h" +#include "cipher.h" +#include "kex.h" +#include "key.h" +#include "log.h" +#include "mac.h" +#include "match.h" +#include "dispatch.h" +#include "monitor.h" + +#define KEX_COOKIE_LEN 16 + +/* prototype */ +static void kex_kexinit_finish(Kex *); +static void kex_choose_conf(Kex *); + +/* put algorithm proposal into buffer */ +static void +kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) +{ + int i; + + buffer_clear(b); + /* + * add a dummy cookie, the cookie will be overwritten by + * kex_send_kexinit(), each time a kexinit is set + */ + for (i = 0; i < KEX_COOKIE_LEN; i++) + buffer_put_char(b, 0); + for (i = 0; i < PROPOSAL_MAX; i++) + buffer_put_cstring(b, proposal[i]); + buffer_put_char(b, 0); /* first_kex_packet_follows */ + buffer_put_int(b, 0); /* uint32 reserved */ +} + +/* parse buffer and return algorithm proposal */ +static char ** +kex_buf2prop(Buffer *raw, int *first_kex_follows) +{ + Buffer b; + int i; + char **proposal; + + proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); + + buffer_init(&b); + buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); + /* skip cookie */ + for (i = 0; i < KEX_COOKIE_LEN; i++) + buffer_get_char(&b); + /* extract kex init proposal strings */ + for (i = 0; i < PROPOSAL_MAX; i++) { + proposal[i] = buffer_get_string(&b,NULL); + debug2("kex_parse_kexinit: %s", proposal[i]); + } + /* first kex follows / reserved */ + i = buffer_get_char(&b); + if (first_kex_follows != NULL) + *first_kex_follows = i; + debug2("kex_parse_kexinit: first_kex_follows %d ", i); + i = buffer_get_int(&b); + debug2("kex_parse_kexinit: reserved %d ", i); + buffer_free(&b); + return proposal; +} + +static void +kex_prop_free(char **proposal) +{ + int i; + + for (i = 0; i < PROPOSAL_MAX; i++) + xfree(proposal[i]); + xfree(proposal); +} + +static void +kex_protocol_error(int type, u_int32_t seq, void *ctxt) +{ + error("Hm, kex protocol error: type %d seq %u", type, seq); +} + +static void +kex_reset_dispatch(void) +{ + dispatch_range(SSH2_MSG_TRANSPORT_MIN, + SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); + dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); +} + +void +kex_finish(Kex *kex) +{ + kex_reset_dispatch(); + + packet_start(SSH2_MSG_NEWKEYS); + packet_send(); + /* packet_write_wait(); */ + debug("SSH2_MSG_NEWKEYS sent"); + + debug("expecting SSH2_MSG_NEWKEYS"); + packet_read_expect(SSH2_MSG_NEWKEYS); + packet_check_eom(); + debug("SSH2_MSG_NEWKEYS received"); + + kex->done = 1; + buffer_clear(&kex->peer); + /* buffer_clear(&kex->my); */ + kex->flags &= ~KEX_INIT_SENT; + xfree(kex->name); + kex->name = NULL; +} + +void +kex_send_kexinit(Kex *kex) +{ + u_int32_t rnd = 0; + u_char *cookie; + int i; + + if (kex == NULL) { + error("kex_send_kexinit: no kex, cannot rekey"); + return; + } + if (kex->flags & KEX_INIT_SENT) { + debug("KEX_INIT_SENT"); + return; + } + kex->done = 0; + + /* generate a random cookie */ + if (buffer_len(&kex->my) < KEX_COOKIE_LEN) + fatal("kex_send_kexinit: kex proposal too short"); + cookie = buffer_ptr(&kex->my); + for (i = 0; i < KEX_COOKIE_LEN; i++) { + if (i % 4 == 0) + rnd = arc4random(); + cookie[i] = rnd; + rnd >>= 8; + } + packet_start(SSH2_MSG_KEXINIT); + packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); + packet_send(); + debug("SSH2_MSG_KEXINIT sent"); + kex->flags |= KEX_INIT_SENT; +} + +void +kex_input_kexinit(int type, u_int32_t seq, void *ctxt) +{ + char *ptr; + int dlen; + int i; + Kex *kex = (Kex *)ctxt; + + debug("SSH2_MSG_KEXINIT received"); + if (kex == NULL) + fatal("kex_input_kexinit: no kex, cannot rekey"); + + ptr = packet_get_raw(&dlen); + buffer_append(&kex->peer, ptr, dlen); + + /* discard packet */ + for (i = 0; i < KEX_COOKIE_LEN; i++) + packet_get_char(); + for (i = 0; i < PROPOSAL_MAX; i++) + xfree(packet_get_string(NULL)); + (void) packet_get_char(); + (void) packet_get_int(); + packet_check_eom(); + + kex_kexinit_finish(kex); +} + +Kex * +kex_setup(char *proposal[PROPOSAL_MAX]) +{ + Kex *kex; + + kex = xmalloc(sizeof(*kex)); + memset(kex, 0, sizeof(*kex)); + buffer_init(&kex->peer); + buffer_init(&kex->my); + kex_prop2buf(&kex->my, proposal); + kex->done = 0; + + kex_send_kexinit(kex); /* we start */ + kex_reset_dispatch(); + + return kex; +} + +static void +kex_kexinit_finish(Kex *kex) +{ + if (!(kex->flags & KEX_INIT_SENT)) + kex_send_kexinit(kex); + + kex_choose_conf(kex); + + if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && + kex->kex[kex->kex_type] != NULL) { + (kex->kex[kex->kex_type])(kex); + } else { + fatal("Unsupported key exchange %d", kex->kex_type); + } +} + +static void +choose_enc(Enc *enc, char *client, char *server) +{ + char *name = match_list(client, server, NULL); + if (name == NULL) + fatal("no matching cipher found: client %s server %s", client, server); + if ((enc->cipher = cipher_by_name(name)) == NULL) + fatal("matching cipher is not supported: %s", name); + enc->name = name; + enc->enabled = 0; + enc->iv = NULL; + enc->key = NULL; + enc->key_len = cipher_keylen(enc->cipher); + enc->block_size = cipher_blocksize(enc->cipher); +} +static void +choose_mac(Mac *mac, char *client, char *server) +{ + char *name = match_list(client, server, NULL); + if (name == NULL) + fatal("no matching mac found: client %s server %s", client, server); + if (mac_init(mac, name) < 0) + fatal("unsupported mac %s", name); + /* truncate the key */ + if (datafellows & SSH_BUG_HMAC) + mac->key_len = 16; + mac->name = name; + mac->key = NULL; + mac->enabled = 0; +} +static void +choose_comp(Comp *comp, char *client, char *server) +{ + char *name = match_list(client, server, NULL); + if (name == NULL) + fatal("no matching comp found: client %s server %s", client, server); + if (strcmp(name, "zlib") == 0) { + comp->type = 1; + } else if (strcmp(name, "none") == 0) { + comp->type = 0; + } else { + fatal("unsupported comp %s", name); + } + comp->name = name; +} +static void +choose_kex(Kex *k, char *client, char *server) +{ + k->name = match_list(client, server, NULL); + if (k->name == NULL) + fatal("no kex alg"); + if (strcmp(k->name, KEX_DH1) == 0) { + k->kex_type = KEX_DH_GRP1_SHA1; + } else if (strcmp(k->name, KEX_DH14) == 0) { + k->kex_type = KEX_DH_GRP14_SHA1; + } else if (strcmp(k->name, KEX_DHGEX) == 0) { + k->kex_type = KEX_DH_GEX_SHA1; + } else + fatal("bad kex alg %s", k->name); +} +static void +choose_hostkeyalg(Kex *k, char *client, char *server) +{ + char *hostkeyalg = match_list(client, server, NULL); + if (hostkeyalg == NULL) + fatal("no hostkey alg"); + k->hostkey_type = key_type_from_name(hostkeyalg); + if (k->hostkey_type == KEY_UNSPEC) + fatal("bad hostkey alg '%s'", hostkeyalg); + xfree(hostkeyalg); +} + +static int +proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) +{ + static int check[] = { + PROPOSAL_KEX_ALGS, PROPOSAL_SERVER_HOST_KEY_ALGS, -1 + }; + int *idx; + char *p; + + for (idx = &check[0]; *idx != -1; idx++) { + if ((p = strchr(my[*idx], ',')) != NULL) + *p = '\0'; + if ((p = strchr(peer[*idx], ',')) != NULL) + *p = '\0'; + if (strcmp(my[*idx], peer[*idx]) != 0) { + debug2("proposal mismatch: my %s peer %s", + my[*idx], peer[*idx]); + return (0); + } + } + debug2("proposals match"); + return (1); +} + +static void +kex_choose_conf(Kex *kex) +{ + Newkeys *newkeys; + char **my, **peer; + char **cprop, **sprop; + int nenc, nmac, ncomp; + int mode; + int ctos; /* direction: if true client-to-server */ + int need; + int first_kex_follows, type; + + my = kex_buf2prop(&kex->my, NULL); + peer = kex_buf2prop(&kex->peer, &first_kex_follows); + + if (kex->server) { + cprop=peer; + sprop=my; + } else { + cprop=my; + sprop=peer; + } + + /* Algorithm Negotiation */ + for (mode = 0; mode < MODE_MAX; mode++) { + newkeys = xmalloc(sizeof(*newkeys)); + memset(newkeys, 0, sizeof(*newkeys)); + kex->newkeys[mode] = newkeys; + ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); + nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; + nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; + ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; + choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); + choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); + choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); + debug("kex: %s %s %s %s", + ctos ? "client->server" : "server->client", + newkeys->enc.name, + newkeys->mac.name, + newkeys->comp.name); + } + choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); + choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], + sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); + need = 0; + for (mode = 0; mode < MODE_MAX; mode++) { + newkeys = kex->newkeys[mode]; + if (need < newkeys->enc.key_len) + need = newkeys->enc.key_len; + if (need < newkeys->enc.block_size) + need = newkeys->enc.block_size; + if (need < newkeys->mac.key_len) + need = newkeys->mac.key_len; + } + /* XXX need runden? */ + kex->we_need = need; + + /* ignore the next message if the proposals do not match */ + if (first_kex_follows && !proposals_match(my, peer) && + !(datafellows & SSH_BUG_FIRSTKEX)) { + type = packet_read(); + debug2("skipping next packet (type %u)", type); + } + + kex_prop_free(my); + kex_prop_free(peer); +} + +static u_char * +derive_key(Kex *kex, int id, int need, u_char *hash, BIGNUM *shared_secret) +{ + Buffer b; + const EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + char c = id; + int have; + int mdsz = EVP_MD_size(evp_md); + u_char *digest = xmalloc(roundup(need, mdsz)); + + buffer_init(&b); + buffer_put_bignum2(&b, shared_secret); + + /* K1 = HASH(K || H || "A" || session_id) */ + EVP_DigestInit(&md, evp_md); + if (!(datafellows & SSH_BUG_DERIVEKEY)) + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestUpdate(&md, hash, mdsz); + EVP_DigestUpdate(&md, &c, 1); + EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); + EVP_DigestFinal(&md, digest, NULL); + + /* + * expand key: + * Kn = HASH(K || H || K1 || K2 || ... || Kn-1) + * Key = K1 || K2 || ... || Kn + */ + for (have = mdsz; need > have; have += mdsz) { + EVP_DigestInit(&md, evp_md); + if (!(datafellows & SSH_BUG_DERIVEKEY)) + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestUpdate(&md, hash, mdsz); + EVP_DigestUpdate(&md, digest, have); + EVP_DigestFinal(&md, digest + have, NULL); + } + buffer_free(&b); +#ifdef DEBUG_KEX + fprintf(stderr, "key '%c'== ", c); + dump_digest("key", digest, need); +#endif + return digest; +} + +Newkeys *current_keys[MODE_MAX]; + +#define NKEYS 6 +void +kex_derive_keys(Kex *kex, u_char *hash, BIGNUM *shared_secret) +{ + u_char *keys[NKEYS]; + int i, mode, ctos; + + for (i = 0; i < NKEYS; i++) + keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, shared_secret); + + debug2("kex_derive_keys"); + for (mode = 0; mode < MODE_MAX; mode++) { + current_keys[mode] = kex->newkeys[mode]; + kex->newkeys[mode] = NULL; + ctos = (!kex->server && mode == MODE_OUT) || (kex->server && mode == MODE_IN); + current_keys[mode]->enc.iv = keys[ctos ? 0 : 1]; + current_keys[mode]->enc.key = keys[ctos ? 2 : 3]; + current_keys[mode]->mac.key = keys[ctos ? 4 : 5]; + } +} + +Newkeys * +kex_get_newkeys(int mode) +{ + Newkeys *ret; + + ret = current_keys[mode]; + current_keys[mode] = NULL; + return ret; +} + +void +derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, + u_int8_t cookie[8], u_int8_t id[16]) +{ + const EVP_MD *evp_md = EVP_md5(); + EVP_MD_CTX md; + u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; + int len; + + EVP_DigestInit(&md, evp_md); + + len = BN_num_bytes(host_modulus); + if (len < (512 / 8) || len > sizeof(nbuf)) + fatal("%s: bad host modulus (len %d)", __func__, len); + BN_bn2bin(host_modulus, nbuf); + EVP_DigestUpdate(&md, nbuf, len); + + len = BN_num_bytes(server_modulus); + if (len < (512 / 8) || len > sizeof(nbuf)) + fatal("%s: bad server modulus (len %d)", __func__, len); + BN_bn2bin(server_modulus, nbuf); + EVP_DigestUpdate(&md, nbuf, len); + + EVP_DigestUpdate(&md, cookie, 8); + + EVP_DigestFinal(&md, obuf, NULL); + memcpy(id, obuf, 16); + + memset(nbuf, 0, sizeof(nbuf)); + memset(obuf, 0, sizeof(obuf)); + memset(&md, 0, sizeof(md)); +} + +#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) +void +dump_digest(char *msg, u_char *digest, int len) +{ + int i; + + fprintf(stderr, "%s\n", msg); + for (i = 0; i< len; i++) { + fprintf(stderr, "%02x", digest[i]); + if (i%32 == 31) + fprintf(stderr, "\n"); + else if (i%8 == 7) + fprintf(stderr, " "); + } + fprintf(stderr, "\n"); +} +#endif diff --git a/crypto/openssh-3.9p1/kex.h b/crypto/openssh-3.9p1/kex.h new file mode 100644 index 0000000000..d9e9d6522f --- /dev/null +++ b/crypto/openssh-3.9p1/kex.h @@ -0,0 +1,149 @@ +/* $OpenBSD: kex.h,v 1.35 2004/06/13 12:53:24 djm Exp $ */ + +/* + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef KEX_H +#define KEX_H + +#include +#include "buffer.h" +#include "cipher.h" +#include "key.h" + +#define KEX_DH1 "diffie-hellman-group1-sha1" +#define KEX_DH14 "diffie-hellman-group14-sha1" +#define KEX_DHGEX "diffie-hellman-group-exchange-sha1" + +enum kex_init_proposals { + PROPOSAL_KEX_ALGS, + PROPOSAL_SERVER_HOST_KEY_ALGS, + PROPOSAL_ENC_ALGS_CTOS, + PROPOSAL_ENC_ALGS_STOC, + PROPOSAL_MAC_ALGS_CTOS, + PROPOSAL_MAC_ALGS_STOC, + PROPOSAL_COMP_ALGS_CTOS, + PROPOSAL_COMP_ALGS_STOC, + PROPOSAL_LANG_CTOS, + PROPOSAL_LANG_STOC, + PROPOSAL_MAX +}; + +enum kex_modes { + MODE_IN, + MODE_OUT, + MODE_MAX +}; + +enum kex_exchange { + KEX_DH_GRP1_SHA1, + KEX_DH_GRP14_SHA1, + KEX_DH_GEX_SHA1, + KEX_MAX +}; + +#define KEX_INIT_SENT 0x0001 + +typedef struct Kex Kex; +typedef struct Mac Mac; +typedef struct Comp Comp; +typedef struct Enc Enc; +typedef struct Newkeys Newkeys; + +struct Enc { + char *name; + Cipher *cipher; + int enabled; + u_int key_len; + u_int block_size; + u_char *key; + u_char *iv; +}; +struct Mac { + char *name; + int enabled; + const EVP_MD *md; + int mac_len; + u_char *key; + int key_len; +}; +struct Comp { + int type; + int enabled; + char *name; +}; +struct Newkeys { + Enc enc; + Mac mac; + Comp comp; +}; +struct Kex { + u_char *session_id; + u_int session_id_len; + Newkeys *newkeys[MODE_MAX]; + int we_need; + int server; + char *name; + int hostkey_type; + int kex_type; + Buffer my; + Buffer peer; + int done; + int flags; + char *client_version_string; + char *server_version_string; + int (*verify_host_key)(Key *); + Key *(*load_host_key)(int); + int (*host_key_index)(Key *); + void (*kex[KEX_MAX])(Kex *); +}; + +Kex *kex_setup(char *[PROPOSAL_MAX]); +void kex_finish(Kex *); + +void kex_send_kexinit(Kex *); +void kex_input_kexinit(int, u_int32_t, void *); +void kex_derive_keys(Kex *, u_char *, BIGNUM *); + +Newkeys *kex_get_newkeys(int); + +void kexdh_client(Kex *); +void kexdh_server(Kex *); +void kexgex_client(Kex *); +void kexgex_server(Kex *); + +u_char * +kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, + BIGNUM *, BIGNUM *, BIGNUM *); +u_char * +kexgex_hash(char *, char *, char *, int, char *, int, u_char *, int, + int, int, int, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *); + +void +derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]); + +#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) +void dump_digest(char *, u_char *, int); +#endif + +#endif diff --git a/crypto/openssh-3.9p1/kexdh.c b/crypto/openssh-3.9p1/kexdh.c new file mode 100644 index 0000000000..4bbb7d1dba --- /dev/null +++ b/crypto/openssh-3.9p1/kexdh.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: kexdh.c,v 1.19 2003/02/16 17:09:57 markus Exp $"); + +#include + +#include "buffer.h" +#include "bufaux.h" +#include "ssh2.h" +#include "kex.h" + +u_char * +kex_dh_hash( + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + u_char *serverhostkeyblob, int sbloblen, + BIGNUM *client_dh_pub, + BIGNUM *server_dh_pub, + BIGNUM *shared_secret) +{ + Buffer b; + static u_char digest[EVP_MAX_MD_SIZE]; + const EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + + buffer_init(&b); + buffer_put_cstring(&b, client_version_string); + buffer_put_cstring(&b, server_version_string); + + /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ + buffer_put_int(&b, ckexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, ckexinit, ckexinitlen); + buffer_put_int(&b, skexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, skexinit, skexinitlen); + + buffer_put_string(&b, serverhostkeyblob, sbloblen); + buffer_put_bignum2(&b, client_dh_pub); + buffer_put_bignum2(&b, server_dh_pub); + buffer_put_bignum2(&b, shared_secret); + +#ifdef DEBUG_KEX + buffer_dump(&b); +#endif + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + + buffer_free(&b); + +#ifdef DEBUG_KEX + dump_digest("hash", digest, EVP_MD_size(evp_md)); +#endif + return digest; +} diff --git a/crypto/openssh-3.9p1/kexdhc.c b/crypto/openssh-3.9p1/kexdhc.c new file mode 100644 index 0000000000..f48bd46785 --- /dev/null +++ b/crypto/openssh-3.9p1/kexdhc.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: kexdhc.c,v 1.2 2004/06/13 12:53:24 djm Exp $"); + +#include "xmalloc.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" + +void +kexdh_client(Kex *kex) +{ + BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; + DH *dh; + Key *server_host_key; + u_char *server_host_key_blob = NULL, *signature = NULL; + u_char *kbuf, *hash; + u_int klen, kout, slen, sbloblen; + + /* generate and send 'e', client DH public key */ + switch (kex->kex_type) { + case KEX_DH_GRP1_SHA1: + dh = dh_new_group1(); + break; + case KEX_DH_GRP14_SHA1: + dh = dh_new_group14(); + break; + default: + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + dh_gen_key(dh, kex->we_need * 8); + packet_start(SSH2_MSG_KEXDH_INIT); + packet_put_bignum2(dh->pub_key); + packet_send(); + + debug("sending SSH2_MSG_KEXDH_INIT"); +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + + debug("expecting SSH2_MSG_KEXDH_REPLY"); + packet_read_expect(SSH2_MSG_KEXDH_REPLY); + + /* key, cert */ + server_host_key_blob = packet_get_string(&sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); + if (server_host_key == NULL) + fatal("cannot decode server_host_key_blob"); + if (server_host_key->type != kex->hostkey_type) + fatal("type mismatch for decoded server_host_key_blob"); + if (kex->verify_host_key == NULL) + fatal("cannot verify server_host_key"); + if (kex->verify_host_key(server_host_key) == -1) + fatal("server_host_key verification failed"); + + /* DH paramter f, server public DH key */ + if ((dh_server_pub = BN_new()) == NULL) + fatal("dh_server_pub == NULL"); + packet_get_bignum2(dh_server_pub); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_server_pub= "); + BN_print_fp(stderr, dh_server_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_server_pub)); +#endif + + /* signed H */ + signature = packet_get_string(&slen); + packet_check_eom(); + + if (!dh_pub_is_valid(dh, dh_server_pub)) + packet_disconnect("bad server public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_server_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + if ((shared_secret = BN_new()) == NULL) + fatal("kexdh_client: BN_new failed"); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + /* calc and verify H */ + hash = kex_dh_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->my), buffer_len(&kex->my), + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + server_host_key_blob, sbloblen, + dh->pub_key, + dh_server_pub, + shared_secret + ); + xfree(server_host_key_blob); + BN_clear_free(dh_server_pub); + DH_free(dh); + + if (key_verify(server_host_key, signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); + key_free(server_host_key); + xfree(signature); + + /* save session id */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + kex_finish(kex); +} diff --git a/crypto/openssh-3.9p1/kexdhs.c b/crypto/openssh-3.9p1/kexdhs.c new file mode 100644 index 0000000000..225e655926 --- /dev/null +++ b/crypto/openssh-3.9p1/kexdhs.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: kexdhs.c,v 1.2 2004/06/13 12:53:24 djm Exp $"); + +#include "xmalloc.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" +#include "monitor_wrap.h" + +void +kexdh_server(Kex *kex) +{ + BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; + DH *dh; + Key *server_host_key; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int sbloblen, klen, kout; + u_int slen; + + /* generate server DH public key */ + switch (kex->kex_type) { + case KEX_DH_GRP1_SHA1: + dh = dh_new_group1(); + break; + case KEX_DH_GRP14_SHA1: + dh = dh_new_group14(); + break; + default: + fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); + } + dh_gen_key(dh, kex->we_need * 8); + + debug("expecting SSH2_MSG_KEXDH_INIT"); + packet_read_expect(SSH2_MSG_KEXDH_INIT); + + if (kex->load_host_key == NULL) + fatal("Cannot load hostkey"); + server_host_key = kex->load_host_key(kex->hostkey_type); + if (server_host_key == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); + + /* key, cert */ + if ((dh_client_pub = BN_new()) == NULL) + fatal("dh_client_pub == NULL"); + packet_get_bignum2(dh_client_pub); + packet_check_eom(); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_client_pub= "); + BN_print_fp(stderr, dh_client_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_client_pub)); +#endif + +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + if (!dh_pub_is_valid(dh, dh_client_pub)) + packet_disconnect("bad client public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + if ((shared_secret = BN_new()) == NULL) + fatal("kexdh_server: BN_new failed"); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + + /* calc H */ + hash = kex_dh_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + buffer_ptr(&kex->my), buffer_len(&kex->my), + server_host_key_blob, sbloblen, + dh_client_pub, + dh->pub_key, + shared_secret + ); + BN_clear_free(dh_client_pub); + + /* save session id := H */ + /* XXX hashlen depends on KEX */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + /* sign H */ + /* XXX hashlen depends on KEX */ + PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20)); + + /* destroy_sensitive_data(); */ + + /* send server hostkey, DH pubkey 'f' and singed H */ + packet_start(SSH2_MSG_KEXDH_REPLY); + packet_put_string(server_host_key_blob, sbloblen); + packet_put_bignum2(dh->pub_key); /* f */ + packet_put_string(signature, slen); + packet_send(); + + xfree(signature); + xfree(server_host_key_blob); + /* have keys, free DH */ + DH_free(dh); + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + kex_finish(kex); +} diff --git a/crypto/openssh-3.9p1/kexgex.c b/crypto/openssh-3.9p1/kexgex.c new file mode 100644 index 0000000000..b0c39c8cbc --- /dev/null +++ b/crypto/openssh-3.9p1/kexgex.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: kexgex.c,v 1.23 2003/02/16 17:09:57 markus Exp $"); + +#include + +#include "buffer.h" +#include "bufaux.h" +#include "kex.h" +#include "ssh2.h" + +u_char * +kexgex_hash( + char *client_version_string, + char *server_version_string, + char *ckexinit, int ckexinitlen, + char *skexinit, int skexinitlen, + u_char *serverhostkeyblob, int sbloblen, + int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen, + BIGNUM *client_dh_pub, + BIGNUM *server_dh_pub, + BIGNUM *shared_secret) +{ + Buffer b; + static u_char digest[EVP_MAX_MD_SIZE]; + const EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + + buffer_init(&b); + buffer_put_cstring(&b, client_version_string); + buffer_put_cstring(&b, server_version_string); + + /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ + buffer_put_int(&b, ckexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, ckexinit, ckexinitlen); + buffer_put_int(&b, skexinitlen+1); + buffer_put_char(&b, SSH2_MSG_KEXINIT); + buffer_append(&b, skexinit, skexinitlen); + + buffer_put_string(&b, serverhostkeyblob, sbloblen); + if (min == -1 || max == -1) + buffer_put_int(&b, wantbits); + else { + buffer_put_int(&b, min); + buffer_put_int(&b, wantbits); + buffer_put_int(&b, max); + } + buffer_put_bignum2(&b, prime); + buffer_put_bignum2(&b, gen); + buffer_put_bignum2(&b, client_dh_pub); + buffer_put_bignum2(&b, server_dh_pub); + buffer_put_bignum2(&b, shared_secret); + +#ifdef DEBUG_KEXDH + buffer_dump(&b); +#endif + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); + EVP_DigestFinal(&md, digest, NULL); + + buffer_free(&b); + +#ifdef DEBUG_KEXDH + dump_digest("hash", digest, EVP_MD_size(evp_md)); +#endif + return digest; +} diff --git a/crypto/openssh-3.9p1/kexgexc.c b/crypto/openssh-3.9p1/kexgexc.c new file mode 100644 index 0000000000..0193183b95 --- /dev/null +++ b/crypto/openssh-3.9p1/kexgexc.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: kexgexc.c,v 1.2 2003/12/08 11:00:47 markus Exp $"); + +#include "xmalloc.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" +#include "compat.h" + +void +kexgex_client(Kex *kex) +{ + BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; + BIGNUM *p = NULL, *g = NULL; + Key *server_host_key; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int klen, kout, slen, sbloblen; + int min, max, nbits; + DH *dh; + + nbits = dh_estimate(kex->we_need * 8); + + if (datafellows & SSH_OLD_DHGEX) { + /* Old GEX request */ + packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); + packet_put_int(nbits); + min = DH_GRP_MIN; + max = DH_GRP_MAX; + + debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits); + } else { + /* New GEX request */ + min = DH_GRP_MIN; + max = DH_GRP_MAX; + packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); + packet_put_int(min); + packet_put_int(nbits); + packet_put_int(max); + + debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent", + min, nbits, max); + } +#ifdef DEBUG_KEXDH + fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", + min, nbits, max); +#endif + packet_send(); + + debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP"); + packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP); + + if ((p = BN_new()) == NULL) + fatal("BN_new"); + packet_get_bignum2(p); + if ((g = BN_new()) == NULL) + fatal("BN_new"); + packet_get_bignum2(g); + packet_check_eom(); + + if (BN_num_bits(p) < min || BN_num_bits(p) > max) + fatal("DH_GEX group out of range: %d !< %d !< %d", + min, BN_num_bits(p), max); + + dh = dh_new_group(g, p); + dh_gen_key(dh, kex->we_need * 8); + +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + + debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); + /* generate and send 'e', client DH public key */ + packet_start(SSH2_MSG_KEX_DH_GEX_INIT); + packet_put_bignum2(dh->pub_key); + packet_send(); + + debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY"); + packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY); + + /* key, cert */ + server_host_key_blob = packet_get_string(&sbloblen); + server_host_key = key_from_blob(server_host_key_blob, sbloblen); + if (server_host_key == NULL) + fatal("cannot decode server_host_key_blob"); + if (server_host_key->type != kex->hostkey_type) + fatal("type mismatch for decoded server_host_key_blob"); + if (kex->verify_host_key == NULL) + fatal("cannot verify server_host_key"); + if (kex->verify_host_key(server_host_key) == -1) + fatal("server_host_key verification failed"); + + /* DH paramter f, server public DH key */ + if ((dh_server_pub = BN_new()) == NULL) + fatal("dh_server_pub == NULL"); + packet_get_bignum2(dh_server_pub); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_server_pub= "); + BN_print_fp(stderr, dh_server_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_server_pub)); +#endif + + /* signed H */ + signature = packet_get_string(&slen); + packet_check_eom(); + + if (!dh_pub_is_valid(dh, dh_server_pub)) + packet_disconnect("bad server public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_server_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + if ((shared_secret = BN_new()) == NULL) + fatal("kexgex_client: BN_new failed"); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + if (datafellows & SSH_OLD_DHGEX) + min = max = -1; + + /* calc and verify H */ + hash = kexgex_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->my), buffer_len(&kex->my), + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + server_host_key_blob, sbloblen, + min, nbits, max, + dh->p, dh->g, + dh->pub_key, + dh_server_pub, + shared_secret + ); + /* have keys, free DH */ + DH_free(dh); + xfree(server_host_key_blob); + BN_clear_free(dh_server_pub); + + if (key_verify(server_host_key, signature, slen, hash, 20) != 1) + fatal("key_verify failed for server_host_key"); + key_free(server_host_key); + xfree(signature); + + /* save session id */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + + kex_finish(kex); +} diff --git a/crypto/openssh-3.9p1/kexgexs.c b/crypto/openssh-3.9p1/kexgexs.c new file mode 100644 index 0000000000..baebfcfb0f --- /dev/null +++ b/crypto/openssh-3.9p1/kexgexs.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2000 Niels Provos. All rights reserved. + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: kexgexs.c,v 1.1 2003/02/16 17:09:57 markus Exp $"); + +#include "xmalloc.h" +#include "key.h" +#include "kex.h" +#include "log.h" +#include "packet.h" +#include "dh.h" +#include "ssh2.h" +#include "compat.h" +#include "monitor_wrap.h" + +void +kexgex_server(Kex *kex) +{ + BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; + Key *server_host_key; + DH *dh; + u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; + u_int sbloblen, klen, kout, slen; + int min = -1, max = -1, nbits = -1, type; + + if (kex->load_host_key == NULL) + fatal("Cannot load hostkey"); + server_host_key = kex->load_host_key(kex->hostkey_type); + if (server_host_key == NULL) + fatal("Unsupported hostkey type %d", kex->hostkey_type); + + type = packet_read(); + switch (type) { + case SSH2_MSG_KEX_DH_GEX_REQUEST: + debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); + min = packet_get_int(); + nbits = packet_get_int(); + max = packet_get_int(); + min = MAX(DH_GRP_MIN, min); + max = MIN(DH_GRP_MAX, max); + break; + case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: + debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); + nbits = packet_get_int(); + min = DH_GRP_MIN; + max = DH_GRP_MAX; + /* unused for old GEX */ + break; + default: + fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); + } + packet_check_eom(); + + if (max < min || nbits < min || max < nbits) + fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", + min, nbits, max); + + /* Contact privileged parent */ + dh = PRIVSEP(choose_dh(min, nbits, max)); + if (dh == NULL) + packet_disconnect("Protocol error: no matching DH grp found"); + + debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); + packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); + packet_put_bignum2(dh->p); + packet_put_bignum2(dh->g); + packet_send(); + + /* flush */ + packet_write_wait(); + + /* Compute our exchange value in parallel with the client */ + dh_gen_key(dh, kex->we_need * 8); + + debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); + packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); + + /* key, cert */ + if ((dh_client_pub = BN_new()) == NULL) + fatal("dh_client_pub == NULL"); + packet_get_bignum2(dh_client_pub); + packet_check_eom(); + +#ifdef DEBUG_KEXDH + fprintf(stderr, "dh_client_pub= "); + BN_print_fp(stderr, dh_client_pub); + fprintf(stderr, "\n"); + debug("bits %d", BN_num_bits(dh_client_pub)); +#endif + +#ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, dh); + fprintf(stderr, "pub= "); + BN_print_fp(stderr, dh->pub_key); + fprintf(stderr, "\n"); +#endif + if (!dh_pub_is_valid(dh, dh_client_pub)) + packet_disconnect("bad client public DH value"); + + klen = DH_size(dh); + kbuf = xmalloc(klen); + kout = DH_compute_key(kbuf, dh_client_pub, dh); +#ifdef DEBUG_KEXDH + dump_digest("shared secret", kbuf, kout); +#endif + if ((shared_secret = BN_new()) == NULL) + fatal("kexgex_server: BN_new failed"); + BN_bin2bn(kbuf, kout, shared_secret); + memset(kbuf, 0, klen); + xfree(kbuf); + + key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); + + if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) + min = max = -1; + + /* calc H */ /* XXX depends on 'kex' */ + hash = kexgex_hash( + kex->client_version_string, + kex->server_version_string, + buffer_ptr(&kex->peer), buffer_len(&kex->peer), + buffer_ptr(&kex->my), buffer_len(&kex->my), + server_host_key_blob, sbloblen, + min, nbits, max, + dh->p, dh->g, + dh_client_pub, + dh->pub_key, + shared_secret + ); + BN_clear_free(dh_client_pub); + + /* save session id := H */ + /* XXX hashlen depends on KEX */ + if (kex->session_id == NULL) { + kex->session_id_len = 20; + kex->session_id = xmalloc(kex->session_id_len); + memcpy(kex->session_id, hash, kex->session_id_len); + } + + /* sign H */ + /* XXX hashlen depends on KEX */ + PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20)); + + /* destroy_sensitive_data(); */ + + /* send server hostkey, DH pubkey 'f' and singed H */ + debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); + packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); + packet_put_string(server_host_key_blob, sbloblen); + packet_put_bignum2(dh->pub_key); /* f */ + packet_put_string(signature, slen); + packet_send(); + + xfree(signature); + xfree(server_host_key_blob); + /* have keys, free DH */ + DH_free(dh); + + kex_derive_keys(kex, hash, shared_secret); + BN_clear_free(shared_secret); + + kex_finish(kex); +} diff --git a/crypto/openssh-3.9p1/key.c b/crypto/openssh-3.9p1/key.c new file mode 100644 index 0000000000..21b0869df0 --- /dev/null +++ b/crypto/openssh-3.9p1/key.c @@ -0,0 +1,858 @@ +/* + * read_bignum(): + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * + * 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". + * + * + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: key.c,v 1.56 2004/07/28 09:40:29 markus Exp $"); + +#include + +#include "xmalloc.h" +#include "key.h" +#include "rsa.h" +#include "uuencode.h" +#include "buffer.h" +#include "bufaux.h" +#include "log.h" + +Key * +key_new(int type) +{ + Key *k; + RSA *rsa; + DSA *dsa; + k = xmalloc(sizeof(*k)); + k->type = type; + k->flags = 0; + k->dsa = NULL; + k->rsa = NULL; + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((rsa = RSA_new()) == NULL) + fatal("key_new: RSA_new failed"); + if ((rsa->n = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((rsa->e = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + k->rsa = rsa; + break; + case KEY_DSA: + if ((dsa = DSA_new()) == NULL) + fatal("key_new: DSA_new failed"); + if ((dsa->p = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((dsa->q = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((dsa->g = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + if ((dsa->pub_key = BN_new()) == NULL) + fatal("key_new: BN_new failed"); + k->dsa = dsa; + break; + case KEY_UNSPEC: + break; + default: + fatal("key_new: bad key type %d", k->type); + break; + } + return k; +} + +Key * +key_new_private(int type) +{ + Key *k = key_new(type); + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((k->rsa->d = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->iqmp = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->q = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->p = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->dmq1 = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + if ((k->rsa->dmp1 = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + break; + case KEY_DSA: + if ((k->dsa->priv_key = BN_new()) == NULL) + fatal("key_new_private: BN_new failed"); + break; + case KEY_UNSPEC: + break; + default: + break; + } + return k; +} + +void +key_free(Key *k) +{ + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if (k->rsa != NULL) + RSA_free(k->rsa); + k->rsa = NULL; + break; + case KEY_DSA: + if (k->dsa != NULL) + DSA_free(k->dsa); + k->dsa = NULL; + break; + case KEY_UNSPEC: + break; + default: + fatal("key_free: bad key type %d", k->type); + break; + } + xfree(k); +} + +int +key_equal(const Key *a, const Key *b) +{ + if (a == NULL || b == NULL || a->type != b->type) + return 0; + switch (a->type) { + case KEY_RSA1: + case KEY_RSA: + return a->rsa != NULL && b->rsa != NULL && + BN_cmp(a->rsa->e, b->rsa->e) == 0 && + BN_cmp(a->rsa->n, b->rsa->n) == 0; + break; + case KEY_DSA: + return a->dsa != NULL && b->dsa != NULL && + BN_cmp(a->dsa->p, b->dsa->p) == 0 && + BN_cmp(a->dsa->q, b->dsa->q) == 0 && + BN_cmp(a->dsa->g, b->dsa->g) == 0 && + BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; + break; + default: + fatal("key_equal: bad key type %d", a->type); + break; + } + return 0; +} + +u_char* +key_fingerprint_raw(const Key *k, enum fp_type dgst_type, + u_int *dgst_raw_length) +{ + const EVP_MD *md = NULL; + EVP_MD_CTX ctx; + u_char *blob = NULL; + u_char *retval = NULL; + u_int len = 0; + int nlen, elen; + + *dgst_raw_length = 0; + + switch (dgst_type) { + case SSH_FP_MD5: + md = EVP_md5(); + break; + case SSH_FP_SHA1: + md = EVP_sha1(); + break; + default: + fatal("key_fingerprint_raw: bad digest type %d", + dgst_type); + } + switch (k->type) { + case KEY_RSA1: + nlen = BN_num_bytes(k->rsa->n); + elen = BN_num_bytes(k->rsa->e); + len = nlen + elen; + blob = xmalloc(len); + BN_bn2bin(k->rsa->n, blob); + BN_bn2bin(k->rsa->e, blob + nlen); + break; + case KEY_DSA: + case KEY_RSA: + key_to_blob(k, &blob, &len); + break; + case KEY_UNSPEC: + return retval; + break; + default: + fatal("key_fingerprint_raw: bad key type %d", k->type); + break; + } + if (blob != NULL) { + retval = xmalloc(EVP_MAX_MD_SIZE); + EVP_DigestInit(&ctx, md); + EVP_DigestUpdate(&ctx, blob, len); + EVP_DigestFinal(&ctx, retval, dgst_raw_length); + memset(blob, 0, len); + xfree(blob); + } else { + fatal("key_fingerprint_raw: blob is null"); + } + return retval; +} + +static char * +key_fingerprint_hex(u_char *dgst_raw, u_int dgst_raw_len) +{ + char *retval; + int i; + + retval = xmalloc(dgst_raw_len * 3 + 1); + retval[0] = '\0'; + for (i = 0; i < dgst_raw_len; i++) { + char hex[4]; + snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]); + strlcat(retval, hex, dgst_raw_len * 3 + 1); + } + + /* Remove the trailing ':' character */ + retval[(dgst_raw_len * 3) - 1] = '\0'; + return retval; +} + +static char * +key_fingerprint_bubblebabble(u_char *dgst_raw, u_int dgst_raw_len) +{ + char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; + char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', + 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; + u_int i, j = 0, rounds, seed = 1; + char *retval; + + rounds = (dgst_raw_len / 2) + 1; + retval = xmalloc(sizeof(char) * (rounds*6)); + retval[j++] = 'x'; + for (i = 0; i < rounds; i++) { + u_int idx0, idx1, idx2, idx3, idx4; + if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) { + idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) + + seed) % 6; + idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15; + idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) + + (seed / 6)) % 6; + retval[j++] = vowels[idx0]; + retval[j++] = consonants[idx1]; + retval[j++] = vowels[idx2]; + if ((i + 1) < rounds) { + idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15; + idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15; + retval[j++] = consonants[idx3]; + retval[j++] = '-'; + retval[j++] = consonants[idx4]; + seed = ((seed * 5) + + ((((u_int)(dgst_raw[2 * i])) * 7) + + ((u_int)(dgst_raw[(2 * i) + 1])))) % 36; + } + } else { + idx0 = seed % 6; + idx1 = 16; + idx2 = seed / 6; + retval[j++] = vowels[idx0]; + retval[j++] = consonants[idx1]; + retval[j++] = vowels[idx2]; + } + } + retval[j++] = 'x'; + retval[j++] = '\0'; + return retval; +} + +char * +key_fingerprint(const Key *k, enum fp_type dgst_type, enum fp_rep dgst_rep) +{ + char *retval = NULL; + u_char *dgst_raw; + u_int dgst_raw_len; + + dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len); + if (!dgst_raw) + fatal("key_fingerprint: null from key_fingerprint_raw()"); + switch (dgst_rep) { + case SSH_FP_HEX: + retval = key_fingerprint_hex(dgst_raw, dgst_raw_len); + break; + case SSH_FP_BUBBLEBABBLE: + retval = key_fingerprint_bubblebabble(dgst_raw, dgst_raw_len); + break; + default: + fatal("key_fingerprint_ex: bad digest representation %d", + dgst_rep); + break; + } + memset(dgst_raw, 0, dgst_raw_len); + xfree(dgst_raw); + return retval; +} + +/* + * Reads a multiple-precision integer in decimal 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. + */ +static int +read_bignum(char **cpp, BIGNUM * value) +{ + char *cp = *cpp; + int old; + + /* Skip any leading whitespace. */ + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + + /* Check that it begins with a decimal digit. */ + if (*cp < '0' || *cp > '9') + return 0; + + /* Save starting position. */ + *cpp = cp; + + /* Move forward until all decimal digits skipped. */ + for (; *cp >= '0' && *cp <= '9'; cp++) + ; + + /* Save the old terminating character, and replace it by \0. */ + old = *cp; + *cp = 0; + + /* Parse the number. */ + if (BN_dec2bn(&value, *cpp) == 0) + return 0; + + /* Restore old terminating character. */ + *cp = old; + + /* Move beyond the number and return success. */ + *cpp = cp; + return 1; +} + +static int +write_bignum(FILE *f, BIGNUM *num) +{ + char *buf = BN_bn2dec(num); + if (buf == NULL) { + error("write_bignum: BN_bn2dec() failed"); + return 0; + } + fprintf(f, " %s", buf); + OPENSSL_free(buf); + return 1; +} + +/* returns 1 ok, -1 error */ +int +key_read(Key *ret, char **cpp) +{ + Key *k; + int success = -1; + char *cp, *space; + int len, n, type; + u_int bits; + u_char *blob; + + cp = *cpp; + + switch (ret->type) { + case KEY_RSA1: + /* Get number of bits. */ + if (*cp < '0' || *cp > '9') + return -1; /* Bad bit count... */ + for (bits = 0; *cp >= '0' && *cp <= '9'; cp++) + bits = 10 * bits + *cp - '0'; + if (bits == 0) + return -1; + *cpp = cp; + /* Get public exponent, public modulus. */ + if (!read_bignum(cpp, ret->rsa->e)) + return -1; + if (!read_bignum(cpp, ret->rsa->n)) + return -1; + success = 1; + break; + case KEY_UNSPEC: + case KEY_RSA: + case KEY_DSA: + space = strchr(cp, ' '); + if (space == NULL) { + debug3("key_read: missing whitespace"); + return -1; + } + *space = '\0'; + type = key_type_from_name(cp); + *space = ' '; + if (type == KEY_UNSPEC) { + debug3("key_read: missing keytype"); + return -1; + } + cp = space+1; + if (*cp == '\0') { + debug3("key_read: short string"); + return -1; + } + if (ret->type == KEY_UNSPEC) { + ret->type = type; + } else if (ret->type != type) { + /* is a key, but different type */ + debug3("key_read: type mismatch"); + return -1; + } + len = 2*strlen(cp); + blob = xmalloc(len); + n = uudecode(cp, blob, len); + if (n < 0) { + error("key_read: uudecode %s failed", cp); + xfree(blob); + return -1; + } + k = key_from_blob(blob, (u_int)n); + xfree(blob); + if (k == NULL) { + error("key_read: key_from_blob %s failed", cp); + return -1; + } + if (k->type != type) { + error("key_read: type mismatch: encoding error"); + key_free(k); + return -1; + } +/*XXXX*/ + if (ret->type == KEY_RSA) { + if (ret->rsa != NULL) + RSA_free(ret->rsa); + ret->rsa = k->rsa; + k->rsa = NULL; + success = 1; +#ifdef DEBUG_PK + RSA_print_fp(stderr, ret->rsa, 8); +#endif + } else { + if (ret->dsa != NULL) + DSA_free(ret->dsa); + ret->dsa = k->dsa; + k->dsa = NULL; + success = 1; +#ifdef DEBUG_PK + DSA_print_fp(stderr, ret->dsa, 8); +#endif + } +/*XXXX*/ + key_free(k); + if (success != 1) + break; + /* advance cp: skip whitespace and data */ + while (*cp == ' ' || *cp == '\t') + cp++; + while (*cp != '\0' && *cp != ' ' && *cp != '\t') + cp++; + *cpp = cp; + break; + default: + fatal("key_read: bad key type: %d", ret->type); + break; + } + return success; +} + +int +key_write(const Key *key, FILE *f) +{ + int n, success = 0; + u_int len, bits = 0; + u_char *blob; + char *uu; + + if (key->type == KEY_RSA1 && key->rsa != NULL) { + /* size of modulus 'n' */ + bits = BN_num_bits(key->rsa->n); + fprintf(f, "%u", bits); + if (write_bignum(f, key->rsa->e) && + write_bignum(f, key->rsa->n)) { + success = 1; + } else { + error("key_write: failed for RSA key"); + } + } else if ((key->type == KEY_DSA && key->dsa != NULL) || + (key->type == KEY_RSA && key->rsa != NULL)) { + key_to_blob(key, &blob, &len); + uu = xmalloc(2*len); + n = uuencode(blob, len, uu, 2*len); + if (n > 0) { + fprintf(f, "%s %s", key_ssh_name(key), uu); + success = 1; + } + xfree(blob); + xfree(uu); + } + return success; +} + +const char * +key_type(const Key *k) +{ + switch (k->type) { + case KEY_RSA1: + return "RSA1"; + break; + case KEY_RSA: + return "RSA"; + break; + case KEY_DSA: + return "DSA"; + break; + } + return "unknown"; +} + +const char * +key_ssh_name(const Key *k) +{ + switch (k->type) { + case KEY_RSA: + return "ssh-rsa"; + break; + case KEY_DSA: + return "ssh-dss"; + break; + } + return "ssh-unknown"; +} + +u_int +key_size(const Key *k) +{ + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + return BN_num_bits(k->rsa->n); + break; + case KEY_DSA: + return BN_num_bits(k->dsa->p); + break; + } + return 0; +} + +static RSA * +rsa_generate_private_key(u_int bits) +{ + RSA *private; + private = RSA_generate_key(bits, 35, NULL, NULL); + if (private == NULL) + fatal("rsa_generate_private_key: key generation failed."); + return private; +} + +static DSA* +dsa_generate_private_key(u_int bits) +{ + DSA *private = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL); + if (private == NULL) + fatal("dsa_generate_private_key: DSA_generate_parameters failed"); + if (!DSA_generate_key(private)) + fatal("dsa_generate_private_key: DSA_generate_key failed."); + if (private == NULL) + fatal("dsa_generate_private_key: NULL."); + return private; +} + +Key * +key_generate(int type, u_int bits) +{ + Key *k = key_new(KEY_UNSPEC); + switch (type) { + case KEY_DSA: + k->dsa = dsa_generate_private_key(bits); + break; + case KEY_RSA: + case KEY_RSA1: + k->rsa = rsa_generate_private_key(bits); + break; + default: + fatal("key_generate: unknown type %d", type); + } + k->type = type; + return k; +} + +Key * +key_from_private(const Key *k) +{ + Key *n = NULL; + switch (k->type) { + case KEY_DSA: + n = key_new(k->type); + BN_copy(n->dsa->p, k->dsa->p); + BN_copy(n->dsa->q, k->dsa->q); + BN_copy(n->dsa->g, k->dsa->g); + BN_copy(n->dsa->pub_key, k->dsa->pub_key); + break; + case KEY_RSA: + case KEY_RSA1: + n = key_new(k->type); + BN_copy(n->rsa->n, k->rsa->n); + BN_copy(n->rsa->e, k->rsa->e); + break; + default: + fatal("key_from_private: unknown type %d", k->type); + break; + } + return n; +} + +int +key_type_from_name(char *name) +{ + if (strcmp(name, "rsa1") == 0) { + return KEY_RSA1; + } else if (strcmp(name, "rsa") == 0) { + return KEY_RSA; + } else if (strcmp(name, "dsa") == 0) { + return KEY_DSA; + } else if (strcmp(name, "ssh-rsa") == 0) { + return KEY_RSA; + } else if (strcmp(name, "ssh-dss") == 0) { + return KEY_DSA; + } + debug2("key_type_from_name: unknown key type '%s'", name); + return KEY_UNSPEC; +} + +int +key_names_valid2(const char *names) +{ + char *s, *cp, *p; + + if (names == NULL || strcmp(names, "") == 0) + return 0; + s = cp = xstrdup(names); + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + switch (key_type_from_name(p)) { + case KEY_RSA1: + case KEY_UNSPEC: + xfree(s); + return 0; + } + } + debug3("key names ok: [%s]", names); + xfree(s); + return 1; +} + +Key * +key_from_blob(const u_char *blob, u_int blen) +{ + Buffer b; + char *ktype; + int rlen, type; + Key *key = NULL; + +#ifdef DEBUG_PK + dump_base64(stderr, blob, blen); +#endif + buffer_init(&b); + buffer_append(&b, blob, blen); + ktype = buffer_get_string(&b, NULL); + type = key_type_from_name(ktype); + + switch (type) { + case KEY_RSA: + key = key_new(type); + buffer_get_bignum2(&b, key->rsa->e); + buffer_get_bignum2(&b, key->rsa->n); +#ifdef DEBUG_PK + RSA_print_fp(stderr, key->rsa, 8); +#endif + break; + case KEY_DSA: + key = key_new(type); + buffer_get_bignum2(&b, key->dsa->p); + buffer_get_bignum2(&b, key->dsa->q); + buffer_get_bignum2(&b, key->dsa->g); + buffer_get_bignum2(&b, key->dsa->pub_key); +#ifdef DEBUG_PK + DSA_print_fp(stderr, key->dsa, 8); +#endif + break; + case KEY_UNSPEC: + key = key_new(type); + break; + default: + error("key_from_blob: cannot handle type %s", ktype); + break; + } + rlen = buffer_len(&b); + if (key != NULL && rlen != 0) + error("key_from_blob: remaining bytes in key blob %d", rlen); + xfree(ktype); + buffer_free(&b); + return key; +} + +int +key_to_blob(const Key *key, u_char **blobp, u_int *lenp) +{ + Buffer b; + int len; + + if (key == NULL) { + error("key_to_blob: key == NULL"); + return 0; + } + buffer_init(&b); + switch (key->type) { + case KEY_DSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->dsa->p); + buffer_put_bignum2(&b, key->dsa->q); + buffer_put_bignum2(&b, key->dsa->g); + buffer_put_bignum2(&b, key->dsa->pub_key); + break; + case KEY_RSA: + buffer_put_cstring(&b, key_ssh_name(key)); + buffer_put_bignum2(&b, key->rsa->e); + buffer_put_bignum2(&b, key->rsa->n); + break; + default: + error("key_to_blob: unsupported key type %d", key->type); + buffer_free(&b); + return 0; + } + len = buffer_len(&b); + if (lenp != NULL) + *lenp = len; + if (blobp != NULL) { + *blobp = xmalloc(len); + memcpy(*blobp, buffer_ptr(&b), len); + } + memset(buffer_ptr(&b), 0, len); + buffer_free(&b); + return len; +} + +int +key_sign( + const Key *key, + u_char **sigp, u_int *lenp, + const u_char *data, u_int datalen) +{ + switch (key->type) { + case KEY_DSA: + return ssh_dss_sign(key, sigp, lenp, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_sign(key, sigp, lenp, data, datalen); + break; + default: + error("key_sign: invalid key type %d", key->type); + return -1; + break; + } +} + +/* + * key_verify returns 1 for a correct signature, 0 for an incorrect signature + * and -1 on error. + */ +int +key_verify( + const Key *key, + const u_char *signature, u_int signaturelen, + const u_char *data, u_int datalen) +{ + if (signaturelen == 0) + return -1; + + switch (key->type) { + case KEY_DSA: + return ssh_dss_verify(key, signature, signaturelen, data, datalen); + break; + case KEY_RSA: + return ssh_rsa_verify(key, signature, signaturelen, data, datalen); + break; + default: + error("key_verify: invalid key type %d", key->type); + return -1; + break; + } +} + +/* Converts a private to a public key */ +Key * +key_demote(const Key *k) +{ + Key *pk; + + pk = xmalloc(sizeof(*pk)); + pk->type = k->type; + pk->flags = k->flags; + pk->dsa = NULL; + pk->rsa = NULL; + + switch (k->type) { + case KEY_RSA1: + case KEY_RSA: + if ((pk->rsa = RSA_new()) == NULL) + fatal("key_demote: RSA_new failed"); + if ((pk->rsa->e = BN_dup(k->rsa->e)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->rsa->n = BN_dup(k->rsa->n)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + case KEY_DSA: + if ((pk->dsa = DSA_new()) == NULL) + fatal("key_demote: DSA_new failed"); + if ((pk->dsa->p = BN_dup(k->dsa->p)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->q = BN_dup(k->dsa->q)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->g = BN_dup(k->dsa->g)) == NULL) + fatal("key_demote: BN_dup failed"); + if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) + fatal("key_demote: BN_dup failed"); + break; + default: + fatal("key_free: bad key type %d", k->type); + break; + } + + return (pk); +} diff --git a/crypto/openssh-3.9p1/key.h b/crypto/openssh-3.9p1/key.h new file mode 100644 index 0000000000..50df8500bb --- /dev/null +++ b/crypto/openssh-3.9p1/key.h @@ -0,0 +1,87 @@ +/* $OpenBSD: key.h,v 1.23 2003/11/10 16:23:41 jakob Exp $ */ + +/* + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef KEY_H +#define KEY_H + +#include +#include + +typedef struct Key Key; +enum types { + KEY_RSA1, + KEY_RSA, + KEY_DSA, + KEY_UNSPEC +}; +enum fp_type { + SSH_FP_SHA1, + SSH_FP_MD5 +}; +enum fp_rep { + SSH_FP_HEX, + SSH_FP_BUBBLEBABBLE +}; + +/* key is stored in external hardware */ +#define KEY_FLAG_EXT 0x0001 + +struct Key { + int type; + int flags; + RSA *rsa; + DSA *dsa; +}; + +Key *key_new(int); +Key *key_new_private(int); +void key_free(Key *); +Key *key_demote(const Key *); +int key_equal(const Key *, const Key *); +char *key_fingerprint(const Key *, enum fp_type, enum fp_rep); +u_char *key_fingerprint_raw(const Key *, enum fp_type, u_int *); +const char *key_type(const Key *); +int key_write(const Key *, FILE *); +int key_read(Key *, char **); +u_int key_size(const Key *); + +Key *key_generate(int, u_int); +Key *key_from_private(const Key *); +int key_type_from_name(char *); + +Key *key_from_blob(const u_char *, u_int); +int key_to_blob(const Key *, u_char **, u_int *); +const char *key_ssh_name(const Key *); +int key_names_valid2(const char *); + +int key_sign(const Key *, u_char **, u_int *, const u_char *, u_int); +int key_verify(const Key *, const u_char *, u_int, const u_char *, u_int); + +int ssh_dss_sign(const Key *, u_char **, u_int *, const u_char *, u_int); +int ssh_dss_verify(const Key *, const u_char *, u_int, const u_char *, u_int); +int ssh_rsa_sign(const Key *, u_char **, u_int *, const u_char *, u_int); +int ssh_rsa_verify(const Key *, const u_char *, u_int, const u_char *, u_int); + +#endif diff --git a/crypto/openssh-3.9p1/log.c b/crypto/openssh-3.9p1/log.c new file mode 100644 index 0000000000..5d8625d15a --- /dev/null +++ b/crypto/openssh-3.9p1/log.c @@ -0,0 +1,338 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: log.c,v 1.29 2003/09/23 20:17:11 markus Exp $"); + +#include "log.h" +#include "xmalloc.h" + +#include +#if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) +# include +#endif + +static LogLevel log_level = SYSLOG_LEVEL_INFO; +static int log_on_stderr = 1; +static int log_facility = LOG_AUTH; +static char *argv0; + +extern char *__progname; + +#define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL) +#define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL) + +/* textual representation of log-facilities/levels */ + +static struct { + const char *name; + SyslogFacility val; +} log_facilities[] = { + { "DAEMON", SYSLOG_FACILITY_DAEMON }, + { "USER", SYSLOG_FACILITY_USER }, + { "AUTH", SYSLOG_FACILITY_AUTH }, +#ifdef LOG_AUTHPRIV + { "AUTHPRIV", SYSLOG_FACILITY_AUTHPRIV }, +#endif + { "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, SYSLOG_FACILITY_NOT_SET } +}; + +static struct { + const char *name; + LogLevel val; +} log_levels[] = +{ + { "QUIET", SYSLOG_LEVEL_QUIET }, + { "FATAL", SYSLOG_LEVEL_FATAL }, + { "ERROR", SYSLOG_LEVEL_ERROR }, + { "INFO", SYSLOG_LEVEL_INFO }, + { "VERBOSE", SYSLOG_LEVEL_VERBOSE }, + { "DEBUG", SYSLOG_LEVEL_DEBUG1 }, + { "DEBUG1", SYSLOG_LEVEL_DEBUG1 }, + { "DEBUG2", SYSLOG_LEVEL_DEBUG2 }, + { "DEBUG3", SYSLOG_LEVEL_DEBUG3 }, + { NULL, SYSLOG_LEVEL_NOT_SET } +}; + +SyslogFacility +log_facility_number(char *name) +{ + int i; + + if (name != NULL) + for (i = 0; log_facilities[i].name; i++) + if (strcasecmp(log_facilities[i].name, name) == 0) + return log_facilities[i].val; + return SYSLOG_FACILITY_NOT_SET; +} + +LogLevel +log_level_number(char *name) +{ + int i; + + if (name != NULL) + for (i = 0; log_levels[i].name; i++) + if (strcasecmp(log_levels[i].name, name) == 0) + return log_levels[i].val; + return SYSLOG_LEVEL_NOT_SET; +} + +/* Error messages that should be logged. */ + +void +error(const char *fmt,...) +{ + va_list args; + + va_start(args, fmt); + do_log(SYSLOG_LEVEL_ERROR, fmt, args); + va_end(args); +} + +/* Log this message (information that usually should go to the log). */ + +void +logit(const char *fmt,...) +{ + va_list args; + + va_start(args, fmt); + do_log(SYSLOG_LEVEL_INFO, fmt, args); + va_end(args); +} + +/* More detailed messages (information that does not need to go to the log). */ + +void +verbose(const char *fmt,...) +{ + va_list args; + + va_start(args, fmt); + do_log(SYSLOG_LEVEL_VERBOSE, fmt, args); + va_end(args); +} + +/* Debugging messages that should not be logged during normal operation. */ + +void +debug(const char *fmt,...) +{ + va_list args; + + va_start(args, fmt); + do_log(SYSLOG_LEVEL_DEBUG1, fmt, args); + va_end(args); +} + +void +debug2(const char *fmt,...) +{ + va_list args; + + va_start(args, fmt); + do_log(SYSLOG_LEVEL_DEBUG2, fmt, args); + va_end(args); +} + +void +debug3(const char *fmt,...) +{ + va_list args; + + va_start(args, fmt); + do_log(SYSLOG_LEVEL_DEBUG3, fmt, args); + va_end(args); +} + +/* + * Initialize the log. + */ + +void +log_init(char *av0, LogLevel level, SyslogFacility facility, int on_stderr) +{ + argv0 = av0; + + switch (level) { + case SYSLOG_LEVEL_QUIET: + case SYSLOG_LEVEL_FATAL: + case SYSLOG_LEVEL_ERROR: + case SYSLOG_LEVEL_INFO: + case SYSLOG_LEVEL_VERBOSE: + case SYSLOG_LEVEL_DEBUG1: + case SYSLOG_LEVEL_DEBUG2: + case SYSLOG_LEVEL_DEBUG3: + log_level = level; + break; + default: + fprintf(stderr, "Unrecognized internal syslog level code %d\n", + (int) level); + exit(1); + } + + log_on_stderr = on_stderr; + if (on_stderr) + return; + + 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; +#ifdef LOG_AUTHPRIV + case SYSLOG_FACILITY_AUTHPRIV: + log_facility = LOG_AUTHPRIV; + break; +#endif + 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); + } +} + +#define MSGBUFSIZ 1024 + +void +do_log(LogLevel level, const char *fmt, va_list args) +{ +#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) + struct syslog_data sdata = SYSLOG_DATA_INIT; +#endif + char msgbuf[MSGBUFSIZ]; + char fmtbuf[MSGBUFSIZ]; + char *txt = NULL; + int pri = LOG_INFO; + + if (level > log_level) + return; + + switch (level) { + case SYSLOG_LEVEL_FATAL: + if (!log_on_stderr) + txt = "fatal"; + pri = LOG_CRIT; + break; + case SYSLOG_LEVEL_ERROR: + if (!log_on_stderr) + txt = "error"; + pri = LOG_ERR; + break; + case SYSLOG_LEVEL_INFO: + pri = LOG_INFO; + break; + case SYSLOG_LEVEL_VERBOSE: + pri = LOG_INFO; + break; + case SYSLOG_LEVEL_DEBUG1: + txt = "debug1"; + pri = LOG_DEBUG; + break; + case SYSLOG_LEVEL_DEBUG2: + txt = "debug2"; + pri = LOG_DEBUG; + break; + case SYSLOG_LEVEL_DEBUG3: + txt = "debug3"; + pri = LOG_DEBUG; + break; + default: + txt = "internal error"; + pri = LOG_ERR; + break; + } + if (txt != NULL) { + snprintf(fmtbuf, sizeof(fmtbuf), "%s: %s", txt, fmt); + vsnprintf(msgbuf, sizeof(msgbuf), fmtbuf, args); + } else { + vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); + } + strnvis(fmtbuf, msgbuf, sizeof(fmtbuf), + log_on_stderr ? LOG_STDERR_VIS : LOG_SYSLOG_VIS); + if (log_on_stderr) { + snprintf(msgbuf, sizeof msgbuf, "%s\r\n", fmtbuf); + write(STDERR_FILENO, msgbuf, strlen(msgbuf)); + } else { +#if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) + openlog_r(argv0 ? argv0 : __progname, LOG_PID, log_facility, &sdata); + syslog_r(pri, &sdata, "%.500s", fmtbuf); + closelog_r(&sdata); +#else + openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility); + syslog(pri, "%.500s", fmtbuf); + closelog(); +#endif + } +} diff --git a/crypto/openssh-3.9p1/log.h b/crypto/openssh-3.9p1/log.h new file mode 100644 index 0000000000..2b3c3090f9 --- /dev/null +++ b/crypto/openssh-3.9p1/log.h @@ -0,0 +1,66 @@ +/* $OpenBSD: log.h,v 1.11 2004/06/21 22:02:58 djm Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#ifndef SSH_LOG_H +#define SSH_LOG_H + +#include /* Needed for LOG_AUTHPRIV (if present) */ + +/* Supported syslog facilities and levels. */ +typedef enum { + SYSLOG_FACILITY_DAEMON, + SYSLOG_FACILITY_USER, + SYSLOG_FACILITY_AUTH, +#ifdef LOG_AUTHPRIV + SYSLOG_FACILITY_AUTHPRIV, +#endif + SYSLOG_FACILITY_LOCAL0, + SYSLOG_FACILITY_LOCAL1, + SYSLOG_FACILITY_LOCAL2, + SYSLOG_FACILITY_LOCAL3, + SYSLOG_FACILITY_LOCAL4, + SYSLOG_FACILITY_LOCAL5, + SYSLOG_FACILITY_LOCAL6, + SYSLOG_FACILITY_LOCAL7, + SYSLOG_FACILITY_NOT_SET = -1 +} SyslogFacility; + +typedef enum { + SYSLOG_LEVEL_QUIET, + SYSLOG_LEVEL_FATAL, + SYSLOG_LEVEL_ERROR, + SYSLOG_LEVEL_INFO, + SYSLOG_LEVEL_VERBOSE, + SYSLOG_LEVEL_DEBUG1, + SYSLOG_LEVEL_DEBUG2, + SYSLOG_LEVEL_DEBUG3, + SYSLOG_LEVEL_NOT_SET = -1 +} LogLevel; + +void log_init(char *, LogLevel, SyslogFacility, int); + +SyslogFacility log_facility_number(char *); +LogLevel log_level_number(char *); + +void fatal(const char *, ...) __dead __attribute__((format(printf, 1, 2))); +void error(const char *, ...) __attribute__((format(printf, 1, 2))); +void logit(const char *, ...) __attribute__((format(printf, 1, 2))); +void verbose(const char *, ...) __attribute__((format(printf, 1, 2))); +void debug(const char *, ...) __attribute__((format(printf, 1, 2))); +void debug2(const char *, ...) __attribute__((format(printf, 1, 2))); +void debug3(const char *, ...) __attribute__((format(printf, 1, 2))); + +void do_log(LogLevel, const char *, va_list); +void cleanup_exit(int) __dead; +#endif diff --git a/crypto/openssh-3.9p1/log.h.patch b/crypto/openssh-3.9p1/log.h.patch new file mode 100644 index 0000000000..871fe0e45d --- /dev/null +++ b/crypto/openssh-3.9p1/log.h.patch @@ -0,0 +1,11 @@ +--- log.h_orig 2004-08-22 16:25:25.000000000 +0000 ++++ log.h 2004-08-22 16:25:38.000000000 +0000 +@@ -15,6 +15,8 @@ + #ifndef SSH_LOG_H + #define SSH_LOG_H + ++#define __dead __dead2 ++ + #include /* Needed for LOG_AUTHPRIV (if present) */ + + /* Supported syslog facilities and levels. */ diff --git a/crypto/openssh-3.9p1/log.h_orig b/crypto/openssh-3.9p1/log.h_orig new file mode 100644 index 0000000000..2b3c3090f9 --- /dev/null +++ b/crypto/openssh-3.9p1/log.h_orig @@ -0,0 +1,66 @@ +/* $OpenBSD: log.h,v 1.11 2004/06/21 22:02:58 djm Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#ifndef SSH_LOG_H +#define SSH_LOG_H + +#include /* Needed for LOG_AUTHPRIV (if present) */ + +/* Supported syslog facilities and levels. */ +typedef enum { + SYSLOG_FACILITY_DAEMON, + SYSLOG_FACILITY_USER, + SYSLOG_FACILITY_AUTH, +#ifdef LOG_AUTHPRIV + SYSLOG_FACILITY_AUTHPRIV, +#endif + SYSLOG_FACILITY_LOCAL0, + SYSLOG_FACILITY_LOCAL1, + SYSLOG_FACILITY_LOCAL2, + SYSLOG_FACILITY_LOCAL3, + SYSLOG_FACILITY_LOCAL4, + SYSLOG_FACILITY_LOCAL5, + SYSLOG_FACILITY_LOCAL6, + SYSLOG_FACILITY_LOCAL7, + SYSLOG_FACILITY_NOT_SET = -1 +} SyslogFacility; + +typedef enum { + SYSLOG_LEVEL_QUIET, + SYSLOG_LEVEL_FATAL, + SYSLOG_LEVEL_ERROR, + SYSLOG_LEVEL_INFO, + SYSLOG_LEVEL_VERBOSE, + SYSLOG_LEVEL_DEBUG1, + SYSLOG_LEVEL_DEBUG2, + SYSLOG_LEVEL_DEBUG3, + SYSLOG_LEVEL_NOT_SET = -1 +} LogLevel; + +void log_init(char *, LogLevel, SyslogFacility, int); + +SyslogFacility log_facility_number(char *); +LogLevel log_level_number(char *); + +void fatal(const char *, ...) __dead __attribute__((format(printf, 1, 2))); +void error(const char *, ...) __attribute__((format(printf, 1, 2))); +void logit(const char *, ...) __attribute__((format(printf, 1, 2))); +void verbose(const char *, ...) __attribute__((format(printf, 1, 2))); +void debug(const char *, ...) __attribute__((format(printf, 1, 2))); +void debug2(const char *, ...) __attribute__((format(printf, 1, 2))); +void debug3(const char *, ...) __attribute__((format(printf, 1, 2))); + +void do_log(LogLevel, const char *, va_list); +void cleanup_exit(int) __dead; +#endif diff --git a/crypto/openssh-3.9p1/loginrec.c b/crypto/openssh-3.9p1/loginrec.c new file mode 100644 index 0000000000..f07f65fce1 --- /dev/null +++ b/crypto/openssh-3.9p1/loginrec.c @@ -0,0 +1,1578 @@ +/* + * Copyright (c) 2000 Andre Lucas. All rights reserved. + * Portions copyright (c) 1998 Todd C. Miller + * Portions copyright (c) 1996 Jason Downs + * Portions copyright (c) 1996 Theo de Raadt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + ** loginrec.c: platform-independent login recording and lastlog retrieval + **/ + +/* + The new login code explained + ============================ + + This code attempts to provide a common interface to login recording + (utmp and friends) and last login time retrieval. + + Its primary means of achieving this is to use 'struct logininfo', a + union of all the useful fields in the various different types of + system login record structures one finds on UNIX variants. + + We depend on autoconf to define which recording methods are to be + used, and which fields are contained in the relevant data structures + on the local system. Many C preprocessor symbols affect which code + gets compiled here. + + The code is designed to make it easy to modify a particular + recording method, without affecting other methods nor requiring so + many nested conditional compilation blocks as were commonplace in + the old code. + + For login recording, we try to use the local system's libraries as + these are clearly most likely to work correctly. For utmp systems + this usually means login() and logout() or setutent() etc., probably + in libutil, along with logwtmp() etc. On these systems, we fall back + to writing the files directly if we have to, though this method + requires very thorough testing so we do not corrupt local auditing + information. These files and their access methods are very system + specific indeed. + + For utmpx systems, the corresponding library functions are + setutxent() etc. To the author's knowledge, all utmpx systems have + these library functions and so no direct write is attempted. If such + a system exists and needs support, direct analogues of the [uw]tmp + code should suffice. + + Retrieving the time of last login ('lastlog') is in some ways even + more problemmatic than login recording. Some systems provide a + simple table of all users which we seek based on uid and retrieve a + relatively standard structure. Others record the same information in + a directory with a separate file, and others don't record the + information separately at all. For systems in the latter category, + we look backwards in the wtmp or wtmpx file for the last login entry + for our user. Naturally this is slower and on busy systems could + incur a significant performance penalty. + + Calling the new code + -------------------- + + In OpenSSH all login recording and retrieval is performed in + login.c. Here you'll find working examples. Also, in the logintest.c + program there are more examples. + + Internal handler calling method + ------------------------------- + + When a call is made to login_login() or login_logout(), both + routines set a struct logininfo flag defining which action (log in, + or log out) is to be taken. They both then call login_write(), which + calls whichever of the many structure-specific handlers autoconf + selects for the local system. + + The handlers themselves handle system data structure specifics. Both + struct utmp and struct utmpx have utility functions (see + construct_utmp*()) to try to make it simpler to add extra systems + that introduce new features to either structure. + + While it may seem terribly wasteful to replicate so much similar + code for each method, experience has shown that maintaining code to + write both struct utmp and utmpx in one function, whilst maintaining + support for all systems whether they have library support or not, is + a difficult and time-consuming task. + + Lastlog support proceeds similarly. Functions login_get_lastlog() + (and its OpenSSH-tuned friend login_get_lastlog_time()) call + getlast_entry(), which tries one of three methods to find the last + login time. It uses local system lastlog support if it can, + otherwise it tries wtmp or wtmpx before giving up and returning 0, + meaning "tilt". + + Maintenance + ----------- + + In many cases it's possible to tweak autoconf to select the correct + methods for a particular platform, either by improving the detection + code (best), or by presetting DISABLE_ or CONF__FILE + symbols for the platform. + + Use logintest to check which symbols are defined before modifying + configure.ac and loginrec.c. (You have to build logintest yourself + with 'make logintest' as it's not built by default.) + + Otherwise, patches to the specific method(s) are very helpful! + +*/ + +/** + ** TODO: + ** homegrown ttyslot() + ** test, test, test + ** + ** Platform status: + ** ---------------- + ** + ** Known good: + ** Linux (Redhat 6.2, Debian) + ** Solaris + ** HP-UX 10.20 (gcc only) + ** IRIX + ** NeXT - M68k/HPPA/Sparc (4.2/3.3) + ** + ** Testing required: Please send reports! + ** NetBSD + ** HP-UX 11 + ** AIX + ** + ** Platforms with known problems: + ** Some variants of Slackware Linux + ** + **/ + +#include "includes.h" + +#include "ssh.h" +#include "xmalloc.h" +#include "loginrec.h" +#include "log.h" +#include "atomicio.h" + +RCSID("$Id: loginrec.c,v 1.58 2004/08/15 09:12:52 djm Exp $"); + +#ifdef HAVE_UTIL_H +# include +#endif + +#ifdef HAVE_LIBUTIL_H +# include +#endif + +/** + ** prototypes for helper functions in this file + **/ + +#if HAVE_UTMP_H +void set_utmp_time(struct logininfo *li, struct utmp *ut); +void construct_utmp(struct logininfo *li, struct utmp *ut); +#endif + +#ifdef HAVE_UTMPX_H +void set_utmpx_time(struct logininfo *li, struct utmpx *ut); +void construct_utmpx(struct logininfo *li, struct utmpx *ut); +#endif + +int utmp_write_entry(struct logininfo *li); +int utmpx_write_entry(struct logininfo *li); +int wtmp_write_entry(struct logininfo *li); +int wtmpx_write_entry(struct logininfo *li); +int lastlog_write_entry(struct logininfo *li); +int syslogin_write_entry(struct logininfo *li); + +int getlast_entry(struct logininfo *li); +int lastlog_get_entry(struct logininfo *li); +int wtmp_get_entry(struct logininfo *li); +int wtmpx_get_entry(struct logininfo *li); + +/* pick the shortest string */ +#define MIN_SIZEOF(s1,s2) ( sizeof(s1) < sizeof(s2) ? sizeof(s1) : sizeof(s2) ) + +/** + ** platform-independent login functions + **/ + +/* login_login(struct logininfo *) -Record a login + * + * Call with a pointer to a struct logininfo initialised with + * login_init_entry() or login_alloc_entry() + * + * Returns: + * >0 if successful + * 0 on failure (will use OpenSSH's logging facilities for diagnostics) + */ +int +login_login (struct logininfo *li) +{ + li->type = LTYPE_LOGIN; + return login_write(li); +} + + +/* login_logout(struct logininfo *) - Record a logout + * + * Call as with login_login() + * + * Returns: + * >0 if successful + * 0 on failure (will use OpenSSH's logging facilities for diagnostics) + */ +int +login_logout(struct logininfo *li) +{ + li->type = LTYPE_LOGOUT; + return login_write(li); +} + +/* login_get_lastlog_time(int) - Retrieve the last login time + * + * Retrieve the last login time for the given uid. Will try to use the + * system lastlog facilities if they are available, but will fall back + * to looking in wtmp/wtmpx if necessary + * + * Returns: + * 0 on failure, or if user has never logged in + * Time in seconds from the epoch if successful + * + * Useful preprocessor symbols: + * DISABLE_LASTLOG: If set, *never* even try to retrieve lastlog + * info + * USE_LASTLOG: If set, indicates the presence of system lastlog + * facilities. If this and DISABLE_LASTLOG are not set, + * try to retrieve lastlog information from wtmp/wtmpx. + */ +unsigned int +login_get_lastlog_time(const int uid) +{ + struct logininfo li; + + if (login_get_lastlog(&li, uid)) + return li.tv_sec; + else + return 0; +} + +/* login_get_lastlog(struct logininfo *, int) - Retrieve a lastlog entry + * + * Retrieve a logininfo structure populated (only partially) with + * information from the system lastlog data, or from wtmp/wtmpx if no + * system lastlog information exists. + * + * Note this routine must be given a pre-allocated logininfo. + * + * Returns: + * >0: A pointer to your struct logininfo if successful + * 0 on failure (will use OpenSSH's logging facilities for diagnostics) + * + */ +struct logininfo * +login_get_lastlog(struct logininfo *li, const int uid) +{ + struct passwd *pw; + + memset(li, '\0', sizeof(*li)); + li->uid = uid; + + /* + * If we don't have a 'real' lastlog, we need the username to + * reliably search wtmp(x) for the last login (see + * wtmp_get_entry().) + */ + pw = getpwuid(uid); + if (pw == NULL) + fatal("login_get_lastlog: Cannot find account for uid %i", uid); + + /* No MIN_SIZEOF here - we absolutely *must not* truncate the + * username */ + strlcpy(li->username, pw->pw_name, sizeof(li->username)); + + if (getlast_entry(li)) + return li; + else + return NULL; +} + + +/* login_alloc_entry(int, char*, char*, char*) - Allocate and initialise + * a logininfo structure + * + * This function creates a new struct logininfo, a data structure + * meant to carry the information required to portably record login info. + * + * Returns a pointer to a newly created struct logininfo. If memory + * allocation fails, the program halts. + */ +struct +logininfo *login_alloc_entry(int pid, const char *username, + const char *hostname, const char *line) +{ + struct logininfo *newli; + + newli = (struct logininfo *) xmalloc (sizeof(*newli)); + (void)login_init_entry(newli, pid, username, hostname, line); + return newli; +} + + +/* login_free_entry(struct logininfo *) - free struct memory */ +void +login_free_entry(struct logininfo *li) +{ + xfree(li); +} + + +/* login_init_entry(struct logininfo *, int, char*, char*, char*) + * - initialise a struct logininfo + * + * Populates a new struct logininfo, a data structure meant to carry + * the information required to portably record login info. + * + * Returns: 1 + */ +int +login_init_entry(struct logininfo *li, int pid, const char *username, + const char *hostname, const char *line) +{ + struct passwd *pw; + + memset(li, 0, sizeof(*li)); + + li->pid = pid; + + /* set the line information */ + if (line) + line_fullname(li->line, line, sizeof(li->line)); + + if (username) { + strlcpy(li->username, username, sizeof(li->username)); + pw = getpwnam(li->username); + if (pw == NULL) + fatal("login_init_entry: Cannot find user \"%s\"", li->username); + li->uid = pw->pw_uid; + } + + if (hostname) + strlcpy(li->hostname, hostname, sizeof(li->hostname)); + + return 1; +} + +/* login_set_current_time(struct logininfo *) - set the current time + * + * Set the current time in a logininfo structure. This function is + * meant to eliminate the need to deal with system dependencies for + * time handling. + */ +void +login_set_current_time(struct logininfo *li) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + + li->tv_sec = tv.tv_sec; + li->tv_usec = tv.tv_usec; +} + +/* copy a sockaddr_* into our logininfo */ +void +login_set_addr(struct logininfo *li, const struct sockaddr *sa, + const unsigned int sa_size) +{ + unsigned int bufsize = sa_size; + + /* make sure we don't overrun our union */ + if (sizeof(li->hostaddr) < sa_size) + bufsize = sizeof(li->hostaddr); + + memcpy((void *)&(li->hostaddr.sa), (const void *)sa, bufsize); +} + + +/** + ** login_write: Call low-level recording functions based on autoconf + ** results + **/ +int +login_write (struct logininfo *li) +{ +#ifndef HAVE_CYGWIN + if ((int)geteuid() != 0) { + logit("Attempt to write login records by non-root user (aborting)"); + return 1; + } +#endif + + /* set the timestamp */ + login_set_current_time(li); +#ifdef USE_LOGIN + syslogin_write_entry(li); +#endif +#ifdef USE_LASTLOG + if (li->type == LTYPE_LOGIN) { + lastlog_write_entry(li); + } +#endif +#ifdef USE_UTMP + utmp_write_entry(li); +#endif +#ifdef USE_WTMP + wtmp_write_entry(li); +#endif +#ifdef USE_UTMPX + utmpx_write_entry(li); +#endif +#ifdef USE_WTMPX + wtmpx_write_entry(li); +#endif +#ifdef CUSTOM_SYS_AUTH_RECORD_LOGIN + if (li->type == LTYPE_LOGIN && + !sys_auth_record_login(li->username,li->hostname,li->line)) + logit("Writing login record failed for %s", li->username); +#endif + return 0; +} + +#ifdef LOGIN_NEEDS_UTMPX +int +login_utmp_only(struct logininfo *li) +{ + li->type = LTYPE_LOGIN; + login_set_current_time(li); +# ifdef USE_UTMP + utmp_write_entry(li); +# endif +# ifdef USE_WTMP + wtmp_write_entry(li); +# endif +# ifdef USE_UTMPX + utmpx_write_entry(li); +# endif +# ifdef USE_WTMPX + wtmpx_write_entry(li); +# endif + return 0; +} +#endif + +/** + ** getlast_entry: Call low-level functions to retrieve the last login + ** time. + **/ + +/* take the uid in li and return the last login time */ +int +getlast_entry(struct logininfo *li) +{ +#ifdef USE_LASTLOG + return(lastlog_get_entry(li)); +#else /* !USE_LASTLOG */ + +#ifdef DISABLE_LASTLOG + /* On some systems we shouldn't even try to obtain last login + * time, e.g. AIX */ + return 0; +# else /* DISABLE_LASTLOG */ + /* Try to retrieve the last login time from wtmp */ +# if defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) + /* retrieve last login time from utmp */ + return (wtmp_get_entry(li)); +# else /* defined(USE_WTMP) && (defined(HAVE_TIME_IN_UTMP) || defined(HAVE_TV_IN_UTMP)) */ + /* If wtmp isn't available, try wtmpx */ +# if defined(USE_WTMPX) && (defined(HAVE_TIME_IN_UTMPX) || defined(HAVE_TV_IN_UTMPX)) + /* retrieve last login time from utmpx */ + return (wtmpx_get_entry(li)); +# else + /* Give up: No means of retrieving last login time */ + return 0; +# endif /* USE_WTMPX && (HAVE_TIME_IN_UTMPX || HAVE_TV_IN_UTMPX) */ +# endif /* USE_WTMP && (HAVE_TIME_IN_UTMP || HAVE_TV_IN_UTMP) */ +# endif /* DISABLE_LASTLOG */ +#endif /* USE_LASTLOG */ +} + + + +/* + * 'line' string utility functions + * + * These functions process the 'line' string into one of three forms: + * + * 1. The full filename (including '/dev') + * 2. The stripped name (excluding '/dev') + * 3. The abbreviated name (e.g. /dev/ttyp00 -> yp00 + * /dev/pts/1 -> ts/1 ) + * + * Form 3 is used on some systems to identify a .tmp.? entry when + * attempting to remove it. Typically both addition and removal is + * performed by one application - say, sshd - so as long as the choice + * uniquely identifies a terminal it's ok. + */ + + +/* line_fullname(): add the leading '/dev/' if it doesn't exist make + * sure dst has enough space, if not just copy src (ugh) */ +char * +line_fullname(char *dst, const char *src, int dstsize) +{ + memset(dst, '\0', dstsize); + if ((strncmp(src, "/dev/", 5) == 0) || (dstsize < (strlen(src) + 5))) { + strlcpy(dst, src, dstsize); + } else { + strlcpy(dst, "/dev/", dstsize); + strlcat(dst, src, dstsize); + } + return dst; +} + +/* line_stripname(): strip the leading '/dev' if it exists, return dst */ +char * +line_stripname(char *dst, const char *src, int dstsize) +{ + memset(dst, '\0', dstsize); + if (strncmp(src, "/dev/", 5) == 0) + strlcpy(dst, src + 5, dstsize); + else + strlcpy(dst, src, dstsize); + return dst; +} + +/* line_abbrevname(): Return the abbreviated (usually four-character) + * form of the line (Just use the last characters of the + * full name.) + * + * NOTE: use strncpy because we do NOT necessarily want zero + * termination */ +char * +line_abbrevname(char *dst, const char *src, int dstsize) +{ + size_t len; + + memset(dst, '\0', dstsize); + + /* Always skip prefix if present */ + if (strncmp(src, "/dev/", 5) == 0) + src += 5; + +#ifdef WITH_ABBREV_NO_TTY + if (strncmp(src, "tty", 3) == 0) + src += 3; +#endif + + len = strlen(src); + + if (len > 0) { + if (((int)len - dstsize) > 0) + src += ((int)len - dstsize); + + /* note: _don't_ change this to strlcpy */ + strncpy(dst, src, (size_t)dstsize); + } + + return dst; +} + +/** + ** utmp utility functions + ** + ** These functions manipulate struct utmp, taking system differences + ** into account. + **/ + +#if defined(USE_UTMP) || defined (USE_WTMP) || defined (USE_LOGIN) + +/* build the utmp structure */ +void +set_utmp_time(struct logininfo *li, struct utmp *ut) +{ +# ifdef HAVE_TV_IN_UTMP + ut->ut_tv.tv_sec = li->tv_sec; + ut->ut_tv.tv_usec = li->tv_usec; +# else +# ifdef HAVE_TIME_IN_UTMP + ut->ut_time = li->tv_sec; +# endif +# endif +} + +void +construct_utmp(struct logininfo *li, + struct utmp *ut) +{ +# ifdef HAVE_ADDR_V6_IN_UTMP + struct sockaddr_in6 *sa6; +# endif + memset(ut, '\0', sizeof(*ut)); + + /* First fill out fields used for both logins and logouts */ + +# ifdef HAVE_ID_IN_UTMP + line_abbrevname(ut->ut_id, li->line, sizeof(ut->ut_id)); +# endif + +# ifdef HAVE_TYPE_IN_UTMP + /* This is done here to keep utmp constants out of struct logininfo */ + switch (li->type) { + case LTYPE_LOGIN: + ut->ut_type = USER_PROCESS; +#ifdef _UNICOS + cray_set_tmpdir(ut); +#endif + break; + case LTYPE_LOGOUT: + ut->ut_type = DEAD_PROCESS; +#ifdef _UNICOS + cray_retain_utmp(ut, li->pid); +#endif + break; + } +# endif + set_utmp_time(li, ut); + + line_stripname(ut->ut_line, li->line, sizeof(ut->ut_line)); + +# ifdef HAVE_PID_IN_UTMP + ut->ut_pid = li->pid; +# endif + + /* If we're logging out, leave all other fields blank */ + if (li->type == LTYPE_LOGOUT) + return; + + /* + * These fields are only used when logging in, and are blank + * for logouts. + */ + + /* Use strncpy because we don't necessarily want null termination */ + strncpy(ut->ut_name, li->username, MIN_SIZEOF(ut->ut_name, li->username)); +# ifdef HAVE_HOST_IN_UTMP + strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname)); +# endif +# ifdef HAVE_ADDR_IN_UTMP + /* this is just a 32-bit IP address */ + if (li->hostaddr.sa.sa_family == AF_INET) + ut->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; +# endif +# ifdef HAVE_ADDR_V6_IN_UTMP + /* this is just a 128-bit IPv6 address */ + if (li->hostaddr.sa.sa_family == AF_INET6) { + sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); + memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); + if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { + ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; + ut->ut_addr_v6[1] = 0; + ut->ut_addr_v6[2] = 0; + ut->ut_addr_v6[3] = 0; + } + } +# endif +} +#endif /* USE_UTMP || USE_WTMP || USE_LOGIN */ + +/** + ** utmpx utility functions + ** + ** These functions manipulate struct utmpx, accounting for system + ** variations. + **/ + +#if defined(USE_UTMPX) || defined (USE_WTMPX) +/* build the utmpx structure */ +void +set_utmpx_time(struct logininfo *li, struct utmpx *utx) +{ +# ifdef HAVE_TV_IN_UTMPX + utx->ut_tv.tv_sec = li->tv_sec; + utx->ut_tv.tv_usec = li->tv_usec; +# else /* HAVE_TV_IN_UTMPX */ +# ifdef HAVE_TIME_IN_UTMPX + utx->ut_time = li->tv_sec; +# endif /* HAVE_TIME_IN_UTMPX */ +# endif /* HAVE_TV_IN_UTMPX */ +} + +void +construct_utmpx(struct logininfo *li, struct utmpx *utx) +{ +# ifdef HAVE_ADDR_V6_IN_UTMP + struct sockaddr_in6 *sa6; +# endif + memset(utx, '\0', sizeof(*utx)); +# ifdef HAVE_ID_IN_UTMPX + line_abbrevname(utx->ut_id, li->line, sizeof(utx->ut_id)); +# endif + + /* this is done here to keep utmp constants out of loginrec.h */ + switch (li->type) { + case LTYPE_LOGIN: + utx->ut_type = USER_PROCESS; + break; + case LTYPE_LOGOUT: + utx->ut_type = DEAD_PROCESS; + break; + } + line_stripname(utx->ut_line, li->line, sizeof(utx->ut_line)); + set_utmpx_time(li, utx); + utx->ut_pid = li->pid; + /* strncpy(): Don't necessarily want null termination */ + strncpy(utx->ut_name, li->username, MIN_SIZEOF(utx->ut_name, li->username)); + + if (li->type == LTYPE_LOGOUT) + return; + + /* + * These fields are only used when logging in, and are blank + * for logouts. + */ + +# ifdef HAVE_HOST_IN_UTMPX + strncpy(utx->ut_host, li->hostname, MIN_SIZEOF(utx->ut_host, li->hostname)); +# endif +# ifdef HAVE_ADDR_IN_UTMPX + /* this is just a 32-bit IP address */ + if (li->hostaddr.sa.sa_family == AF_INET) + utx->ut_addr = li->hostaddr.sa_in.sin_addr.s_addr; +# endif +# ifdef HAVE_ADDR_V6_IN_UTMP + /* this is just a 128-bit IPv6 address */ + if (li->hostaddr.sa.sa_family == AF_INET6) { + sa6 = ((struct sockaddr_in6 *)&li->hostaddr.sa); + memcpy(ut->ut_addr_v6, sa6->sin6_addr.s6_addr, 16); + if (IN6_IS_ADDR_V4MAPPED(&sa6->sin6_addr)) { + ut->ut_addr_v6[0] = ut->ut_addr_v6[3]; + ut->ut_addr_v6[1] = 0; + ut->ut_addr_v6[2] = 0; + ut->ut_addr_v6[3] = 0; + } + } +# endif +# ifdef HAVE_SYSLEN_IN_UTMPX + /* ut_syslen is the length of the utx_host string */ + utx->ut_syslen = MIN(strlen(li->hostname), sizeof(utx->ut_host)); +# endif +} +#endif /* USE_UTMPX || USE_WTMPX */ + +/** + ** Low-level utmp functions + **/ + +/* FIXME: (ATL) utmp_write_direct needs testing */ +#ifdef USE_UTMP + +/* if we can, use pututline() etc. */ +# if !defined(DISABLE_PUTUTLINE) && defined(HAVE_SETUTENT) && \ + defined(HAVE_PUTUTLINE) +# define UTMP_USE_LIBRARY +# endif + + +/* write a utmp entry with the system's help (pututline() and pals) */ +# ifdef UTMP_USE_LIBRARY +static int +utmp_write_library(struct logininfo *li, struct utmp *ut) +{ + setutent(); + pututline(ut); + +# ifdef HAVE_ENDUTENT + endutent(); +# endif + return 1; +} +# else /* UTMP_USE_LIBRARY */ + +/* write a utmp entry direct to the file */ +/* This is a slightly modification of code in OpenBSD's login.c */ +static int +utmp_write_direct(struct logininfo *li, struct utmp *ut) +{ + struct utmp old_ut; + register int fd; + int tty; + + /* FIXME: (ATL) ttyslot() needs local implementation */ + +#if defined(HAVE_GETTTYENT) + register struct ttyent *ty; + + tty=0; + + setttyent(); + while ((struct ttyent *)0 != (ty = getttyent())) { + tty++; + if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line))) + break; + } + endttyent(); + + if((struct ttyent *)0 == ty) { + logit("%s: tty not found", __func__); + return (0); + } +#else /* FIXME */ + + tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */ + +#endif /* HAVE_GETTTYENT */ + + if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) { + off_t pos, ret; + + pos = (off_t)tty * sizeof(struct utmp); + if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { + logit("%s: llseek: %s", strerror(errno)); + return (0); + } + if (ret != pos) { + logit("%s: Couldn't seek to tty %s slot in %s", tty, + UTMP_FILE); + return (0); + } + /* + * Prevent luser from zero'ing out ut_host. + * If the new ut_line is empty but the old one is not + * and ut_line and ut_name match, preserve the old ut_line. + */ + if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) && + (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') && + (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) && + (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) { + (void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host)); + } + + if ((ret = lseek(fd, pos, SEEK_SET)) == -1) { + logit("%s: llseek: %s", __func__, strerror(errno)); + return (0); + } + if (ret != pos) { + logit("%s: Couldn't seek to tty %s slot in %s", + __func__, tty, UTMP_FILE); + return (0); + } + if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) + logit("%s: error writing %s: %s", __func__, + UTMP_FILE, strerror(errno)); + + (void)close(fd); + return 1; + } else { + return 0; + } +} +# endif /* UTMP_USE_LIBRARY */ + +static int +utmp_perform_login(struct logininfo *li) +{ + struct utmp ut; + + construct_utmp(li, &ut); +# ifdef UTMP_USE_LIBRARY + if (!utmp_write_library(li, &ut)) { + logit("utmp_perform_login: utmp_write_library() failed"); + return 0; + } +# else + if (!utmp_write_direct(li, &ut)) { + logit("utmp_perform_login: utmp_write_direct() failed"); + return 0; + } +# endif + return 1; +} + + +static int +utmp_perform_logout(struct logininfo *li) +{ + struct utmp ut; + + construct_utmp(li, &ut); +# ifdef UTMP_USE_LIBRARY + if (!utmp_write_library(li, &ut)) { + logit("utmp_perform_logout: utmp_write_library() failed"); + return 0; + } +# else + if (!utmp_write_direct(li, &ut)) { + logit("utmp_perform_logout: utmp_write_direct() failed"); + return 0; + } +# endif + return 1; +} + + +int +utmp_write_entry(struct logininfo *li) +{ + switch(li->type) { + case LTYPE_LOGIN: + return utmp_perform_login(li); + + case LTYPE_LOGOUT: + return utmp_perform_logout(li); + + default: + logit("utmp_write_entry: invalid type field"); + return 0; + } +} +#endif /* USE_UTMP */ + + +/** + ** Low-level utmpx functions + **/ + +/* not much point if we don't want utmpx entries */ +#ifdef USE_UTMPX + +/* if we have the wherewithall, use pututxline etc. */ +# if !defined(DISABLE_PUTUTXLINE) && defined(HAVE_SETUTXENT) && \ + defined(HAVE_PUTUTXLINE) +# define UTMPX_USE_LIBRARY +# endif + + +/* write a utmpx entry with the system's help (pututxline() and pals) */ +# ifdef UTMPX_USE_LIBRARY +static int +utmpx_write_library(struct logininfo *li, struct utmpx *utx) +{ + setutxent(); + pututxline(utx); + +# ifdef HAVE_ENDUTXENT + endutxent(); +# endif + return 1; +} + +# else /* UTMPX_USE_LIBRARY */ + +/* write a utmp entry direct to the file */ +static int +utmpx_write_direct(struct logininfo *li, struct utmpx *utx) +{ + logit("utmpx_write_direct: not implemented!"); + return 0; +} +# endif /* UTMPX_USE_LIBRARY */ + +static int +utmpx_perform_login(struct logininfo *li) +{ + struct utmpx utx; + + construct_utmpx(li, &utx); +# ifdef UTMPX_USE_LIBRARY + if (!utmpx_write_library(li, &utx)) { + logit("utmpx_perform_login: utmp_write_library() failed"); + return 0; + } +# else + if (!utmpx_write_direct(li, &ut)) { + logit("utmpx_perform_login: utmp_write_direct() failed"); + return 0; + } +# endif + return 1; +} + + +static int +utmpx_perform_logout(struct logininfo *li) +{ + struct utmpx utx; + + construct_utmpx(li, &utx); +# ifdef HAVE_ID_IN_UTMPX + line_abbrevname(utx.ut_id, li->line, sizeof(utx.ut_id)); +# endif +# ifdef HAVE_TYPE_IN_UTMPX + utx.ut_type = DEAD_PROCESS; +# endif + +# ifdef UTMPX_USE_LIBRARY + utmpx_write_library(li, &utx); +# else + utmpx_write_direct(li, &utx); +# endif + return 1; +} + +int +utmpx_write_entry(struct logininfo *li) +{ + switch(li->type) { + case LTYPE_LOGIN: + return utmpx_perform_login(li); + case LTYPE_LOGOUT: + return utmpx_perform_logout(li); + default: + logit("utmpx_write_entry: invalid type field"); + return 0; + } +} +#endif /* USE_UTMPX */ + + +/** + ** Low-level wtmp functions + **/ + +#ifdef USE_WTMP + +/* write a wtmp entry direct to the end of the file */ +/* This is a slight modification of code in OpenBSD's logwtmp.c */ +static int +wtmp_write(struct logininfo *li, struct utmp *ut) +{ + struct stat buf; + int fd, ret = 1; + + if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) { + logit("wtmp_write: problem writing %s: %s", + WTMP_FILE, strerror(errno)); + return 0; + } + if (fstat(fd, &buf) == 0) + if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) { + ftruncate(fd, buf.st_size); + logit("wtmp_write: problem writing %s: %s", + WTMP_FILE, strerror(errno)); + ret = 0; + } + (void)close(fd); + return ret; +} + +static int +wtmp_perform_login(struct logininfo *li) +{ + struct utmp ut; + + construct_utmp(li, &ut); + return wtmp_write(li, &ut); +} + + +static int +wtmp_perform_logout(struct logininfo *li) +{ + struct utmp ut; + + construct_utmp(li, &ut); + return wtmp_write(li, &ut); +} + + +int +wtmp_write_entry(struct logininfo *li) +{ + switch(li->type) { + case LTYPE_LOGIN: + return wtmp_perform_login(li); + case LTYPE_LOGOUT: + return wtmp_perform_logout(li); + default: + logit("wtmp_write_entry: invalid type field"); + return 0; + } +} + + +/* Notes on fetching login data from wtmp/wtmpx + * + * Logouts are usually recorded with (amongst other things) a blank + * username on a given tty line. However, some systems (HP-UX is one) + * leave all fields set, but change the ut_type field to DEAD_PROCESS. + * + * Since we're only looking for logins here, we know that the username + * must be set correctly. On systems that leave it in, we check for + * ut_type==USER_PROCESS (indicating a login.) + * + * Portability: Some systems may set something other than USER_PROCESS + * to indicate a login process. I don't know of any as I write. Also, + * it's possible that some systems may both leave the username in + * place and not have ut_type. + */ + +/* return true if this wtmp entry indicates a login */ +static int +wtmp_islogin(struct logininfo *li, struct utmp *ut) +{ + if (strncmp(li->username, ut->ut_name, + MIN_SIZEOF(li->username, ut->ut_name)) == 0) { +# ifdef HAVE_TYPE_IN_UTMP + if (ut->ut_type & USER_PROCESS) + return 1; +# else + return 1; +# endif + } + return 0; +} + +int +wtmp_get_entry(struct logininfo *li) +{ + struct stat st; + struct utmp ut; + int fd, found=0; + + /* Clear the time entries in our logininfo */ + li->tv_sec = li->tv_usec = 0; + + if ((fd = open(WTMP_FILE, O_RDONLY)) < 0) { + logit("wtmp_get_entry: problem opening %s: %s", + WTMP_FILE, strerror(errno)); + return 0; + } + if (fstat(fd, &st) != 0) { + logit("wtmp_get_entry: couldn't stat %s: %s", + WTMP_FILE, strerror(errno)); + close(fd); + return 0; + } + + /* Seek to the start of the last struct utmp */ + if (lseek(fd, -(off_t)sizeof(struct utmp), SEEK_END) == -1) { + /* Looks like we've got a fresh wtmp file */ + close(fd); + return 0; + } + + while (!found) { + if (atomicio(read, fd, &ut, sizeof(ut)) != sizeof(ut)) { + logit("wtmp_get_entry: read of %s failed: %s", + WTMP_FILE, strerror(errno)); + close (fd); + return 0; + } + if ( wtmp_islogin(li, &ut) ) { + found = 1; + /* We've already checked for a time in struct + * utmp, in login_getlast(). */ +# ifdef HAVE_TIME_IN_UTMP + li->tv_sec = ut.ut_time; +# else +# if HAVE_TV_IN_UTMP + li->tv_sec = ut.ut_tv.tv_sec; +# endif +# endif + line_fullname(li->line, ut.ut_line, + MIN_SIZEOF(li->line, ut.ut_line)); +# ifdef HAVE_HOST_IN_UTMP + strlcpy(li->hostname, ut.ut_host, + MIN_SIZEOF(li->hostname, ut.ut_host)); +# endif + continue; + } + /* Seek back 2 x struct utmp */ + if (lseek(fd, -(off_t)(2 * sizeof(struct utmp)), SEEK_CUR) == -1) { + /* We've found the start of the file, so quit */ + close (fd); + return 0; + } + } + + /* We found an entry. Tidy up and return */ + close(fd); + return 1; +} +# endif /* USE_WTMP */ + + +/** + ** Low-level wtmpx functions + **/ + +#ifdef USE_WTMPX +/* write a wtmpx entry direct to the end of the file */ +/* This is a slight modification of code in OpenBSD's logwtmp.c */ +static int +wtmpx_write(struct logininfo *li, struct utmpx *utx) +{ +#ifndef HAVE_UPDWTMPX + struct stat buf; + int fd, ret = 1; + + if ((fd = open(WTMPX_FILE, O_WRONLY|O_APPEND, 0)) < 0) { + logit("wtmpx_write: problem opening %s: %s", + WTMPX_FILE, strerror(errno)); + return 0; + } + + if (fstat(fd, &buf) == 0) + if (atomicio(vwrite, fd, utx, sizeof(*utx)) != sizeof(*utx)) { + ftruncate(fd, buf.st_size); + logit("wtmpx_write: problem writing %s: %s", + WTMPX_FILE, strerror(errno)); + ret = 0; + } + (void)close(fd); + + return ret; +#else + updwtmpx(WTMPX_FILE, utx); + return 1; +#endif +} + + +static int +wtmpx_perform_login(struct logininfo *li) +{ + struct utmpx utx; + + construct_utmpx(li, &utx); + return wtmpx_write(li, &utx); +} + + +static int +wtmpx_perform_logout(struct logininfo *li) +{ + struct utmpx utx; + + construct_utmpx(li, &utx); + return wtmpx_write(li, &utx); +} + + +int +wtmpx_write_entry(struct logininfo *li) +{ + switch(li->type) { + case LTYPE_LOGIN: + return wtmpx_perform_login(li); + case LTYPE_LOGOUT: + return wtmpx_perform_logout(li); + default: + logit("wtmpx_write_entry: invalid type field"); + return 0; + } +} + +/* Please see the notes above wtmp_islogin() for information about the + next two functions */ + +/* Return true if this wtmpx entry indicates a login */ +static int +wtmpx_islogin(struct logininfo *li, struct utmpx *utx) +{ + if ( strncmp(li->username, utx->ut_name, + MIN_SIZEOF(li->username, utx->ut_name)) == 0 ) { +# ifdef HAVE_TYPE_IN_UTMPX + if (utx->ut_type == USER_PROCESS) + return 1; +# else + return 1; +# endif + } + return 0; +} + + +int +wtmpx_get_entry(struct logininfo *li) +{ + struct stat st; + struct utmpx utx; + int fd, found=0; + + /* Clear the time entries */ + li->tv_sec = li->tv_usec = 0; + + if ((fd = open(WTMPX_FILE, O_RDONLY)) < 0) { + logit("wtmpx_get_entry: problem opening %s: %s", + WTMPX_FILE, strerror(errno)); + return 0; + } + if (fstat(fd, &st) != 0) { + logit("wtmpx_get_entry: couldn't stat %s: %s", + WTMPX_FILE, strerror(errno)); + close(fd); + return 0; + } + + /* Seek to the start of the last struct utmpx */ + if (lseek(fd, -(off_t)sizeof(struct utmpx), SEEK_END) == -1 ) { + /* probably a newly rotated wtmpx file */ + close(fd); + return 0; + } + + while (!found) { + if (atomicio(read, fd, &utx, sizeof(utx)) != sizeof(utx)) { + logit("wtmpx_get_entry: read of %s failed: %s", + WTMPX_FILE, strerror(errno)); + close (fd); + return 0; + } + /* Logouts are recorded as a blank username on a particular line. + * So, we just need to find the username in struct utmpx */ + if ( wtmpx_islogin(li, &utx) ) { + found = 1; +# ifdef HAVE_TV_IN_UTMPX + li->tv_sec = utx.ut_tv.tv_sec; +# else +# ifdef HAVE_TIME_IN_UTMPX + li->tv_sec = utx.ut_time; +# endif +# endif + line_fullname(li->line, utx.ut_line, sizeof(li->line)); +# ifdef HAVE_HOST_IN_UTMPX + strlcpy(li->hostname, utx.ut_host, + MIN_SIZEOF(li->hostname, utx.ut_host)); +# endif + continue; + } + if (lseek(fd, -(off_t)(2 * sizeof(struct utmpx)), SEEK_CUR) == -1) { + close (fd); + return 0; + } + } + + close(fd); + return 1; +} +#endif /* USE_WTMPX */ + +/** + ** Low-level libutil login() functions + **/ + +#ifdef USE_LOGIN +static int +syslogin_perform_login(struct logininfo *li) +{ + struct utmp *ut; + + if (! (ut = (struct utmp *)malloc(sizeof(*ut)))) { + logit("syslogin_perform_login: couldn't malloc()"); + return 0; + } + construct_utmp(li, ut); + login(ut); + free(ut); + + return 1; +} + +static int +syslogin_perform_logout(struct logininfo *li) +{ +# ifdef HAVE_LOGOUT + char line[UT_LINESIZE]; + + (void)line_stripname(line, li->line, sizeof(line)); + + if (!logout(line)) { + logit("syslogin_perform_logout: logout() returned an error"); +# ifdef HAVE_LOGWTMP + } else { + logwtmp(line, "", ""); +# endif + } + /* FIXME: (ATL - if the need arises) What to do if we have + * login, but no logout? what if logout but no logwtmp? All + * routines are in libutil so they should all be there, + * but... */ +# endif + return 1; +} + +int +syslogin_write_entry(struct logininfo *li) +{ + switch (li->type) { + case LTYPE_LOGIN: + return syslogin_perform_login(li); + case LTYPE_LOGOUT: + return syslogin_perform_logout(li); + default: + logit("syslogin_write_entry: Invalid type field"); + return 0; + } +} +#endif /* USE_LOGIN */ + +/* end of file log-syslogin.c */ + +/** + ** Low-level lastlog functions + **/ + +#ifdef USE_LASTLOG +#define LL_FILE 1 +#define LL_DIR 2 +#define LL_OTHER 3 + +static void +lastlog_construct(struct logininfo *li, struct lastlog *last) +{ + /* clear the structure */ + memset(last, '\0', sizeof(*last)); + + (void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line)); + strlcpy(last->ll_host, li->hostname, + MIN_SIZEOF(last->ll_host, li->hostname)); + last->ll_time = li->tv_sec; +} + +static int +lastlog_filetype(char *filename) +{ + struct stat st; + + if (stat(LASTLOG_FILE, &st) != 0) { + logit("lastlog_perform_login: Couldn't stat %s: %s", LASTLOG_FILE, + strerror(errno)); + return 0; + } + if (S_ISDIR(st.st_mode)) + return LL_DIR; + else if (S_ISREG(st.st_mode)) + return LL_FILE; + else + return LL_OTHER; +} + + +/* open the file (using filemode) and seek to the login entry */ +static int +lastlog_openseek(struct logininfo *li, int *fd, int filemode) +{ + off_t offset; + int type; + char lastlog_file[1024]; + + type = lastlog_filetype(LASTLOG_FILE); + switch (type) { + case LL_FILE: + strlcpy(lastlog_file, LASTLOG_FILE, sizeof(lastlog_file)); + break; + case LL_DIR: + snprintf(lastlog_file, sizeof(lastlog_file), "%s/%s", + LASTLOG_FILE, li->username); + break; + default: + logit("lastlog_openseek: %.100s is not a file or directory!", + LASTLOG_FILE); + return 0; + } + + *fd = open(lastlog_file, filemode, 0600); + if ( *fd < 0) { + debug("lastlog_openseek: Couldn't open %s: %s", + lastlog_file, strerror(errno)); + return 0; + } + + if (type == LL_FILE) { + /* find this uid's offset in the lastlog file */ + offset = (off_t) ((long)li->uid * sizeof(struct lastlog)); + + if ( lseek(*fd, offset, SEEK_SET) != offset ) { + logit("lastlog_openseek: %s->lseek(): %s", + lastlog_file, strerror(errno)); + return 0; + } + } + + return 1; +} + +static int +lastlog_perform_login(struct logininfo *li) +{ + struct lastlog last; + int fd; + + /* create our struct lastlog */ + lastlog_construct(li, &last); + + if (!lastlog_openseek(li, &fd, O_RDWR|O_CREAT)) + return(0); + + /* write the entry */ + if (atomicio(vwrite, fd, &last, sizeof(last)) != sizeof(last)) { + close(fd); + logit("lastlog_write_filemode: Error writing to %s: %s", + LASTLOG_FILE, strerror(errno)); + return 0; + } + + close(fd); + return 1; +} + +int +lastlog_write_entry(struct logininfo *li) +{ + switch(li->type) { + case LTYPE_LOGIN: + return lastlog_perform_login(li); + default: + logit("lastlog_write_entry: Invalid type field"); + return 0; + } +} + +static void +lastlog_populate_entry(struct logininfo *li, struct lastlog *last) +{ + line_fullname(li->line, last->ll_line, sizeof(li->line)); + strlcpy(li->hostname, last->ll_host, + MIN_SIZEOF(li->hostname, last->ll_host)); + li->tv_sec = last->ll_time; +} + +int +lastlog_get_entry(struct logininfo *li) +{ + struct lastlog last; + int fd, ret; + + if (!lastlog_openseek(li, &fd, O_RDONLY)) + return (0); + + ret = atomicio(read, fd, &last, sizeof(last)); + close(fd); + + switch (ret) { + case 0: + memset(&last, '\0', sizeof(last)); + /* FALLTHRU */ + case sizeof(last): + lastlog_populate_entry(li, &last); + return (1); + case -1: + error("%s: Error reading from %s: %s", __func__, + LASTLOG_FILE, strerror(errno)); + return (0); + default: + error("%s: Error reading from %s: Expecting %d, got %d", + __func__, LASTLOG_FILE, sizeof(last), ret); + return (0); + } + + /* NOTREACHED */ + return (0); +} +#endif /* USE_LASTLOG */ diff --git a/crypto/openssh-3.9p1/loginrec.h b/crypto/openssh-3.9p1/loginrec.h new file mode 100644 index 0000000000..7f932c2966 --- /dev/null +++ b/crypto/openssh-3.9p1/loginrec.h @@ -0,0 +1,135 @@ +#ifndef _HAVE_LOGINREC_H_ +#define _HAVE_LOGINREC_H_ + +/* + * Copyright (c) 2000 Andre Lucas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + ** loginrec.h: platform-independent login recording and lastlog retrieval + **/ + +#include "includes.h" + +#include +#include +#include + +/* RCSID("$Id: loginrec.h,v 1.7 2003/06/03 02:18:50 djm Exp $"); */ + +/** + ** you should use the login_* calls to work around platform dependencies + **/ + +/* + * login_netinfo structure + */ + +union login_netinfo { + struct sockaddr sa; + struct sockaddr_in sa_in; + struct sockaddr_storage sa_storage; +}; + +/* + * * logininfo structure * + */ +/* types - different to utmp.h 'type' macros */ +/* (though set to the same value as linux, openbsd and others...) */ +#define LTYPE_LOGIN 7 +#define LTYPE_LOGOUT 8 + +/* string lengths - set very long */ +#define LINFO_PROGSIZE 64 +#define LINFO_LINESIZE 64 +#define LINFO_NAMESIZE 64 +#define LINFO_HOSTSIZE 256 + +struct logininfo { + char progname[LINFO_PROGSIZE]; /* name of program (for PAM) */ + int progname_null; + short int type; /* type of login (LTYPE_*) */ + int pid; /* PID of login process */ + int uid; /* UID of this user */ + char line[LINFO_LINESIZE]; /* tty/pty name */ + char username[LINFO_NAMESIZE]; /* login username */ + char hostname[LINFO_HOSTSIZE]; /* remote hostname */ + /* 'exit_status' structure components */ + int exit; /* process exit status */ + int termination; /* process termination status */ + /* struct timeval (sys/time.h) isn't always available, if it isn't we'll + * use time_t's value as tv_sec and set tv_usec to 0 + */ + unsigned int tv_sec; + unsigned int tv_usec; + union login_netinfo hostaddr; /* caller's host address(es) */ +}; /* struct logininfo */ + +/* + * login recording functions + */ + +/** 'public' functions */ + +/* construct a new login entry */ +struct logininfo *login_alloc_entry(int pid, const char *username, + const char *hostname, const char *line); +/* free a structure */ +void login_free_entry(struct logininfo *li); +/* fill out a pre-allocated structure with useful information */ +int login_init_entry(struct logininfo *li, int pid, const char *username, + const char *hostname, const char *line); +/* place the current time in a logininfo struct */ +void login_set_current_time(struct logininfo *li); + +/* record the entry */ +int login_login (struct logininfo *li); +int login_logout(struct logininfo *li); +#ifdef LOGIN_NEEDS_UTMPX +int login_utmp_only(struct logininfo *li); +#endif + +/** End of public functions */ + +/* record the entry */ +int login_write (struct logininfo *li); +int login_log_entry(struct logininfo *li); + +/* set the network address based on network address type */ +void login_set_addr(struct logininfo *li, const struct sockaddr *sa, + const unsigned int sa_size); + +/* + * lastlog retrieval functions + */ +/* lastlog *entry* functions fill out a logininfo */ +struct logininfo *login_get_lastlog(struct logininfo *li, const int uid); +/* lastlog *time* functions return time_t equivalent (uint) */ +unsigned int login_get_lastlog_time(const int uid); + +/* produce various forms of the line filename */ +char *line_fullname(char *dst, const char *src, int dstsize); +char *line_stripname(char *dst, const char *src, int dstsize); +char *line_abbrevname(char *dst, const char *src, int dstsize); + +#endif /* _HAVE_LOGINREC_H_ */ diff --git a/crypto/openssh-3.9p1/logintest.c b/crypto/openssh-3.9p1/logintest.c new file mode 100644 index 0000000000..95cce5a3ab --- /dev/null +++ b/crypto/openssh-3.9p1/logintest.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2000 Andre Lucas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + ** logintest.c: simple test driver for platform-independent login recording + ** and lastlog retrieval + **/ + +#include "includes.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_TIME_H +#include +#endif + +#include "loginrec.h" + +RCSID("$Id: logintest.c,v 1.11 2004/07/17 04:07:42 dtucker Exp $"); + +extern char *__progname; + +#define PAUSE_BEFORE_LOGOUT 3 + +int nologtest = 0; +int compile_opts_only = 0; +int be_verbose = 0; + + +/* Dump a logininfo to stdout. Assumes a tab size of 8 chars. */ +void +dump_logininfo(struct logininfo *li, char *descname) +{ + /* yes I know how nasty this is */ + printf("struct logininfo %s = {\n\t" + "progname\t'%s'\n\ttype\t\t%d\n\t" + "pid\t\t%d\n\tuid\t\t%d\n\t" + "line\t\t'%s'\n\tusername\t'%s'\n\t" + "hostname\t'%s'\n\texit\t\t%d\n\ttermination\t%d\n\t" + "tv_sec\t%d\n\ttv_usec\t%d\n\t" + "struct login_netinfo hostaddr {\n\t\t" + "struct sockaddr sa {\n" + "\t\t\tfamily\t%d\n\t\t}\n" + "\t}\n" + "}\n", + descname, li->progname, li->type, + li->pid, li->uid, li->line, + li->username, li->hostname, li->exit, + li->termination, li->tv_sec, li->tv_usec, + li->hostaddr.sa.sa_family); +} + + +int +testAPI() +{ + struct logininfo *li1; + struct passwd *pw; + struct hostent *he; + struct sockaddr_in sa_in4; + char cmdstring[256], stripline[8]; + char username[32]; +#ifdef HAVE_TIME_H + time_t t0, t1, t2, logintime, logouttime; + char s_t0[64],s_t1[64],s_t2[64]; + char s_logintime[64], s_logouttime[64]; /* ctime() strings */ +#endif + + printf("**\n** Testing the API...\n**\n"); + + pw = getpwuid(getuid()); + strlcpy(username, pw->pw_name, sizeof(username)); + + /* gethostname(hostname, sizeof(hostname)); */ + + printf("login_alloc_entry test (no host info):\n"); + + /* FIXME fake tty more effectively - this could upset some platforms */ + li1 = login_alloc_entry((int)getpid(), username, NULL, ttyname(0)); + strlcpy(li1->progname, "OpenSSH-logintest", sizeof(li1->progname)); + + if (be_verbose) + dump_logininfo(li1, "li1"); + + printf("Setting host address info for 'localhost' (may call out):\n"); + if (! (he = gethostbyname("localhost"))) { + printf("Couldn't set hostname(lookup failed)\n"); + } else { + /* NOTE: this is messy, but typically a program wouldn't have to set + * any of this, a sockaddr_in* would be already prepared */ + memcpy((void *)&(sa_in4.sin_addr), (void *)&(he->h_addr_list[0][0]), + sizeof(struct in_addr)); + login_set_addr(li1, (struct sockaddr *) &sa_in4, sizeof(sa_in4)); + strlcpy(li1->hostname, "localhost", sizeof(li1->hostname)); + } + if (be_verbose) + dump_logininfo(li1, "li1"); + + if ((int)geteuid() != 0) { + printf("NOT RUNNING LOGIN TESTS - you are not root!\n"); + return 1; + } + + if (nologtest) + return 1; + + line_stripname(stripline, li1->line, sizeof(stripline)); + + printf("Performing an invalid login attempt (no type field)\n--\n"); + login_write(li1); + printf("--\n(Should have written errors to stderr)\n"); + +#ifdef HAVE_TIME_H + (void)time(&t0); + strlcpy(s_t0, ctime(&t0), sizeof(s_t0)); + t1 = login_get_lastlog_time(getuid()); + strlcpy(s_t1, ctime(&t1), sizeof(s_t1)); + printf("Before logging in:\n\tcurrent time is %d - %s\t" + "lastlog time is %d - %s\n", + (int)t0, s_t0, (int)t1, s_t1); +#endif + + printf("Performing a login on line %s ", stripline); +#ifdef HAVE_TIME_H + (void)time(&logintime); + strlcpy(s_logintime, ctime(&logintime), sizeof(s_logintime)); + printf("at %d - %s", (int)logintime, s_logintime); +#endif + printf("--\n"); + login_login(li1); + + snprintf(cmdstring, sizeof(cmdstring), "who | grep '%s '", + stripline); + system(cmdstring); + + printf("--\nPausing for %d second(s)...\n", PAUSE_BEFORE_LOGOUT); + sleep(PAUSE_BEFORE_LOGOUT); + + printf("Performing a logout "); +#ifdef HAVE_TIME_H + (void)time(&logouttime); + strlcpy(s_logouttime, ctime(&logouttime), sizeof(s_logouttime)); + printf("at %d - %s", (int)logouttime, s_logouttime); +#endif + printf("\nThe root login shown above should be gone.\n" + "If the root login hasn't gone, but another user on the same\n" + "pty has, this is OK - we're hacking it here, and there\n" + "shouldn't be two users on one pty in reality...\n" + "-- ('who' output follows)\n"); + login_logout(li1); + + system(cmdstring); + printf("-- ('who' output ends)\n"); + +#ifdef HAVE_TIME_H + t2 = login_get_lastlog_time(getuid()); + strlcpy(s_t2, ctime(&t2), sizeof(s_t2)); + printf("After logging in, lastlog time is %d - %s\n", (int)t2, s_t2); + if (t1 == t2) + printf("The lastlog times before and after logging in are the " + "same.\nThis indicates that lastlog is ** NOT WORKING " + "CORRECTLY **\n"); + else if (t0 != t2) + /* We can be off by a second or so, even when recording works fine. + * I'm not 100% sure why, but it's true. */ + printf("** The login time and the lastlog time differ.\n" + "** This indicates that lastlog is either recording the " + "wrong time,\n** or retrieving the wrong entry.\n" + "If it's off by less than %d second(s) " + "run the test again.\n", PAUSE_BEFORE_LOGOUT); + else + printf("lastlog agrees with the login time. This is a good thing.\n"); + +#endif + + printf("--\nThe output of 'last' shown next should have " + "an entry for root \n on %s for the time shown above:\n--\n", + stripline); + snprintf(cmdstring, sizeof(cmdstring), "last | grep '%s ' | head -3", + stripline); + system(cmdstring); + + printf("--\nEnd of login test.\n"); + + login_free_entry(li1); + + return 1; +} /* testAPI() */ + + +void +testLineName(char *line) +{ + /* have to null-terminate - these functions are designed for + * structures with fixed-length char arrays, and don't null-term.*/ + char full[17], strip[9], abbrev[5]; + + memset(full, '\0', sizeof(full)); + memset(strip, '\0', sizeof(strip)); + memset(abbrev, '\0', sizeof(abbrev)); + + line_fullname(full, line, sizeof(full)-1); + line_stripname(strip, full, sizeof(strip)-1); + line_abbrevname(abbrev, full, sizeof(abbrev)-1); + printf("%s: %s, %s, %s\n", line, full, strip, abbrev); + +} /* testLineName() */ + + +int +testOutput() +{ + printf("**\n** Testing linename functions\n**\n"); + testLineName("/dev/pts/1"); + testLineName("pts/1"); + testLineName("pts/999"); + testLineName("/dev/ttyp00"); + testLineName("ttyp00"); + + return 1; +} /* testOutput() */ + + +/* show which options got compiled in */ +void +showOptions(void) +{ + printf("**\n** Compile-time options\n**\n"); + + printf("login recording methods selected:\n"); +#ifdef USE_LOGIN + printf("\tUSE_LOGIN\n"); +#endif +#ifdef USE_UTMP + printf("\tUSE_UTMP (UTMP_FILE=%s)\n", UTMP_FILE); +#endif +#ifdef USE_UTMPX + printf("\tUSE_UTMPX (UTMPX_FILE=%s)\n", UTMPX_FILE); +#endif +#ifdef USE_WTMP + printf("\tUSE_WTMP (WTMP_FILE=%s)\n", WTMP_FILE); +#endif +#ifdef USE_WTMPX + printf("\tUSE_WTMPX (WTMPX_FILE=%s)\n", WTMPX_FILE); +#endif +#ifdef USE_LASTLOG + printf("\tUSE_LASTLOG (LASTLOG_FILE=%s)\n", LASTLOG_FILE); +#endif + printf("\n"); + +} /* showOptions() */ + + +int +main(int argc, char *argv[]) +{ + printf("Platform-independent login recording test driver\n"); + + __progname = ssh_get_progname(argv[0]); + if (argc == 2) { + if (strncmp(argv[1], "-i", 3) == 0) + compile_opts_only = 1; + else if (strncmp(argv[1], "-v", 3) == 0) + be_verbose=1; + } + + if (!compile_opts_only) { + if (be_verbose && !testOutput()) + return 1; + + if (!testAPI()) + return 1; + } + + showOptions(); + + return 0; +} /* main() */ + diff --git a/crypto/openssh-3.9p1/mac.c b/crypto/openssh-3.9p1/mac.c new file mode 100644 index 0000000000..097f0b93bf --- /dev/null +++ b/crypto/openssh-3.9p1/mac.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: mac.c,v 1.6 2003/09/18 13:02:21 miod Exp $"); + +#include + +#include "xmalloc.h" +#include "getput.h" +#include "log.h" +#include "cipher.h" +#include "kex.h" +#include "mac.h" + +struct { + char *name; + const EVP_MD * (*mdfunc)(void); + int truncatebits; /* truncate digest if != 0 */ +} macs[] = { + { "hmac-sha1", EVP_sha1, 0, }, + { "hmac-sha1-96", EVP_sha1, 96 }, + { "hmac-md5", EVP_md5, 0 }, + { "hmac-md5-96", EVP_md5, 96 }, + { "hmac-ripemd160", EVP_ripemd160, 0 }, + { "hmac-ripemd160@openssh.com", EVP_ripemd160, 0 }, + { NULL, NULL, 0 } +}; + +int +mac_init(Mac *mac, char *name) +{ + int i; + for (i = 0; macs[i].name; i++) { + if (strcmp(name, macs[i].name) == 0) { + if (mac != NULL) { + mac->md = (*macs[i].mdfunc)(); + mac->key_len = mac->mac_len = EVP_MD_size(mac->md); + if (macs[i].truncatebits != 0) + mac->mac_len = macs[i].truncatebits/8; + } + debug2("mac_init: found %s", name); + return (0); + } + } + debug2("mac_init: unknown %s", name); + return (-1); +} + +u_char * +mac_compute(Mac *mac, u_int32_t seqno, u_char *data, int datalen) +{ + HMAC_CTX c; + static u_char m[EVP_MAX_MD_SIZE]; + u_char b[4]; + + if (mac->key == NULL) + fatal("mac_compute: no key"); + if ((u_int)mac->mac_len > sizeof(m)) + fatal("mac_compute: mac too long"); + HMAC_Init(&c, mac->key, mac->key_len, mac->md); + PUT_32BIT(b, seqno); + HMAC_Update(&c, b, sizeof(b)); + HMAC_Update(&c, data, datalen); + HMAC_Final(&c, m, NULL); + HMAC_cleanup(&c); + return (m); +} + +/* XXX copied from ciphers_valid */ +#define MAC_SEP "," +int +mac_valid(const char *names) +{ + char *maclist, *cp, *p; + + if (names == NULL || strcmp(names, "") == 0) + return (0); + maclist = cp = xstrdup(names); + for ((p = strsep(&cp, MAC_SEP)); p && *p != '\0'; + (p = strsep(&cp, MAC_SEP))) { + if (mac_init(NULL, p) < 0) { + debug("bad mac %s [%s]", p, names); + xfree(maclist); + return (0); + } else { + debug3("mac ok: %s [%s]", p, names); + } + } + debug3("macs ok: [%s]", names); + xfree(maclist); + return (1); +} diff --git a/crypto/openssh-3.9p1/mac.h b/crypto/openssh-3.9p1/mac.h new file mode 100644 index 0000000000..43b485dd92 --- /dev/null +++ b/crypto/openssh-3.9p1/mac.h @@ -0,0 +1,28 @@ +/* $OpenBSD: mac.h,v 1.3 2001/06/26 17:27:24 markus Exp $ */ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +int mac_valid(const char *); +int mac_init(Mac *, char *); +u_char *mac_compute(Mac *, u_int32_t, u_char *, int); diff --git a/crypto/openssh-3.9p1/match.c b/crypto/openssh-3.9p1/match.c new file mode 100644 index 0000000000..3ddb627302 --- /dev/null +++ b/crypto/openssh-3.9p1/match.c @@ -0,0 +1,269 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Simple pattern matching, with '*' and '?' as wildcards. + * + * 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". + */ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: match.c,v 1.19 2002/03/01 13:12:10 markus Exp $"); + +#include "match.h" +#include "xmalloc.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) +{ + for (;;) { + /* If at end of pattern, accept if also at end of string. */ + if (!*pattern) + return !*s; + + 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 */ +} + +/* + * Tries to match the string against the + * comma-separated sequence of subpatterns (each possibly preceded by ! to + * indicate negation). Returns -1 if negation matches, 1 if there is + * a positive match, 0 if there is no match at all. + */ + +int +match_pattern_list(const char *string, const char *pattern, u_int len, + int dolower) +{ + char sub[1024]; + int negated; + int got_positive; + u_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] = dolower && 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 string. */ + if (match_pattern(string, sub)) { + if (negated) + return -1; /* Negative */ + else + got_positive = 1; /* Positive */ + } + } + + /* + * Return success if got a positive match. If there was a negative + * match, we have already returned -1 and never get here. + */ + return got_positive; +} + +/* + * 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 -1 if negation matches, 1 if there is + * a positive match, 0 if there is no match at all. + */ +int +match_hostname(const char *host, const char *pattern, u_int len) +{ + return match_pattern_list(host, pattern, len, 1); +} + +/* + * returns 0 if we get a negative match for the hostname or the ip + * or if we get no match at all. returns 1 otherwise. + */ +int +match_host_and_ip(const char *host, const char *ipaddr, + const char *patterns) +{ + int mhost, mip; + + /* negative ipaddr match */ + if ((mip = match_hostname(ipaddr, patterns, strlen(patterns))) == -1) + return 0; + /* negative hostname match */ + if ((mhost = match_hostname(host, patterns, strlen(patterns))) == -1) + return 0; + /* no match at all */ + if (mhost == 0 && mip == 0) + return 0; + return 1; +} + +/* + * match user, user@host_or_ip, user@host_or_ip_list against pattern + */ +int +match_user(const char *user, const char *host, const char *ipaddr, + const char *pattern) +{ + char *p, *pat; + int ret; + + if ((p = strchr(pattern,'@')) == NULL) + return match_pattern(user, pattern); + + pat = xstrdup(pattern); + p = strchr(pat, '@'); + *p++ = '\0'; + + if ((ret = match_pattern(user, pat)) == 1) + ret = match_host_and_ip(host, ipaddr, p); + xfree(pat); + + return ret; +} + +/* + * Returns first item from client-list that is also supported by server-list, + * caller must xfree() returned string. + */ +#define MAX_PROP 40 +#define SEP "," +char * +match_list(const char *client, const char *server, u_int *next) +{ + char *sproposals[MAX_PROP]; + char *c, *s, *p, *ret, *cp, *sp; + int i, j, nproposals; + + c = cp = xstrdup(client); + s = sp = xstrdup(server); + + for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&sp, SEP)), i++) { + if (i < MAX_PROP) + sproposals[i] = p; + else + break; + } + nproposals = i; + + for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; + (p = strsep(&cp, SEP)), i++) { + for (j = 0; j < nproposals; j++) { + if (strcmp(p, sproposals[j]) == 0) { + ret = xstrdup(p); + if (next != NULL) + *next = (cp == NULL) ? + strlen(c) : cp - c; + xfree(c); + xfree(s); + return ret; + } + } + } + if (next != NULL) + *next = strlen(c); + xfree(c); + xfree(s); + return NULL; +} diff --git a/crypto/openssh-3.9p1/match.h b/crypto/openssh-3.9p1/match.h new file mode 100644 index 0000000000..a0764e0013 --- /dev/null +++ b/crypto/openssh-3.9p1/match.h @@ -0,0 +1,24 @@ +/* $OpenBSD: match.h,v 1.12 2002/03/01 13:12:10 markus Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ +#ifndef MATCH_H +#define MATCH_H + +int match_pattern(const char *, const char *); +int match_pattern_list(const char *, const char *, u_int, int); +int match_hostname(const char *, const char *, u_int); +int match_host_and_ip(const char *, const char *, const char *); +int match_user(const char *, const char *, const char *, const char *); +char *match_list(const char *, const char *, u_int *); + +#endif diff --git a/crypto/openssh-3.9p1/md5crypt.c b/crypto/openssh-3.9p1/md5crypt.c new file mode 100644 index 0000000000..8f2523e621 --- /dev/null +++ b/crypto/openssh-3.9p1/md5crypt.c @@ -0,0 +1,165 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this + * notice you can do whatever you want with this stuff. If we meet some + * day, and you think this stuff is worth it, you can buy me a beer in + * return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + +#include "includes.h" + +#if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) +#include + +RCSID("$Id: md5crypt.c,v 1.9 2003/11/21 12:56:47 djm Exp $"); + +/* 0 ... 63 => ascii - 64 */ +static unsigned char itoa64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static char *magic = "$1$"; + +static char * +to64(unsigned long v, int n) +{ + static char buf[5]; + char *s = buf; + + if (n > 4) + return (NULL); + + memset(buf, '\0', sizeof(buf)); + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } + + return (buf); +} + +int +is_md5_salt(const char *salt) +{ + return (strncmp(salt, magic, strlen(magic)) == 0); +} + +char * +md5_crypt(const char *pw, const char *salt) +{ + static char passwd[120], salt_copy[9], *p; + static const char *sp, *ep; + unsigned char final[16]; + int sl, pl, i, j; + MD5_CTX ctx, ctx1; + unsigned long l; + + /* Refine the Salt first */ + sp = salt; + + /* If it starts with the magic string, then skip that */ + if(strncmp(sp, magic, strlen(magic)) == 0) + sp += strlen(magic); + + /* It stops at the first '$', max 8 chars */ + for (ep = sp; *ep != '$'; ep++) { + if (*ep == '\0' || ep >= (sp + 8)) + return (NULL); + } + + /* get the length of the true salt */ + sl = ep - sp; + + /* Stash the salt */ + memcpy(salt_copy, sp, sl); + salt_copy[sl] = '\0'; + + MD5_Init(&ctx); + + /* The password first, since that is what is most unknown */ + MD5_Update(&ctx, pw, strlen(pw)); + + /* Then our magic string */ + MD5_Update(&ctx, magic, strlen(magic)); + + /* Then the raw salt */ + MD5_Update(&ctx, sp, sl); + + /* Then just as many characters of the MD5(pw, salt, pw) */ + MD5_Init(&ctx1); + MD5_Update(&ctx1, pw, strlen(pw)); + MD5_Update(&ctx1, sp, sl); + MD5_Update(&ctx1, pw, strlen(pw)); + MD5_Final(final, &ctx1); + + for(pl = strlen(pw); pl > 0; pl -= 16) + MD5_Update(&ctx, final, pl > 16 ? 16 : pl); + + /* Don't leave anything around in vm they could use. */ + memset(final, '\0', sizeof final); + + /* Then something really weird... */ + for (j = 0, i = strlen(pw); i != 0; i >>= 1) + if (i & 1) + MD5_Update(&ctx, final + j, 1); + else + MD5_Update(&ctx, pw + j, 1); + + /* Now make the output string */ + snprintf(passwd, sizeof(passwd), "%s%s$", magic, salt_copy); + + MD5_Final(final, &ctx); + + /* + * and now, just to make sure things don't run too fast + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for(i = 0; i < 1000; i++) { + MD5_Init(&ctx1); + if (i & 1) + MD5_Update(&ctx1, pw, strlen(pw)); + else + MD5_Update(&ctx1, final, 16); + + if (i % 3) + MD5_Update(&ctx1, sp, sl); + + if (i % 7) + MD5_Update(&ctx1, pw, strlen(pw)); + + if (i & 1) + MD5_Update(&ctx1, final, 16); + else + MD5_Update(&ctx1, pw, strlen(pw)); + + MD5_Final(final, &ctx1); + } + + p = passwd + strlen(passwd); + + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; + strlcat(passwd, to64(l, 4), sizeof(passwd)); + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; + strlcat(passwd, to64(l, 4), sizeof(passwd)); + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; + strlcat(passwd, to64(l, 4), sizeof(passwd)); + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; + strlcat(passwd, to64(l, 4), sizeof(passwd)); + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; + strlcat(passwd, to64(l, 4), sizeof(passwd)); + l = final[11] ; + strlcat(passwd, to64(l, 2), sizeof(passwd)); + + /* Don't leave anything around in vm they could use. */ + memset(final, 0, sizeof(final)); + memset(salt_copy, 0, sizeof(salt_copy)); + memset(&ctx, 0, sizeof(ctx)); + memset(&ctx1, 0, sizeof(ctx1)); + (void)to64(0, 4); + + return (passwd); +} + +#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */ diff --git a/crypto/openssh-3.9p1/md5crypt.h b/crypto/openssh-3.9p1/md5crypt.h new file mode 100644 index 0000000000..2341e2c125 --- /dev/null +++ b/crypto/openssh-3.9p1/md5crypt.h @@ -0,0 +1,24 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + +/* $Id: md5crypt.h,v 1.4 2003/05/18 14:46:46 djm Exp $ */ + +#ifndef _MD5CRYPT_H +#define _MD5CRYPT_H + +#include "config.h" + +#if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) + +int is_md5_salt(const char *); +char *md5_crypt(const char *, const char *); + +#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */ + +#endif /* MD5CRYPT_H */ diff --git a/crypto/openssh-3.9p1/misc.c b/crypto/openssh-3.9p1/misc.c new file mode 100644 index 0000000000..8cb411ccc9 --- /dev/null +++ b/crypto/openssh-3.9p1/misc.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: misc.c,v 1.25 2004/08/11 21:43:05 avsm Exp $"); + +#include "misc.h" +#include "log.h" +#include "xmalloc.h" + +/* remove newline at end of string */ +char * +chop(char *s) +{ + char *t = s; + while (*t) { + if (*t == '\n' || *t == '\r') { + *t = '\0'; + return s; + } + t++; + } + return s; + +} + +/* set/unset filedescriptor to non-blocking */ +int +set_nonblock(int fd) +{ + int val; + + val = fcntl(fd, F_GETFL, 0); + if (val < 0) { + error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); + return (-1); + } + if (val & O_NONBLOCK) { + debug3("fd %d is O_NONBLOCK", fd); + return (0); + } + debug2("fd %d setting O_NONBLOCK", fd); + val |= O_NONBLOCK; + if (fcntl(fd, F_SETFL, val) == -1) { + debug("fcntl(%d, F_SETFL, O_NONBLOCK): %s", fd, + strerror(errno)); + return (-1); + } + return (0); +} + +int +unset_nonblock(int fd) +{ + int val; + + val = fcntl(fd, F_GETFL, 0); + if (val < 0) { + error("fcntl(%d, F_GETFL, 0): %s", fd, strerror(errno)); + return (-1); + } + if (!(val & O_NONBLOCK)) { + debug3("fd %d is not O_NONBLOCK", fd); + return (0); + } + debug("fd %d clearing O_NONBLOCK", fd); + val &= ~O_NONBLOCK; + if (fcntl(fd, F_SETFL, val) == -1) { + debug("fcntl(%d, F_SETFL, ~O_NONBLOCK): %s", + fd, strerror(errno)); + return (-1); + } + return (0); +} + +/* disable nagle on socket */ +void +set_nodelay(int fd) +{ + int opt; + socklen_t optlen; + + optlen = sizeof opt; + if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, &optlen) == -1) { + debug("getsockopt TCP_NODELAY: %.100s", strerror(errno)); + return; + } + if (opt == 1) { + debug2("fd %d is TCP_NODELAY", fd); + return; + } + opt = 1; + debug2("fd %d setting TCP_NODELAY", fd); + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof opt) == -1) + error("setsockopt TCP_NODELAY: %.100s", strerror(errno)); +} + +/* Characters considered whitespace in strsep calls. */ +#define WHITESPACE " \t\r\n" + +/* return next token in configuration line */ +char * +strdelim(char **s) +{ + char *old; + int wspace = 0; + + if (*s == NULL) + return NULL; + + old = *s; + + *s = strpbrk(*s, WHITESPACE "="); + if (*s == NULL) + return (old); + + /* Allow only one '=' to be skipped */ + if (*s[0] == '=') + wspace = 1; + *s[0] = '\0'; + + *s += strspn(*s + 1, WHITESPACE) + 1; + if (*s[0] == '=' && !wspace) + *s += strspn(*s + 1, WHITESPACE) + 1; + + return (old); +} + +struct passwd * +pwcopy(struct passwd *pw) +{ + struct passwd *copy = xmalloc(sizeof(*copy)); + + memset(copy, 0, sizeof(*copy)); + copy->pw_name = xstrdup(pw->pw_name); + copy->pw_passwd = xstrdup(pw->pw_passwd); + copy->pw_gecos = xstrdup(pw->pw_gecos); + copy->pw_uid = pw->pw_uid; + copy->pw_gid = pw->pw_gid; +#ifdef HAVE_PW_EXPIRE_IN_PASSWD + copy->pw_expire = pw->pw_expire; +#endif +#ifdef HAVE_PW_CHANGE_IN_PASSWD + copy->pw_change = pw->pw_change; +#endif +#ifdef HAVE_PW_CLASS_IN_PASSWD + copy->pw_class = xstrdup(pw->pw_class); +#endif + copy->pw_dir = xstrdup(pw->pw_dir); + copy->pw_shell = xstrdup(pw->pw_shell); + return copy; +} + +/* + * Convert ASCII string to TCP/IP port number. + * Port must be >0 and <=65535. + * Return 0 if invalid. + */ +int +a2port(const char *s) +{ + long port; + char *endp; + + errno = 0; + port = strtol(s, &endp, 0); + if (s == endp || *endp != '\0' || + (errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || + port <= 0 || port > 65535) + return 0; + + return port; +} + +#define SECONDS 1 +#define MINUTES (SECONDS * 60) +#define HOURS (MINUTES * 60) +#define DAYS (HOURS * 24) +#define WEEKS (DAYS * 7) + +/* + * Convert a time string into seconds; format is + * a sequence of: + * time[qualifier] + * + * Valid time qualifiers are: + * seconds + * s|S seconds + * m|M minutes + * h|H hours + * d|D days + * w|W weeks + * + * Examples: + * 90m 90 minutes + * 1h30m 90 minutes + * 2d 2 days + * 1w 1 week + * + * Return -1 if time string is invalid. + */ +long +convtime(const char *s) +{ + long total, secs; + const char *p; + char *endp; + + errno = 0; + total = 0; + p = s; + + if (p == NULL || *p == '\0') + return -1; + + while (*p) { + secs = strtol(p, &endp, 10); + if (p == endp || + (errno == ERANGE && (secs == LONG_MIN || secs == LONG_MAX)) || + secs < 0) + return -1; + + switch (*endp++) { + case '\0': + endp--; + case 's': + case 'S': + break; + case 'm': + case 'M': + secs *= MINUTES; + break; + case 'h': + case 'H': + secs *= HOURS; + break; + case 'd': + case 'D': + secs *= DAYS; + break; + case 'w': + case 'W': + secs *= WEEKS; + break; + default: + return -1; + } + total += secs; + if (total < 0) + return -1; + p = endp; + } + + return total; +} + +char * +cleanhostname(char *host) +{ + if (*host == '[' && host[strlen(host) - 1] == ']') { + host[strlen(host) - 1] = '\0'; + return (host + 1); + } else + return host; +} + +char * +colon(char *cp) +{ + int flag = 0; + + if (*cp == ':') /* Leading colon is part of file name. */ + return (0); + if (*cp == '[') + flag = 1; + + for (; *cp; ++cp) { + if (*cp == '@' && *(cp+1) == '[') + flag = 1; + if (*cp == ']' && *(cp+1) == ':' && flag) + return (cp+1); + if (*cp == ':' && !flag) + return (cp); + if (*cp == '/') + return (0); + } + return (0); +} + +/* function to assist building execv() arguments */ +void +addargs(arglist *args, char *fmt, ...) +{ + va_list ap; + char buf[1024]; + u_int nalloc; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + nalloc = args->nalloc; + if (args->list == NULL) { + nalloc = 32; + args->num = 0; + } else if (args->num+2 >= nalloc) + nalloc *= 2; + + args->list = xrealloc(args->list, nalloc * sizeof(char *)); + args->nalloc = nalloc; + args->list[args->num++] = xstrdup(buf); + args->list[args->num] = NULL; +} diff --git a/crypto/openssh-3.9p1/misc.h b/crypto/openssh-3.9p1/misc.h new file mode 100644 index 0000000000..ec47a611d4 --- /dev/null +++ b/crypto/openssh-3.9p1/misc.h @@ -0,0 +1,48 @@ +/* $OpenBSD: misc.h,v 1.17 2004/08/11 21:43:05 avsm Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +/* misc.c */ + +char *chop(char *); +char *strdelim(char **); +int set_nonblock(int); +int unset_nonblock(int); +void set_nodelay(int); +int a2port(const char *); +char *cleanhostname(char *); +char *colon(char *); +long convtime(const char *); + +struct passwd *pwcopy(struct passwd *); + +typedef struct arglist arglist; +struct arglist { + char **list; + u_int num; + u_int nalloc; +}; +void addargs(arglist *, char *, ...) __attribute__((format(printf, 2, 3))); + +/* tildexpand.c */ + +char *tilde_expand_filename(const char *, uid_t); + +/* readpass.c */ + +#define RP_ECHO 0x0001 +#define RP_ALLOW_STDIN 0x0002 +#define RP_ALLOW_EOF 0x0004 +#define RP_USE_ASKPASS 0x0008 + +char *read_passphrase(const char *, int); diff --git a/crypto/openssh-3.9p1/moduli b/crypto/openssh-3.9p1/moduli new file mode 100644 index 0000000000..52639d336c --- /dev/null +++ b/crypto/openssh-3.9p1/moduli @@ -0,0 +1,186 @@ +# $OpenBSD: moduli,v 1.2 2004/01/28 04:44:00 dtucker Exp $ + +# Time Type Tests Tries Size Generator Modulus +20031210004503 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB22C583AB +20031210004553 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB22D0A0D7 +20031210004628 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB22D6CB97 +20031210004801 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB22F2D1B7 +20031210004827 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB22F5615B +20031210004919 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB230138C3 +20031210004952 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB2305F6A3 +20031210005018 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB230801DB +20031210005043 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB230A0383 +20031210005147 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB231C3A7F +20031210005230 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB23249C1B +20031210005301 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB23288F0F +20031210005438 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB2344EC9B +20031210005548 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB235892F3 +20031210005700 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB236C3F03 +20031210005841 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB238BC713 +20031210010040 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB23B466C3 +20031210010119 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB23BB1F8B +20031210010313 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB23E03DDB +20031210010335 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB23E130AB +20031210010422 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB23EA20A3 +20031210010500 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB23F1807B +20031210010628 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB2409DC07 +20031210010759 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB2425487F +20031210010906 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB24397A3F +20031210010945 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB2440ABF7 +20031210011017 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB2445C00B +20031210011059 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB244E4EBF +20031210011158 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB245E056B +20031210011340 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB24808F43 +20031210011408 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB24834C0B +20031210011517 2 6 100 1023 2 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB2495148B +20031210011632 2 6 100 1023 5 DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61EF75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D2683705577D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E3826634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB24A89B27 +20031210014802 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772D3B9DD3 +20031210015017 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772D463D83 +20031210015524 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772D68288B +20031210015701 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772D6C64C3 +20031210020258 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772D94316B +20031210022106 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772E1F8453 +20031210022738 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772E4BDAC7 +20031210022948 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772E5541E7 +20031210023056 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772E56464B +20031210023414 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772E695C8B +20031210024039 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772E939ABF +20031210024457 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772EAE295B +20031210024630 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772EB2BDFB +20031210025118 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772ED059DB +20031210025540 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772EECB4D3 +20031210025956 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F043973 +20031210030256 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F134903 +20031210030415 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F15B5EB +20031210030717 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F25BF3B +20031210030826 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F2670D7 +20031210031055 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F31E5F3 +20031210031311 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F3BFE2B +20031210032243 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F83082B +20031210032437 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F898187 +20031210032703 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772F95718B +20031210032953 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772FA3F5CB +20031210033059 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772FA48FEB +20031210033247 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772FAA6267 +20031210033633 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772FC1BE7B +20031210034313 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772FF18FA7 +20031210034507 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A772FF84977 +20031210035121 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A7730233FBF +20031210035813 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A773054E8F3 +20031210035955 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A7730597847 +20031210040259 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A77306A1B57 +20031210040704 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A77308258FB +20031210040913 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A77308A63F7 +20031210042047 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A7730DEEF8F +20031210042156 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A7730DFE787 +20031210042511 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A7730F1D3CB +20031210042907 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A773107039B +20031210043815 2 6 100 1535 5 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A7731492E37 +20031210045243 2 6 100 1535 2 FB54DC620BB7A5C2A28520E9FFC81958D7A76156412B647E9FCC729F84553FFB4428705868631244E0F804376D5F434C76608B93626D3AA169360C9DD40DFA3429F2E53AA4014730B49FFB6CCBC7FF9D0C391341610280598F7F8EE4E4F956683C59A740C7AB17A5C628694D4C36E6D6A54629822059ACD4C7C8C860262E7CBD04196BB41E7D194C91CFAB58353072EA09390E795733510D69D1267376B2FFA7BA2C88028820012DC84F6F250D88D1B6B44E22FCCDCDD3A3EC654A7731AB1953 +20031210054833 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1C0B0F8B +20031210055609 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1C1CF773 +20031210065401 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1CDD973F +20031210071146 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1D11D9FB +20031210071754 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1D1ED47B +20031210072552 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1D32CE4F +20031210073644 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1D4EC983 +20031210074309 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1D5D4F07 +20031210075517 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1D7DE133 +20031210081718 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1DC395C3 +20031210084322 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1E1A5567 +20031210085218 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1E3127AB +20031210090542 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1E586AD7 +20031210093920 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1EC6C9D3 +20031210100616 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1F19C713 +20031210103627 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1F7B82B3 +20031210104559 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1F95C2EF +20031210104836 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1F969EAF +20031210110201 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1FBEA0DF +20031210111610 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1FE4C70B +20031210111837 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1FE50DBB +20031210112215 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F1FE964FF +20031210124102 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F20F33023 +20031210125610 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F21208AFB +20031210130630 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F213CBA8B +20031210132517 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F21754843 +20031210132855 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F2179D39B +20031210140211 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F21E6E73B +20031210141340 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F22068817 +20031210143133 2 6 100 2047 5 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F223D6017 +20031210143812 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F224A70F3 +20031210150410 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F22A24CFB +20031210153131 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F22FAA253 +20031210153718 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F23071C7B +20031210154203 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F230FFC0B +20031210161808 2 6 100 2047 2 EEFD0DF9B60CBF61DDBA3364F8B6254256FC2DF3211B1D80F4556816C5D629B0A40228861BEE7B4497444DD9375EF7E8997BB7294C6AA097A1E5AD47DB72C14956898FD11CA292ED76215E09D8067835150928D5F09267B29214159C0CB695EECC90E05C0E21374ED6F04759B3F0E162EE2CFBC8259BC1A1F28C809700E1F3ECBA24A99A78BCCC6E776348705837F86A2B4A34DB592753468905179802788F52C337E0187F69C30D52C99546290D09154EAFEE72F9CA32A989AA45AD68220539A6AA302AEA4DCCCE7E6FCF6DEE57440A4511B4BAF5B4832D27247FDED231168413B12A0E1147A5706C56238788A7707463452E1254F2503BA197756F2383B65B +20031210185714 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061924F36F3 +20031210204537 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306192C04AB3 +20031210205604 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306192C3734B +20031210210523 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306192C58A0B +20031210233701 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306193680D03 +20031211013125 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306193E1DD73 +20031211052015 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306194DA94E3 +20031211064439 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619531A017 +20031211074935 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306195731BAB +20031211081053 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306195830BAB +20031211123240 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306196A4C097 +20031211160831 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061978B740B +20031211195847 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619889E1B3 +20031211201456 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619892ED83 +20031211221441 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619910A74B +20031211223303 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061991D35CB +20031211235558 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306199712CCB +20031212005818 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A306199AE96DB +20031212033251 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619A50DDD3 +20031212053332 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619AB31B57 +20031212084926 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619B8949F7 +20031212130319 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619C84A1A3 +20031212192346 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619E1B24BB +20031212210042 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619E7F37FB +20031213002102 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A30619F59BABB +20031213061439 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A0D9208F +20031213071620 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A115D66F +20031213072644 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A1186097 +20031213090613 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A17DACC7 +20031213110037 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A1F577E7 +20031213113226 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A2113AC3 +20031213120232 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A22A232B +20031213121926 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A23443D3 +20031213130353 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A25D51E7 +20031213143149 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A2B63CBB +20031213153322 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A2F05FC7 +20031213180906 2 6 100 3071 2 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A39439A3 +20031213183520 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A3A7705F +20031213192228 2 6 100 3071 5 DBB2151A52F948EE950BE096B2B7C2A260C5BBE57C02EC432FA6E2025306FE486F77352C63622A8F40A65ECD815737C9837C7803980D25CBFAA3438A1BA8A7D41F214A836AB31A067B5813967059AE75B73358FE33930E7B9BEE4149CD71A9234F9E7C35C5097456E2BF17F748E70FB2AB12BC9D75C1BB024CCEA7556384034A22840352DA1CF6EB9E09FA6C5B6317A74DF67318935850079364F06665282743B45E0ABE6866867FB13BE2A082F604E0BA399215A072CE818104A53F37D08F0373CE7DBBF4EBCEFF05349A025A7DD06D5E79205CD74919862E06BFD15990391BBBA75BD27A36C422165AA6CA14F6A1AA5CEB6D862456C7BDA91982DF12D159B859248A9159B935635199498628871815BF0C9F0706265988F9ABB278CBBB941A07E46A713D8F2C10E174C3E4138C3C125BF582359E4D6C3773609C9D6293C22C620AAAE50EF3BDFA3B97D802993BFE0E7BE01FAB3F3E8CE4A2454E5A01E2C08DE17D9D5B9F76D8466FBA22A14C11CA5C7E678514FD72B3DF3D0A3061A3D2DEA7 +20031213125532 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923E8050C3B +20031213125653 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923E8EB2F2B +20031213125813 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923EAB66F4B +20031213125934 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923EAFE508B +20031213130055 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923EB96812B +20031213130217 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923EBB738CB +20031213130337 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923EBDB337F +20031213130458 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923ECA8B62B +20031213130619 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923ECBCE443 +20031213130740 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923ED1637DB +20031213130901 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923ED3EA08F +20031213131021 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923EDC96C6B +20031213131142 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923EEB92FCF +20031213131303 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923F2D2CCF3 +20031213131424 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923F6C89BBB +20031213131545 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923F7962EDB +20031213131706 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923F85A4767 +20031213131827 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923F8A196C7 +20031213131947 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923F94500EF +20031213132108 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923FAF467BF +20031213132229 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923FB5A7803 +20031213132350 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923FB7D5467 +20031213132511 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923FC4A16D7 +20031213132632 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923FEEDC36F +20031213132752 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9923FFA077EF +20031213132913 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA992400725B7B +20031213133034 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA992400728FFB +20031213133155 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9924011CFA13 +20031213133316 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA99240165703F +20031213133436 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA99240166BA7B +20031213133557 2 6 200 4095 5 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA9924018E41B7 +20031213133718 2 6 200 4095 2 CE96240B0B5684D9E281FDA07D5B6C316E14C7AE83913F86D13CAD2546F93B533D15629D4B3E2C76753C5ABCC29A8FB610CA1C3EB1014B0FD8209C330FFF6EB8A562474B7D387E3F8074FA29D0B58BAD5E6967A0AD667C41D41E1241669431F865C57E9EEB00E69BEB1D18C3B940810324B394FAB8F75B27A9B4E7972F07B4916A6A3D50F0445024697155382BF1AD14F90F8BAB7E9D3CCBAE6CD84E488A98770A8C64943582C6D2BB529511945ABA146115273EB6BD718B62FEBFCD503FB56E8D4262E17DC5CE1A9B1D3E8FFA5CE0B825498BC6254DA9CC69DDF7AD9BA582AB8F812C4DE3228C88C5640BAEF5F62B7C039588D6CD7F694F039507AA3AAF4FB368A3712230FFC05B66A14C7003E2AD6A938D544B8B9908C4536F945AC4BDB1CA623F2826A25CA16B39730C9FE940A8642EB35088ED341BE768C10B152C8A65D32E4DBE68764E6B2ABDE6824088B6BE258D7E3AEA155CB919E1C500CDCEE435515CF09575F75551C16FBA0F3AEDE0AABA544E89A58E4C34E255EAAFD8F65340DAA55E3ED8AB903FE188416340ACE15D36F9CEDE379CC3586E6D320F72AA310A1B0A781D06B7418A50525105FA749306AC59A788D6866B7DDD0F4C059BA6CEE43FAD5AD2A362B9DE1C57324ADE8B5B46C6B1DDABD82F0670F7A4DA869F204EFB27EA7E049BC7D6CFD2071682C894161922A99108EB3BB8922113BA992402C07A93 diff --git a/crypto/openssh-3.9p1/moduli.c b/crypto/openssh-3.9p1/moduli.c new file mode 100644 index 0000000000..581b03503d --- /dev/null +++ b/crypto/openssh-3.9p1/moduli.c @@ -0,0 +1,654 @@ +/* $OpenBSD: moduli.c,v 1.9 2004/07/11 17:48:47 deraadt Exp $ */ +/* + * Copyright 1994 Phil Karn + * Copyright 1996-1998, 2003 William Allen Simpson + * Copyright 2000 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Two-step process to generate safe primes for DHGEX + * + * Sieve candidates for "safe" primes, + * suitable for use as Diffie-Hellman moduli; + * that is, where q = (p-1)/2 is also prime. + * + * First step: generate candidate primes (memory intensive) + * Second step: test primes' safety (processor intensive) + */ + +#include "includes.h" +#include "xmalloc.h" +#include "log.h" + +#include + +/* + * File output defines + */ + +/* need line long enough for largest moduli plus headers */ +#define QLINESIZE (100+8192) + +/* Type: decimal. + * Specifies the internal structure of the prime modulus. + */ +#define QTYPE_UNKNOWN (0) +#define QTYPE_UNSTRUCTURED (1) +#define QTYPE_SAFE (2) +#define QTYPE_SCHNOOR (3) +#define QTYPE_SOPHIE_GERMAIN (4) +#define QTYPE_STRONG (5) + +/* Tests: decimal (bit field). + * Specifies the methods used in checking for primality. + * Usually, more than one test is used. + */ +#define QTEST_UNTESTED (0x00) +#define QTEST_COMPOSITE (0x01) +#define QTEST_SIEVE (0x02) +#define QTEST_MILLER_RABIN (0x04) +#define QTEST_JACOBI (0x08) +#define QTEST_ELLIPTIC (0x10) + +/* + * Size: decimal. + * Specifies the number of the most significant bit (0 to M). + * WARNING: internally, usually 1 to N. + */ +#define QSIZE_MINIMUM (511) + +/* + * Prime sieving defines + */ + +/* Constant: assuming 8 bit bytes and 32 bit words */ +#define SHIFT_BIT (3) +#define SHIFT_BYTE (2) +#define SHIFT_WORD (SHIFT_BIT+SHIFT_BYTE) +#define SHIFT_MEGABYTE (20) +#define SHIFT_MEGAWORD (SHIFT_MEGABYTE-SHIFT_BYTE) + +/* + * Using virtual memory can cause thrashing. This should be the largest + * number that is supported without a large amount of disk activity -- + * that would increase the run time from hours to days or weeks! + */ +#define LARGE_MINIMUM (8UL) /* megabytes */ + +/* + * Do not increase this number beyond the unsigned integer bit size. + * Due to a multiple of 4, it must be LESS than 128 (yielding 2**30 bits). + */ +#define LARGE_MAXIMUM (127UL) /* megabytes */ + +/* + * Constant: when used with 32-bit integers, the largest sieve prime + * has to be less than 2**32. + */ +#define SMALL_MAXIMUM (0xffffffffUL) + +/* Constant: can sieve all primes less than 2**32, as 65537**2 > 2**32-1. */ +#define TINY_NUMBER (1UL<<16) + +/* Ensure enough bit space for testing 2*q. */ +#define TEST_MAXIMUM (1UL<<16) +#define TEST_MINIMUM (QSIZE_MINIMUM + 1) +/* real TEST_MINIMUM (1UL << (SHIFT_WORD - TEST_POWER)) */ +#define TEST_POWER (3) /* 2**n, n < SHIFT_WORD */ + +/* bit operations on 32-bit words */ +#define BIT_CLEAR(a,n) ((a)[(n)>>SHIFT_WORD] &= ~(1L << ((n) & 31))) +#define BIT_SET(a,n) ((a)[(n)>>SHIFT_WORD] |= (1L << ((n) & 31))) +#define BIT_TEST(a,n) ((a)[(n)>>SHIFT_WORD] & (1L << ((n) & 31))) + +/* + * Prime testing defines + */ + +/* Minimum number of primality tests to perform */ +#define TRIAL_MINIMUM (4) + +/* + * Sieving data (XXX - move to struct) + */ + +/* sieve 2**16 */ +static u_int32_t *TinySieve, tinybits; + +/* sieve 2**30 in 2**16 parts */ +static u_int32_t *SmallSieve, smallbits, smallbase; + +/* sieve relative to the initial value */ +static u_int32_t *LargeSieve, largewords, largetries, largenumbers; +static u_int32_t largebits, largememory; /* megabytes */ +static BIGNUM *largebase; + +int gen_candidates(FILE *, int, int, BIGNUM *); +int prime_test(FILE *, FILE *, u_int32_t, u_int32_t); + +/* + * print moduli out in consistent form, + */ +static int +qfileout(FILE * ofile, u_int32_t otype, u_int32_t otests, u_int32_t otries, + u_int32_t osize, u_int32_t ogenerator, BIGNUM * omodulus) +{ + struct tm *gtm; + time_t time_now; + int res; + + time(&time_now); + gtm = gmtime(&time_now); + + res = fprintf(ofile, "%04d%02d%02d%02d%02d%02d %u %u %u %u %x ", + gtm->tm_year + 1900, gtm->tm_mon + 1, gtm->tm_mday, + gtm->tm_hour, gtm->tm_min, gtm->tm_sec, + otype, otests, otries, osize, ogenerator); + + if (res < 0) + return (-1); + + if (BN_print_fp(ofile, omodulus) < 1) + return (-1); + + res = fprintf(ofile, "\n"); + fflush(ofile); + + return (res > 0 ? 0 : -1); +} + + +/* + ** Sieve p's and q's with small factors + */ +static void +sieve_large(u_int32_t s) +{ + u_int32_t r, u; + + debug3("sieve_large %u", s); + largetries++; + /* r = largebase mod s */ + r = BN_mod_word(largebase, s); + if (r == 0) + u = 0; /* s divides into largebase exactly */ + else + u = s - r; /* largebase+u is first entry divisible by s */ + + if (u < largebits * 2) { + /* + * The sieve omits p's and q's divisible by 2, so ensure that + * largebase+u is odd. Then, step through the sieve in + * increments of 2*s + */ + if (u & 0x1) + u += s; /* Make largebase+u odd, and u even */ + + /* Mark all multiples of 2*s */ + for (u /= 2; u < largebits; u += s) + BIT_SET(LargeSieve, u); + } + + /* r = p mod s */ + r = (2 * r + 1) % s; + if (r == 0) + u = 0; /* s divides p exactly */ + else + u = s - r; /* p+u is first entry divisible by s */ + + if (u < largebits * 4) { + /* + * The sieve omits p's divisible by 4, so ensure that + * largebase+u is not. Then, step through the sieve in + * increments of 4*s + */ + while (u & 0x3) { + if (SMALL_MAXIMUM - u < s) + return; + u += s; + } + + /* Mark all multiples of 4*s */ + for (u /= 4; u < largebits; u += s) + BIT_SET(LargeSieve, u); + } +} + +/* + * list candidates for Sophie-Germain primes (where q = (p-1)/2) + * to standard output. + * The list is checked against small known primes (less than 2**30). + */ +int +gen_candidates(FILE *out, int memory, int power, BIGNUM *start) +{ + BIGNUM *q; + u_int32_t j, r, s, t; + u_int32_t smallwords = TINY_NUMBER >> 6; + u_int32_t tinywords = TINY_NUMBER >> 6; + time_t time_start, time_stop; + int i, ret = 0; + + largememory = memory; + + if (memory != 0 && + (memory < LARGE_MINIMUM || memory > LARGE_MAXIMUM)) { + error("Invalid memory amount (min %ld, max %ld)", + LARGE_MINIMUM, LARGE_MAXIMUM); + return (-1); + } + + /* + * Set power to the length in bits of the prime to be generated. + * This is changed to 1 less than the desired safe prime moduli p. + */ + if (power > TEST_MAXIMUM) { + error("Too many bits: %u > %lu", power, TEST_MAXIMUM); + return (-1); + } else if (power < TEST_MINIMUM) { + error("Too few bits: %u < %u", power, TEST_MINIMUM); + return (-1); + } + power--; /* decrement before squaring */ + + /* + * The density of ordinary primes is on the order of 1/bits, so the + * density of safe primes should be about (1/bits)**2. Set test range + * to something well above bits**2 to be reasonably sure (but not + * guaranteed) of catching at least one safe prime. + */ + largewords = ((power * power) >> (SHIFT_WORD - TEST_POWER)); + + /* + * Need idea of how much memory is available. We don't have to use all + * of it. + */ + if (largememory > LARGE_MAXIMUM) { + logit("Limited memory: %u MB; limit %lu MB", + largememory, LARGE_MAXIMUM); + largememory = LARGE_MAXIMUM; + } + + if (largewords <= (largememory << SHIFT_MEGAWORD)) { + logit("Increased memory: %u MB; need %u bytes", + largememory, (largewords << SHIFT_BYTE)); + largewords = (largememory << SHIFT_MEGAWORD); + } else if (largememory > 0) { + logit("Decreased memory: %u MB; want %u bytes", + largememory, (largewords << SHIFT_BYTE)); + largewords = (largememory << SHIFT_MEGAWORD); + } + + TinySieve = calloc(tinywords, sizeof(u_int32_t)); + if (TinySieve == NULL) { + error("Insufficient memory for tiny sieve: need %u bytes", + tinywords << SHIFT_BYTE); + exit(1); + } + tinybits = tinywords << SHIFT_WORD; + + SmallSieve = calloc(smallwords, sizeof(u_int32_t)); + if (SmallSieve == NULL) { + error("Insufficient memory for small sieve: need %u bytes", + smallwords << SHIFT_BYTE); + xfree(TinySieve); + exit(1); + } + smallbits = smallwords << SHIFT_WORD; + + /* + * dynamically determine available memory + */ + while ((LargeSieve = calloc(largewords, sizeof(u_int32_t))) == NULL) + largewords -= (1L << (SHIFT_MEGAWORD - 2)); /* 1/4 MB chunks */ + + largebits = largewords << SHIFT_WORD; + largenumbers = largebits * 2; /* even numbers excluded */ + + /* validation check: count the number of primes tried */ + largetries = 0; + q = BN_new(); + + /* + * Generate random starting point for subprime search, or use + * specified parameter. + */ + largebase = BN_new(); + if (start == NULL) + BN_rand(largebase, power, 1, 1); + else + BN_copy(largebase, start); + + /* ensure odd */ + BN_set_bit(largebase, 0); + + time(&time_start); + + logit("%.24s Sieve next %u plus %u-bit", ctime(&time_start), + largenumbers, power); + debug2("start point: 0x%s", BN_bn2hex(largebase)); + + /* + * TinySieve + */ + for (i = 0; i < tinybits; i++) { + if (BIT_TEST(TinySieve, i)) + continue; /* 2*i+3 is composite */ + + /* The next tiny prime */ + t = 2 * i + 3; + + /* Mark all multiples of t */ + for (j = i + t; j < tinybits; j += t) + BIT_SET(TinySieve, j); + + sieve_large(t); + } + + /* + * Start the small block search at the next possible prime. To avoid + * fencepost errors, the last pass is skipped. + */ + for (smallbase = TINY_NUMBER + 3; + smallbase < (SMALL_MAXIMUM - TINY_NUMBER); + smallbase += TINY_NUMBER) { + for (i = 0; i < tinybits; i++) { + if (BIT_TEST(TinySieve, i)) + continue; /* 2*i+3 is composite */ + + /* The next tiny prime */ + t = 2 * i + 3; + r = smallbase % t; + + if (r == 0) { + s = 0; /* t divides into smallbase exactly */ + } else { + /* smallbase+s is first entry divisible by t */ + s = t - r; + } + + /* + * The sieve omits even numbers, so ensure that + * smallbase+s is odd. Then, step through the sieve + * in increments of 2*t + */ + if (s & 1) + s += t; /* Make smallbase+s odd, and s even */ + + /* Mark all multiples of 2*t */ + for (s /= 2; s < smallbits; s += t) + BIT_SET(SmallSieve, s); + } + + /* + * SmallSieve + */ + for (i = 0; i < smallbits; i++) { + if (BIT_TEST(SmallSieve, i)) + continue; /* 2*i+smallbase is composite */ + + /* The next small prime */ + sieve_large((2 * i) + smallbase); + } + + memset(SmallSieve, 0, smallwords << SHIFT_BYTE); + } + + time(&time_stop); + + logit("%.24s Sieved with %u small primes in %ld seconds", + ctime(&time_stop), largetries, (long) (time_stop - time_start)); + + for (j = r = 0; j < largebits; j++) { + if (BIT_TEST(LargeSieve, j)) + continue; /* Definitely composite, skip */ + + debug2("test q = largebase+%u", 2 * j); + BN_set_word(q, 2 * j); + BN_add(q, q, largebase); + if (qfileout(out, QTYPE_SOPHIE_GERMAIN, QTEST_SIEVE, + largetries, (power - 1) /* MSB */, (0), q) == -1) { + ret = -1; + break; + } + + r++; /* count q */ + } + + time(&time_stop); + + xfree(LargeSieve); + xfree(SmallSieve); + xfree(TinySieve); + + logit("%.24s Found %u candidates", ctime(&time_stop), r); + + return (ret); +} + +/* + * perform a Miller-Rabin primality test + * on the list of candidates + * (checking both q and p) + * The result is a list of so-call "safe" primes + */ +int +prime_test(FILE *in, FILE *out, u_int32_t trials, u_int32_t generator_wanted) +{ + BIGNUM *q, *p, *a; + BN_CTX *ctx; + char *cp, *lp; + u_int32_t count_in = 0, count_out = 0, count_possible = 0; + u_int32_t generator_known, in_tests, in_tries, in_type, in_size; + time_t time_start, time_stop; + int res; + + if (trials < TRIAL_MINIMUM) { + error("Minimum primality trials is %d", TRIAL_MINIMUM); + return (-1); + } + + time(&time_start); + + p = BN_new(); + q = BN_new(); + ctx = BN_CTX_new(); + + debug2("%.24s Final %u Miller-Rabin trials (%x generator)", + ctime(&time_start), trials, generator_wanted); + + res = 0; + lp = xmalloc(QLINESIZE + 1); + while (fgets(lp, QLINESIZE, in) != NULL) { + int ll = strlen(lp); + + count_in++; + if (ll < 14 || *lp == '!' || *lp == '#') { + debug2("%10u: comment or short line", count_in); + continue; + } + + /* XXX - fragile parser */ + /* time */ + cp = &lp[14]; /* (skip) */ + + /* type */ + in_type = strtoul(cp, &cp, 10); + + /* tests */ + in_tests = strtoul(cp, &cp, 10); + + if (in_tests & QTEST_COMPOSITE) { + debug2("%10u: known composite", count_in); + continue; + } + + /* tries */ + in_tries = strtoul(cp, &cp, 10); + + /* size (most significant bit) */ + in_size = strtoul(cp, &cp, 10); + + /* generator (hex) */ + generator_known = strtoul(cp, &cp, 16); + + /* Skip white space */ + cp += strspn(cp, " "); + + /* modulus (hex) */ + switch (in_type) { + case QTYPE_SOPHIE_GERMAIN: + debug2("%10u: (%u) Sophie-Germain", count_in, in_type); + a = q; + BN_hex2bn(&a, cp); + /* p = 2*q + 1 */ + BN_lshift(p, q, 1); + BN_add_word(p, 1); + in_size += 1; + generator_known = 0; + break; + case QTYPE_UNSTRUCTURED: + case QTYPE_SAFE: + case QTYPE_SCHNOOR: + case QTYPE_STRONG: + case QTYPE_UNKNOWN: + debug2("%10u: (%u)", count_in, in_type); + a = p; + BN_hex2bn(&a, cp); + /* q = (p-1) / 2 */ + BN_rshift(q, p, 1); + break; + default: + debug2("Unknown prime type"); + break; + } + + /* + * due to earlier inconsistencies in interpretation, check + * the proposed bit size. + */ + if (BN_num_bits(p) != (in_size + 1)) { + debug2("%10u: bit size %u mismatch", count_in, in_size); + continue; + } + if (in_size < QSIZE_MINIMUM) { + debug2("%10u: bit size %u too short", count_in, in_size); + continue; + } + + if (in_tests & QTEST_MILLER_RABIN) + in_tries += trials; + else + in_tries = trials; + + /* + * guess unknown generator + */ + if (generator_known == 0) { + if (BN_mod_word(p, 24) == 11) + generator_known = 2; + else if (BN_mod_word(p, 12) == 5) + generator_known = 3; + else { + u_int32_t r = BN_mod_word(p, 10); + + if (r == 3 || r == 7) + generator_known = 5; + } + } + /* + * skip tests when desired generator doesn't match + */ + if (generator_wanted > 0 && + generator_wanted != generator_known) { + debug2("%10u: generator %d != %d", + count_in, generator_known, generator_wanted); + continue; + } + + /* + * Primes with no known generator are useless for DH, so + * skip those. + */ + if (generator_known == 0) { + debug2("%10u: no known generator", count_in); + continue; + } + + count_possible++; + + /* + * The (1/4)^N performance bound on Miller-Rabin is + * extremely pessimistic, so don't spend a lot of time + * really verifying that q is prime until after we know + * that p is also prime. A single pass will weed out the + * vast majority of composite q's. + */ + if (BN_is_prime(q, 1, NULL, ctx, NULL) <= 0) { + debug("%10u: q failed first possible prime test", + count_in); + continue; + } + + /* + * q is possibly prime, so go ahead and really make sure + * that p is prime. If it is, then we can go back and do + * the same for q. If p is composite, chances are that + * will show up on the first Rabin-Miller iteration so it + * doesn't hurt to specify a high iteration count. + */ + if (!BN_is_prime(p, trials, NULL, ctx, NULL)) { + debug("%10u: p is not prime", count_in); + continue; + } + debug("%10u: p is almost certainly prime", count_in); + + /* recheck q more rigorously */ + if (!BN_is_prime(q, trials - 1, NULL, ctx, NULL)) { + debug("%10u: q is not prime", count_in); + continue; + } + debug("%10u: q is almost certainly prime", count_in); + + if (qfileout(out, QTYPE_SAFE, (in_tests | QTEST_MILLER_RABIN), + in_tries, in_size, generator_known, p)) { + res = -1; + break; + } + + count_out++; + } + + time(&time_stop); + xfree(lp); + BN_free(p); + BN_free(q); + BN_CTX_free(ctx); + + logit("%.24s Found %u safe primes of %u candidates in %ld seconds", + ctime(&time_stop), count_out, count_possible, + (long) (time_stop - time_start)); + + return (res); +} diff --git a/crypto/openssh-3.9p1/monitor.c b/crypto/openssh-3.9p1/monitor.c new file mode 100644 index 0000000000..b7463400e6 --- /dev/null +++ b/crypto/openssh-3.9p1/monitor.c @@ -0,0 +1,1849 @@ +/* + * Copyright 2002 Niels Provos + * Copyright 2002 Markus Friedl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: monitor.c,v 1.61 2004/07/17 05:31:41 dtucker Exp $"); + +#include + +#ifdef SKEY +#include +#endif + +#include "ssh.h" +#include "auth.h" +#include "kex.h" +#include "dh.h" +#ifdef TARGET_OS_MAC /* XXX Broken krb5 headers on Mac */ +#undef TARGET_OS_MAC +#include "zlib.h" +#define TARGET_OS_MAC 1 +#else +#include "zlib.h" +#endif +#include "packet.h" +#include "auth-options.h" +#include "sshpty.h" +#include "channels.h" +#include "session.h" +#include "sshlogin.h" +#include "canohost.h" +#include "log.h" +#include "servconf.h" +#include "monitor.h" +#include "monitor_mm.h" +#include "monitor_wrap.h" +#include "monitor_fdpass.h" +#include "xmalloc.h" +#include "misc.h" +#include "buffer.h" +#include "bufaux.h" +#include "compat.h" +#include "ssh2.h" + +#ifdef GSSAPI +#include "ssh-gss.h" +static Gssctxt *gsscontext = NULL; +#endif + +/* Imports */ +extern ServerOptions options; +extern u_int utmp_len; +extern Newkeys *current_keys[]; +extern z_stream incoming_stream; +extern z_stream outgoing_stream; +extern u_char session_id[]; +extern Buffer input, output; +extern Buffer auth_debug; +extern int auth_debug_init; +extern Buffer loginmsg; + +/* State exported from the child */ + +struct { + z_stream incoming; + z_stream outgoing; + u_char *keyin; + u_int keyinlen; + u_char *keyout; + u_int keyoutlen; + u_char *ivin; + u_int ivinlen; + u_char *ivout; + u_int ivoutlen; + u_char *ssh1key; + u_int ssh1keylen; + int ssh1cipher; + int ssh1protoflags; + u_char *input; + u_int ilen; + u_char *output; + u_int olen; +} child_state; + +/* Functions on the monitor that answer unprivileged requests */ + +int mm_answer_moduli(int, Buffer *); +int mm_answer_sign(int, Buffer *); +int mm_answer_pwnamallow(int, Buffer *); +int mm_answer_auth2_read_banner(int, Buffer *); +int mm_answer_authserv(int, Buffer *); +int mm_answer_authpassword(int, Buffer *); +int mm_answer_bsdauthquery(int, Buffer *); +int mm_answer_bsdauthrespond(int, Buffer *); +int mm_answer_skeyquery(int, Buffer *); +int mm_answer_skeyrespond(int, Buffer *); +int mm_answer_keyallowed(int, Buffer *); +int mm_answer_keyverify(int, Buffer *); +int mm_answer_pty(int, Buffer *); +int mm_answer_pty_cleanup(int, Buffer *); +int mm_answer_term(int, Buffer *); +int mm_answer_rsa_keyallowed(int, Buffer *); +int mm_answer_rsa_challenge(int, Buffer *); +int mm_answer_rsa_response(int, Buffer *); +int mm_answer_sesskey(int, Buffer *); +int mm_answer_sessid(int, Buffer *); + +#ifdef USE_PAM +int mm_answer_pam_start(int, Buffer *); +int mm_answer_pam_account(int, Buffer *); +int mm_answer_pam_init_ctx(int, Buffer *); +int mm_answer_pam_query(int, Buffer *); +int mm_answer_pam_respond(int, Buffer *); +int mm_answer_pam_free_ctx(int, Buffer *); +#endif + +#ifdef GSSAPI +int mm_answer_gss_setup_ctx(int, Buffer *); +int mm_answer_gss_accept_ctx(int, Buffer *); +int mm_answer_gss_userok(int, Buffer *); +int mm_answer_gss_checkmic(int, Buffer *); +#endif + +static Authctxt *authctxt; +static BIGNUM *ssh1_challenge = NULL; /* used for ssh1 rsa auth */ + +/* local state for key verify */ +static u_char *key_blob = NULL; +static u_int key_bloblen = 0; +static int key_blobtype = MM_NOKEY; +static char *hostbased_cuser = NULL; +static char *hostbased_chost = NULL; +static char *auth_method = "unknown"; +static u_int session_id2_len = 0; +static u_char *session_id2 = NULL; +static pid_t monitor_child_pid; + +struct mon_table { + enum monitor_reqtype type; + int flags; + int (*f)(int, Buffer *); +}; + +#define MON_ISAUTH 0x0004 /* Required for Authentication */ +#define MON_AUTHDECIDE 0x0008 /* Decides Authentication */ +#define MON_ONCE 0x0010 /* Disable after calling */ + +#define MON_AUTH (MON_ISAUTH|MON_AUTHDECIDE) + +#define MON_PERMIT 0x1000 /* Request is permitted */ + +struct mon_table mon_dispatch_proto20[] = { + {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, + {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, + {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, + {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, +#ifdef USE_PAM + {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, + {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, + {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, + {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, + {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond}, + {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx}, +#endif +#ifdef BSD_AUTH + {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, + {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond}, +#endif +#ifdef SKEY + {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, + {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, +#endif + {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, + {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, +#ifdef GSSAPI + {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, + {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, + {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, + {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic}, +#endif + {0, 0, NULL} +}; + +struct mon_table mon_dispatch_postauth20[] = { + {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, + {MONITOR_REQ_SIGN, 0, mm_answer_sign}, + {MONITOR_REQ_PTY, 0, mm_answer_pty}, + {MONITOR_REQ_PTYCLEANUP, 0, mm_answer_pty_cleanup}, + {MONITOR_REQ_TERM, 0, mm_answer_term}, + {0, 0, NULL} +}; + +struct mon_table mon_dispatch_proto15[] = { + {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, + {MONITOR_REQ_SESSKEY, MON_ONCE, mm_answer_sesskey}, + {MONITOR_REQ_SESSID, MON_ONCE, mm_answer_sessid}, + {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, + {MONITOR_REQ_RSAKEYALLOWED, MON_ISAUTH, mm_answer_rsa_keyallowed}, + {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, + {MONITOR_REQ_RSACHALLENGE, MON_ONCE, mm_answer_rsa_challenge}, + {MONITOR_REQ_RSARESPONSE, MON_ONCE|MON_AUTHDECIDE, mm_answer_rsa_response}, +#ifdef BSD_AUTH + {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, + {MONITOR_REQ_BSDAUTHRESPOND, MON_AUTH,mm_answer_bsdauthrespond}, +#endif +#ifdef SKEY + {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery}, + {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond}, +#endif +#ifdef USE_PAM + {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start}, + {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, + {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx}, + {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query}, + {MONITOR_REQ_PAM_RESPOND, MON_ISAUTH, mm_answer_pam_respond}, + {MONITOR_REQ_PAM_FREE_CTX, MON_ONCE|MON_AUTHDECIDE, mm_answer_pam_free_ctx}, +#endif + {0, 0, NULL} +}; + +struct mon_table mon_dispatch_postauth15[] = { + {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty}, + {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup}, + {MONITOR_REQ_TERM, 0, mm_answer_term}, + {0, 0, NULL} +}; + +struct mon_table *mon_dispatch; + +/* Specifies if a certain message is allowed at the moment */ + +static void +monitor_permit(struct mon_table *ent, enum monitor_reqtype type, int permit) +{ + while (ent->f != NULL) { + if (ent->type == type) { + ent->flags &= ~MON_PERMIT; + ent->flags |= permit ? MON_PERMIT : 0; + return; + } + ent++; + } +} + +static void +monitor_permit_authentications(int permit) +{ + struct mon_table *ent = mon_dispatch; + + while (ent->f != NULL) { + if (ent->flags & MON_AUTH) { + ent->flags &= ~MON_PERMIT; + ent->flags |= permit ? MON_PERMIT : 0; + } + ent++; + } +} + +void +monitor_child_preauth(Authctxt *_authctxt, struct monitor *pmonitor) +{ + struct mon_table *ent; + int authenticated = 0; + + debug3("preauth child monitor started"); + + authctxt = _authctxt; + memset(authctxt, 0, sizeof(*authctxt)); + + if (compat20) { + mon_dispatch = mon_dispatch_proto20; + + /* Permit requests for moduli and signatures */ + monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); + } else { + mon_dispatch = mon_dispatch_proto15; + + monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); + } + + /* The first few requests do not require asynchronous access */ + while (!authenticated) { + authenticated = monitor_read(pmonitor, mon_dispatch, &ent); + if (authenticated) { + if (!(ent->flags & MON_AUTHDECIDE)) + fatal("%s: unexpected authentication from %d", + __func__, ent->type); + if (authctxt->pw->pw_uid == 0 && + !auth_root_allowed(auth_method)) + authenticated = 0; +#ifdef USE_PAM + /* PAM needs to perform account checks after auth */ + if (options.use_pam && authenticated) { + Buffer m; + + buffer_init(&m); + mm_request_receive_expect(pmonitor->m_sendfd, + MONITOR_REQ_PAM_ACCOUNT, &m); + authenticated = mm_answer_pam_account(pmonitor->m_sendfd, &m); + buffer_free(&m); + } +#endif + } + + if (ent->flags & MON_AUTHDECIDE) { + auth_log(authctxt, authenticated, auth_method, + compat20 ? " ssh2" : ""); + if (!authenticated) + authctxt->failures++; + } + } + + if (!authctxt->valid) + fatal("%s: authenticated invalid user", __func__); + + debug("%s: %s has been authenticated by privileged process", + __func__, authctxt->user); + + mm_get_keystate(pmonitor); +} + +static void +monitor_set_child_handler(pid_t pid) +{ + monitor_child_pid = pid; +} + +static void +monitor_child_handler(int sig) +{ + kill(monitor_child_pid, sig); +} + +void +monitor_child_postauth(struct monitor *pmonitor) +{ + monitor_set_child_handler(pmonitor->m_pid); + signal(SIGHUP, &monitor_child_handler); + signal(SIGTERM, &monitor_child_handler); + + if (compat20) { + mon_dispatch = mon_dispatch_postauth20; + + /* Permit requests for moduli and signatures */ + monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); + } else { + mon_dispatch = mon_dispatch_postauth15; + monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); + } + if (!no_pty_flag) { + monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1); + } + + for (;;) + monitor_read(pmonitor, mon_dispatch, NULL); +} + +void +monitor_sync(struct monitor *pmonitor) +{ + if (options.compression) { + /* The member allocation is not visible, so sync it */ + mm_share_sync(&pmonitor->m_zlib, &pmonitor->m_zback); + } +} + +int +monitor_read(struct monitor *pmonitor, struct mon_table *ent, + struct mon_table **pent) +{ + Buffer m; + int ret; + u_char type; + + buffer_init(&m); + + mm_request_receive(pmonitor->m_sendfd, &m); + type = buffer_get_char(&m); + + debug3("%s: checking request %d", __func__, type); + + while (ent->f != NULL) { + if (ent->type == type) + break; + ent++; + } + + if (ent->f != NULL) { + if (!(ent->flags & MON_PERMIT)) + fatal("%s: unpermitted request %d", __func__, + type); + ret = (*ent->f)(pmonitor->m_sendfd, &m); + buffer_free(&m); + + /* The child may use this request only once, disable it */ + if (ent->flags & MON_ONCE) { + debug2("%s: %d used once, disabling now", __func__, + type); + ent->flags &= ~MON_PERMIT; + } + + if (pent != NULL) + *pent = ent; + + return ret; + } + + fatal("%s: unsupported request: %d", __func__, type); + + /* NOTREACHED */ + return (-1); +} + +/* allowed key state */ +static int +monitor_allowed_key(u_char *blob, u_int bloblen) +{ + /* make sure key is allowed */ + if (key_blob == NULL || key_bloblen != bloblen || + memcmp(key_blob, blob, key_bloblen)) + return (0); + return (1); +} + +static void +monitor_reset_key_state(void) +{ + /* reset state */ + if (key_blob != NULL) + xfree(key_blob); + if (hostbased_cuser != NULL) + xfree(hostbased_cuser); + if (hostbased_chost != NULL) + xfree(hostbased_chost); + key_blob = NULL; + key_bloblen = 0; + key_blobtype = MM_NOKEY; + hostbased_cuser = NULL; + hostbased_chost = NULL; +} + +int +mm_answer_moduli(int sock, Buffer *m) +{ + DH *dh; + int min, want, max; + + min = buffer_get_int(m); + want = buffer_get_int(m); + max = buffer_get_int(m); + + debug3("%s: got parameters: %d %d %d", + __func__, min, want, max); + /* We need to check here, too, in case the child got corrupted */ + if (max < min || want < min || max < want) + fatal("%s: bad parameters: %d %d %d", + __func__, min, want, max); + + buffer_clear(m); + + dh = choose_dh(min, want, max); + if (dh == NULL) { + buffer_put_char(m, 0); + return (0); + } else { + /* Send first bignum */ + buffer_put_char(m, 1); + buffer_put_bignum2(m, dh->p); + buffer_put_bignum2(m, dh->g); + + DH_free(dh); + } + mm_request_send(sock, MONITOR_ANS_MODULI, m); + return (0); +} + +int +mm_answer_sign(int sock, Buffer *m) +{ + Key *key; + u_char *p; + u_char *signature; + u_int siglen, datlen; + int keyid; + + debug3("%s", __func__); + + keyid = buffer_get_int(m); + p = buffer_get_string(m, &datlen); + + if (datlen != 20) + fatal("%s: data length incorrect: %u", __func__, datlen); + + /* save session id, it will be passed on the first call */ + if (session_id2_len == 0) { + session_id2_len = datlen; + session_id2 = xmalloc(session_id2_len); + memcpy(session_id2, p, session_id2_len); + } + + if ((key = get_hostkey_by_index(keyid)) == NULL) + fatal("%s: no hostkey from index %d", __func__, keyid); + if (key_sign(key, &signature, &siglen, p, datlen) < 0) + fatal("%s: key_sign failed", __func__); + + debug3("%s: signature %p(%u)", __func__, signature, siglen); + + buffer_clear(m); + buffer_put_string(m, signature, siglen); + + xfree(p); + xfree(signature); + + mm_request_send(sock, MONITOR_ANS_SIGN, m); + + /* Turn on permissions for getpwnam */ + monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); + + return (0); +} + +/* Retrieves the password entry and also checks if the user is permitted */ + +int +mm_answer_pwnamallow(int sock, Buffer *m) +{ + char *username; + struct passwd *pwent; + int allowed = 0; + + debug3("%s", __func__); + + if (authctxt->attempt++ != 0) + fatal("%s: multiple attempts for getpwnam", __func__); + + username = buffer_get_string(m, NULL); + + pwent = getpwnamallow(username); + + authctxt->user = xstrdup(username); + setproctitle("%s [priv]", pwent ? username : "unknown"); + xfree(username); + + buffer_clear(m); + + if (pwent == NULL) { + buffer_put_char(m, 0); + authctxt->pw = fakepw(); + goto out; + } + + allowed = 1; + authctxt->pw = pwent; + authctxt->valid = 1; + + buffer_put_char(m, 1); + buffer_put_string(m, pwent, sizeof(struct passwd)); + buffer_put_cstring(m, pwent->pw_name); + buffer_put_cstring(m, "*"); + buffer_put_cstring(m, pwent->pw_gecos); +#ifdef HAVE_PW_CLASS_IN_PASSWD + buffer_put_cstring(m, pwent->pw_class); +#endif + buffer_put_cstring(m, pwent->pw_dir); + buffer_put_cstring(m, pwent->pw_shell); + + out: + debug3("%s: sending MONITOR_ANS_PWNAM: %d", __func__, allowed); + mm_request_send(sock, MONITOR_ANS_PWNAM, m); + + /* For SSHv1 allow authentication now */ + if (!compat20) + monitor_permit_authentications(1); + else { + /* Allow service/style information on the auth context */ + monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); + } + +#ifdef USE_PAM + if (options.use_pam) + monitor_permit(mon_dispatch, MONITOR_REQ_PAM_START, 1); +#endif + + return (0); +} + +int mm_answer_auth2_read_banner(int sock, Buffer *m) +{ + char *banner; + + buffer_clear(m); + banner = auth2_read_banner(); + buffer_put_cstring(m, banner != NULL ? banner : ""); + mm_request_send(sock, MONITOR_ANS_AUTH2_READ_BANNER, m); + + if (banner != NULL) + xfree(banner); + + return (0); +} + +int +mm_answer_authserv(int sock, Buffer *m) +{ + monitor_permit_authentications(1); + + authctxt->service = buffer_get_string(m, NULL); + authctxt->style = buffer_get_string(m, NULL); + debug3("%s: service=%s, style=%s", + __func__, authctxt->service, authctxt->style); + + if (strlen(authctxt->style) == 0) { + xfree(authctxt->style); + authctxt->style = NULL; + } + + return (0); +} + +int +mm_answer_authpassword(int sock, Buffer *m) +{ + static int call_count; + char *passwd; + int authenticated; + u_int plen; + + passwd = buffer_get_string(m, &plen); + /* Only authenticate if the context is valid */ + authenticated = options.password_authentication && + auth_password(authctxt, passwd); + memset(passwd, 0, strlen(passwd)); + xfree(passwd); + + buffer_clear(m); + buffer_put_int(m, authenticated); + + debug3("%s: sending result %d", __func__, authenticated); + mm_request_send(sock, MONITOR_ANS_AUTHPASSWORD, m); + + call_count++; + if (plen == 0 && call_count == 1) + auth_method = "none"; + else + auth_method = "password"; + + /* Causes monitor loop to terminate if authenticated */ + return (authenticated); +} + +#ifdef BSD_AUTH +int +mm_answer_bsdauthquery(int sock, Buffer *m) +{ + char *name, *infotxt; + u_int numprompts; + u_int *echo_on; + char **prompts; + u_int success; + + success = bsdauth_query(authctxt, &name, &infotxt, &numprompts, + &prompts, &echo_on) < 0 ? 0 : 1; + + buffer_clear(m); + buffer_put_int(m, success); + if (success) + buffer_put_cstring(m, prompts[0]); + + debug3("%s: sending challenge success: %u", __func__, success); + mm_request_send(sock, MONITOR_ANS_BSDAUTHQUERY, m); + + if (success) { + xfree(name); + xfree(infotxt); + xfree(prompts); + xfree(echo_on); + } + + return (0); +} + +int +mm_answer_bsdauthrespond(int sock, Buffer *m) +{ + char *response; + int authok; + + if (authctxt->as == 0) + fatal("%s: no bsd auth session", __func__); + + response = buffer_get_string(m, NULL); + authok = options.challenge_response_authentication && + auth_userresponse(authctxt->as, response, 0); + authctxt->as = NULL; + debug3("%s: <%s> = <%d>", __func__, response, authok); + xfree(response); + + buffer_clear(m); + buffer_put_int(m, authok); + + debug3("%s: sending authenticated: %d", __func__, authok); + mm_request_send(sock, MONITOR_ANS_BSDAUTHRESPOND, m); + + auth_method = "bsdauth"; + + return (authok != 0); +} +#endif + +#ifdef SKEY +int +mm_answer_skeyquery(int sock, Buffer *m) +{ + struct skey skey; + char challenge[1024]; + u_int success; + + success = _compat_skeychallenge(&skey, authctxt->user, challenge, + sizeof(challenge)) < 0 ? 0 : 1; + + buffer_clear(m); + buffer_put_int(m, success); + if (success) + buffer_put_cstring(m, challenge); + + debug3("%s: sending challenge success: %u", __func__, success); + mm_request_send(sock, MONITOR_ANS_SKEYQUERY, m); + + return (0); +} + +int +mm_answer_skeyrespond(int sock, Buffer *m) +{ + char *response; + int authok; + + response = buffer_get_string(m, NULL); + + authok = (options.challenge_response_authentication && + authctxt->valid && + skey_haskey(authctxt->pw->pw_name) == 0 && + skey_passcheck(authctxt->pw->pw_name, response) != -1); + + xfree(response); + + buffer_clear(m); + buffer_put_int(m, authok); + + debug3("%s: sending authenticated: %d", __func__, authok); + mm_request_send(sock, MONITOR_ANS_SKEYRESPOND, m); + + auth_method = "skey"; + + return (authok != 0); +} +#endif + +#ifdef USE_PAM +int +mm_answer_pam_start(int sock, Buffer *m) +{ + if (!options.use_pam) + fatal("UsePAM not set, but ended up in %s anyway", __func__); + + start_pam(authctxt); + + monitor_permit(mon_dispatch, MONITOR_REQ_PAM_ACCOUNT, 1); + + return (0); +} + +int +mm_answer_pam_account(int sock, Buffer *m) +{ + u_int ret; + + if (!options.use_pam) + fatal("UsePAM not set, but ended up in %s anyway", __func__); + + ret = do_pam_account(); + + buffer_put_int(m, ret); + + mm_request_send(sock, MONITOR_ANS_PAM_ACCOUNT, m); + + return (ret); +} + +static void *sshpam_ctxt, *sshpam_authok; +extern KbdintDevice sshpam_device; + +int +mm_answer_pam_init_ctx(int sock, Buffer *m) +{ + + debug3("%s", __func__); + authctxt->user = buffer_get_string(m, NULL); + sshpam_ctxt = (sshpam_device.init_ctx)(authctxt); + sshpam_authok = NULL; + buffer_clear(m); + if (sshpam_ctxt != NULL) { + monitor_permit(mon_dispatch, MONITOR_REQ_PAM_FREE_CTX, 1); + buffer_put_int(m, 1); + } else { + buffer_put_int(m, 0); + } + mm_request_send(sock, MONITOR_ANS_PAM_INIT_CTX, m); + return (0); +} + +int +mm_answer_pam_query(int sock, Buffer *m) +{ + char *name, *info, **prompts; + u_int num, *echo_on; + int i, ret; + + debug3("%s", __func__); + sshpam_authok = NULL; + ret = (sshpam_device.query)(sshpam_ctxt, &name, &info, &num, &prompts, &echo_on); + if (ret == 0 && num == 0) + sshpam_authok = sshpam_ctxt; + if (num > 1 || name == NULL || info == NULL) + ret = -1; + buffer_clear(m); + buffer_put_int(m, ret); + buffer_put_cstring(m, name); + xfree(name); + buffer_put_cstring(m, info); + xfree(info); + buffer_put_int(m, num); + for (i = 0; i < num; ++i) { + buffer_put_cstring(m, prompts[i]); + xfree(prompts[i]); + buffer_put_int(m, echo_on[i]); + } + if (prompts != NULL) + xfree(prompts); + if (echo_on != NULL) + xfree(echo_on); + mm_request_send(sock, MONITOR_ANS_PAM_QUERY, m); + return (0); +} + +int +mm_answer_pam_respond(int sock, Buffer *m) +{ + char **resp; + u_int num; + int i, ret; + + debug3("%s", __func__); + sshpam_authok = NULL; + num = buffer_get_int(m); + if (num > 0) { + resp = xmalloc(num * sizeof(char *)); + for (i = 0; i < num; ++i) + resp[i] = buffer_get_string(m, NULL); + ret = (sshpam_device.respond)(sshpam_ctxt, num, resp); + for (i = 0; i < num; ++i) + xfree(resp[i]); + xfree(resp); + } else { + ret = (sshpam_device.respond)(sshpam_ctxt, num, NULL); + } + buffer_clear(m); + buffer_put_int(m, ret); + mm_request_send(sock, MONITOR_ANS_PAM_RESPOND, m); + auth_method = "keyboard-interactive/pam"; + if (ret == 0) + sshpam_authok = sshpam_ctxt; + return (0); +} + +int +mm_answer_pam_free_ctx(int sock, Buffer *m) +{ + + debug3("%s", __func__); + (sshpam_device.free_ctx)(sshpam_ctxt); + buffer_clear(m); + mm_request_send(sock, MONITOR_ANS_PAM_FREE_CTX, m); + return (sshpam_authok == sshpam_ctxt); +} +#endif + +static void +mm_append_debug(Buffer *m) +{ + if (auth_debug_init && buffer_len(&auth_debug)) { + debug3("%s: Appending debug messages for child", __func__); + buffer_append(m, buffer_ptr(&auth_debug), + buffer_len(&auth_debug)); + buffer_clear(&auth_debug); + } +} + +int +mm_answer_keyallowed(int sock, Buffer *m) +{ + Key *key; + char *cuser, *chost; + u_char *blob; + u_int bloblen; + enum mm_keytype type = 0; + int allowed = 0; + + debug3("%s entering", __func__); + + type = buffer_get_int(m); + cuser = buffer_get_string(m, NULL); + chost = buffer_get_string(m, NULL); + blob = buffer_get_string(m, &bloblen); + + key = key_from_blob(blob, bloblen); + + if ((compat20 && type == MM_RSAHOSTKEY) || + (!compat20 && type != MM_RSAHOSTKEY)) + fatal("%s: key type and protocol mismatch", __func__); + + debug3("%s: key_from_blob: %p", __func__, key); + + if (key != NULL && authctxt->valid) { + switch(type) { + case MM_USERKEY: + allowed = options.pubkey_authentication && + user_key_allowed(authctxt->pw, key); + break; + case MM_HOSTKEY: + allowed = options.hostbased_authentication && + hostbased_key_allowed(authctxt->pw, + cuser, chost, key); + break; + case MM_RSAHOSTKEY: + key->type = KEY_RSA1; /* XXX */ + allowed = options.rhosts_rsa_authentication && + auth_rhosts_rsa_key_allowed(authctxt->pw, + cuser, chost, key); + break; + default: + fatal("%s: unknown key type %d", __func__, type); + break; + } + } + if (key != NULL) + key_free(key); + + /* clear temporarily storage (used by verify) */ + monitor_reset_key_state(); + + if (allowed) { + /* Save temporarily for comparison in verify */ + key_blob = blob; + key_bloblen = bloblen; + key_blobtype = type; + hostbased_cuser = cuser; + hostbased_chost = chost; + } + + debug3("%s: key %p is %s", + __func__, key, allowed ? "allowed" : "disallowed"); + + buffer_clear(m); + buffer_put_int(m, allowed); + buffer_put_int(m, forced_command != NULL); + + mm_append_debug(m); + + mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); + + if (type == MM_RSAHOSTKEY) + monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); + + return (0); +} + +static int +monitor_valid_userblob(u_char *data, u_int datalen) +{ + Buffer b; + char *p; + u_int len; + int fail = 0; + + buffer_init(&b); + buffer_append(&b, data, datalen); + + if (datafellows & SSH_OLD_SESSIONID) { + p = buffer_ptr(&b); + len = buffer_len(&b); + if ((session_id2 == NULL) || + (len < session_id2_len) || + (memcmp(p, session_id2, session_id2_len) != 0)) + fail++; + buffer_consume(&b, session_id2_len); + } else { + p = buffer_get_string(&b, &len); + if ((session_id2 == NULL) || + (len != session_id2_len) || + (memcmp(p, session_id2, session_id2_len) != 0)) + fail++; + xfree(p); + } + if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) + fail++; + p = buffer_get_string(&b, NULL); + if (strcmp(authctxt->user, p) != 0) { + logit("wrong user name passed to monitor: expected %s != %.100s", + authctxt->user, p); + fail++; + } + xfree(p); + buffer_skip_string(&b); + if (datafellows & SSH_BUG_PKAUTH) { + if (!buffer_get_char(&b)) + fail++; + } else { + p = buffer_get_string(&b, NULL); + if (strcmp("publickey", p) != 0) + fail++; + xfree(p); + if (!buffer_get_char(&b)) + fail++; + buffer_skip_string(&b); + } + buffer_skip_string(&b); + if (buffer_len(&b) != 0) + fail++; + buffer_free(&b); + return (fail == 0); +} + +static int +monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, + char *chost) +{ + Buffer b; + char *p; + u_int len; + int fail = 0; + + buffer_init(&b); + buffer_append(&b, data, datalen); + + p = buffer_get_string(&b, &len); + if ((session_id2 == NULL) || + (len != session_id2_len) || + (memcmp(p, session_id2, session_id2_len) != 0)) + fail++; + xfree(p); + + if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) + fail++; + p = buffer_get_string(&b, NULL); + if (strcmp(authctxt->user, p) != 0) { + logit("wrong user name passed to monitor: expected %s != %.100s", + authctxt->user, p); + fail++; + } + xfree(p); + buffer_skip_string(&b); /* service */ + p = buffer_get_string(&b, NULL); + if (strcmp(p, "hostbased") != 0) + fail++; + xfree(p); + buffer_skip_string(&b); /* pkalg */ + buffer_skip_string(&b); /* pkblob */ + + /* verify client host, strip trailing dot if necessary */ + p = buffer_get_string(&b, NULL); + if (((len = strlen(p)) > 0) && p[len - 1] == '.') + p[len - 1] = '\0'; + if (strcmp(p, chost) != 0) + fail++; + xfree(p); + + /* verify client user */ + p = buffer_get_string(&b, NULL); + if (strcmp(p, cuser) != 0) + fail++; + xfree(p); + + if (buffer_len(&b) != 0) + fail++; + buffer_free(&b); + return (fail == 0); +} + +int +mm_answer_keyverify(int sock, Buffer *m) +{ + Key *key; + u_char *signature, *data, *blob; + u_int signaturelen, datalen, bloblen; + int verified = 0; + int valid_data = 0; + + blob = buffer_get_string(m, &bloblen); + signature = buffer_get_string(m, &signaturelen); + data = buffer_get_string(m, &datalen); + + if (hostbased_cuser == NULL || hostbased_chost == NULL || + !monitor_allowed_key(blob, bloblen)) + fatal("%s: bad key, not previously allowed", __func__); + + key = key_from_blob(blob, bloblen); + if (key == NULL) + fatal("%s: bad public key blob", __func__); + + switch (key_blobtype) { + case MM_USERKEY: + valid_data = monitor_valid_userblob(data, datalen); + break; + case MM_HOSTKEY: + valid_data = monitor_valid_hostbasedblob(data, datalen, + hostbased_cuser, hostbased_chost); + break; + default: + valid_data = 0; + break; + } + if (!valid_data) + fatal("%s: bad signature data blob", __func__); + + verified = key_verify(key, signature, signaturelen, data, datalen); + debug3("%s: key %p signature %s", + __func__, key, verified ? "verified" : "unverified"); + + key_free(key); + xfree(blob); + xfree(signature); + xfree(data); + + auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased"; + + monitor_reset_key_state(); + + buffer_clear(m); + buffer_put_int(m, verified); + mm_request_send(sock, MONITOR_ANS_KEYVERIFY, m); + + return (verified); +} + +static void +mm_record_login(Session *s, struct passwd *pw) +{ + socklen_t fromlen; + struct sockaddr_storage from; + + /* + * Get IP address of client. If the connection is not a socket, let + * the address be 0.0.0.0. + */ + memset(&from, 0, sizeof(from)); + fromlen = sizeof(from); + if (packet_connection_is_on_socket()) { + if (getpeername(packet_get_connection_in(), + (struct sockaddr *) & from, &fromlen) < 0) { + debug("getpeername: %.100s", strerror(errno)); + cleanup_exit(255); + } + } + /* Record that there was a login on that tty from the remote host. */ + record_login(s->pid, s->tty, pw->pw_name, pw->pw_uid, + get_remote_name_or_ip(utmp_len, options.use_dns), + (struct sockaddr *)&from, fromlen); +} + +static void +mm_session_close(Session *s) +{ + debug3("%s: session %d pid %ld", __func__, s->self, (long)s->pid); + if (s->ttyfd != -1) { + debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); + session_pty_cleanup2(s); + } + s->used = 0; +} + +int +mm_answer_pty(int sock, Buffer *m) +{ + extern struct monitor *pmonitor; + Session *s; + int res, fd0; + + debug3("%s entering", __func__); + + buffer_clear(m); + s = session_new(); + if (s == NULL) + goto error; + s->authctxt = authctxt; + s->pw = authctxt->pw; + s->pid = pmonitor->m_pid; + res = pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)); + if (res == 0) + goto error; + pty_setowner(authctxt->pw, s->tty); + + buffer_put_int(m, 1); + buffer_put_cstring(m, s->tty); + + /* We need to trick ttyslot */ + if (dup2(s->ttyfd, 0) == -1) + fatal("%s: dup2", __func__); + + mm_record_login(s, authctxt->pw); + + /* Now we can close the file descriptor again */ + close(0); + + /* send messages generated by record_login */ + buffer_put_string(m, buffer_ptr(&loginmsg), buffer_len(&loginmsg)); + buffer_clear(&loginmsg); + + mm_request_send(sock, MONITOR_ANS_PTY, m); + + mm_send_fd(sock, s->ptyfd); + mm_send_fd(sock, s->ttyfd); + + /* make sure nothing uses fd 0 */ + if ((fd0 = open(_PATH_DEVNULL, O_RDONLY)) < 0) + fatal("%s: open(/dev/null): %s", __func__, strerror(errno)); + if (fd0 != 0) + error("%s: fd0 %d != 0", __func__, fd0); + + /* slave is not needed */ + close(s->ttyfd); + s->ttyfd = s->ptyfd; + /* no need to dup() because nobody closes ptyfd */ + s->ptymaster = s->ptyfd; + + debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ttyfd); + + return (0); + + error: + if (s != NULL) + mm_session_close(s); + buffer_put_int(m, 0); + mm_request_send(sock, MONITOR_ANS_PTY, m); + return (0); +} + +int +mm_answer_pty_cleanup(int sock, Buffer *m) +{ + Session *s; + char *tty; + + debug3("%s entering", __func__); + + tty = buffer_get_string(m, NULL); + if ((s = session_by_tty(tty)) != NULL) + mm_session_close(s); + buffer_clear(m); + xfree(tty); + return (0); +} + +int +mm_answer_sesskey(int sock, Buffer *m) +{ + BIGNUM *p; + int rsafail; + + /* Turn off permissions */ + monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1); + + if ((p = BN_new()) == NULL) + fatal("%s: BN_new", __func__); + + buffer_get_bignum2(m, p); + + rsafail = ssh1_session_key(p); + + buffer_clear(m); + buffer_put_int(m, rsafail); + buffer_put_bignum2(m, p); + + BN_clear_free(p); + + mm_request_send(sock, MONITOR_ANS_SESSKEY, m); + + /* Turn on permissions for sessid passing */ + monitor_permit(mon_dispatch, MONITOR_REQ_SESSID, 1); + + return (0); +} + +int +mm_answer_sessid(int sock, Buffer *m) +{ + int i; + + debug3("%s entering", __func__); + + if (buffer_len(m) != 16) + fatal("%s: bad ssh1 session id", __func__); + for (i = 0; i < 16; i++) + session_id[i] = buffer_get_char(m); + + /* Turn on permissions for getpwnam */ + monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1); + + return (0); +} + +int +mm_answer_rsa_keyallowed(int sock, Buffer *m) +{ + BIGNUM *client_n; + Key *key = NULL; + u_char *blob = NULL; + u_int blen = 0; + int allowed = 0; + + debug3("%s entering", __func__); + + if (options.rsa_authentication && authctxt->valid) { + if ((client_n = BN_new()) == NULL) + fatal("%s: BN_new", __func__); + buffer_get_bignum2(m, client_n); + allowed = auth_rsa_key_allowed(authctxt->pw, client_n, &key); + BN_clear_free(client_n); + } + buffer_clear(m); + buffer_put_int(m, allowed); + buffer_put_int(m, forced_command != NULL); + + /* clear temporarily storage (used by generate challenge) */ + monitor_reset_key_state(); + + if (allowed && key != NULL) { + key->type = KEY_RSA; /* cheat for key_to_blob */ + if (key_to_blob(key, &blob, &blen) == 0) + fatal("%s: key_to_blob failed", __func__); + buffer_put_string(m, blob, blen); + + /* Save temporarily for comparison in verify */ + key_blob = blob; + key_bloblen = blen; + key_blobtype = MM_RSAUSERKEY; + } + if (key != NULL) + key_free(key); + + mm_append_debug(m); + + mm_request_send(sock, MONITOR_ANS_RSAKEYALLOWED, m); + + monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); + monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 0); + return (0); +} + +int +mm_answer_rsa_challenge(int sock, Buffer *m) +{ + Key *key = NULL; + u_char *blob; + u_int blen; + + debug3("%s entering", __func__); + + if (!authctxt->valid) + fatal("%s: authctxt not valid", __func__); + blob = buffer_get_string(m, &blen); + if (!monitor_allowed_key(blob, blen)) + fatal("%s: bad key, not previously allowed", __func__); + if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) + fatal("%s: key type mismatch", __func__); + if ((key = key_from_blob(blob, blen)) == NULL) + fatal("%s: received bad key", __func__); + + if (ssh1_challenge) + BN_clear_free(ssh1_challenge); + ssh1_challenge = auth_rsa_generate_challenge(key); + + buffer_clear(m); + buffer_put_bignum2(m, ssh1_challenge); + + debug3("%s sending reply", __func__); + mm_request_send(sock, MONITOR_ANS_RSACHALLENGE, m); + + monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 1); + + xfree(blob); + key_free(key); + return (0); +} + +int +mm_answer_rsa_response(int sock, Buffer *m) +{ + Key *key = NULL; + u_char *blob, *response; + u_int blen, len; + int success; + + debug3("%s entering", __func__); + + if (!authctxt->valid) + fatal("%s: authctxt not valid", __func__); + if (ssh1_challenge == NULL) + fatal("%s: no ssh1_challenge", __func__); + + blob = buffer_get_string(m, &blen); + if (!monitor_allowed_key(blob, blen)) + fatal("%s: bad key, not previously allowed", __func__); + if (key_blobtype != MM_RSAUSERKEY && key_blobtype != MM_RSAHOSTKEY) + fatal("%s: key type mismatch: %d", __func__, key_blobtype); + if ((key = key_from_blob(blob, blen)) == NULL) + fatal("%s: received bad key", __func__); + response = buffer_get_string(m, &len); + if (len != 16) + fatal("%s: received bad response to challenge", __func__); + success = auth_rsa_verify_response(key, ssh1_challenge, response); + + xfree(blob); + key_free(key); + xfree(response); + + auth_method = key_blobtype == MM_RSAUSERKEY ? "rsa" : "rhosts-rsa"; + + /* reset state */ + BN_clear_free(ssh1_challenge); + ssh1_challenge = NULL; + monitor_reset_key_state(); + + buffer_clear(m); + buffer_put_int(m, success); + mm_request_send(sock, MONITOR_ANS_RSARESPONSE, m); + + return (success); +} + +int +mm_answer_term(int sock, Buffer *req) +{ + extern struct monitor *pmonitor; + int res, status; + + debug3("%s: tearing down sessions", __func__); + + /* The child is terminating */ + session_destroy_all(&mm_session_close); + + while (waitpid(pmonitor->m_pid, &status, 0) == -1) + if (errno != EINTR) + exit(1); + + res = WIFEXITED(status) ? WEXITSTATUS(status) : 1; + + /* Terminate process */ + exit(res); +} + +void +monitor_apply_keystate(struct monitor *pmonitor) +{ + if (compat20) { + set_newkeys(MODE_IN); + set_newkeys(MODE_OUT); + } else { + packet_set_protocol_flags(child_state.ssh1protoflags); + packet_set_encryption_key(child_state.ssh1key, + child_state.ssh1keylen, child_state.ssh1cipher); + xfree(child_state.ssh1key); + } + + /* for rc4 and other stateful ciphers */ + packet_set_keycontext(MODE_OUT, child_state.keyout); + xfree(child_state.keyout); + packet_set_keycontext(MODE_IN, child_state.keyin); + xfree(child_state.keyin); + + if (!compat20) { + packet_set_iv(MODE_OUT, child_state.ivout); + xfree(child_state.ivout); + packet_set_iv(MODE_IN, child_state.ivin); + xfree(child_state.ivin); + } + + memcpy(&incoming_stream, &child_state.incoming, + sizeof(incoming_stream)); + memcpy(&outgoing_stream, &child_state.outgoing, + sizeof(outgoing_stream)); + + /* Update with new address */ + if (options.compression) + mm_init_compression(pmonitor->m_zlib); + + /* Network I/O buffers */ + /* XXX inefficient for large buffers, need: buffer_init_from_string */ + buffer_clear(&input); + buffer_append(&input, child_state.input, child_state.ilen); + memset(child_state.input, 0, child_state.ilen); + xfree(child_state.input); + + buffer_clear(&output); + buffer_append(&output, child_state.output, child_state.olen); + memset(child_state.output, 0, child_state.olen); + xfree(child_state.output); +} + +static Kex * +mm_get_kex(Buffer *m) +{ + Kex *kex; + void *blob; + u_int bloblen; + + kex = xmalloc(sizeof(*kex)); + memset(kex, 0, sizeof(*kex)); + kex->session_id = buffer_get_string(m, &kex->session_id_len); + if ((session_id2 == NULL) || + (kex->session_id_len != session_id2_len) || + (memcmp(kex->session_id, session_id2, session_id2_len) != 0)) + fatal("mm_get_get: internal error: bad session id"); + kex->we_need = buffer_get_int(m); + kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; + kex->server = 1; + kex->hostkey_type = buffer_get_int(m); + kex->kex_type = buffer_get_int(m); + blob = buffer_get_string(m, &bloblen); + buffer_init(&kex->my); + buffer_append(&kex->my, blob, bloblen); + xfree(blob); + blob = buffer_get_string(m, &bloblen); + buffer_init(&kex->peer); + buffer_append(&kex->peer, blob, bloblen); + xfree(blob); + kex->done = 1; + kex->flags = buffer_get_int(m); + kex->client_version_string = buffer_get_string(m, NULL); + kex->server_version_string = buffer_get_string(m, NULL); + kex->load_host_key=&get_hostkey_by_type; + kex->host_key_index=&get_hostkey_index; + + return (kex); +} + +/* This function requries careful sanity checking */ + +void +mm_get_keystate(struct monitor *pmonitor) +{ + Buffer m; + u_char *blob, *p; + u_int bloblen, plen; + u_int32_t seqnr, packets; + u_int64_t blocks; + + debug3("%s: Waiting for new keys", __func__); + + buffer_init(&m); + mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, &m); + if (!compat20) { + child_state.ssh1protoflags = buffer_get_int(&m); + child_state.ssh1cipher = buffer_get_int(&m); + child_state.ssh1key = buffer_get_string(&m, + &child_state.ssh1keylen); + child_state.ivout = buffer_get_string(&m, + &child_state.ivoutlen); + child_state.ivin = buffer_get_string(&m, &child_state.ivinlen); + goto skip; + } else { + /* Get the Kex for rekeying */ + *pmonitor->m_pkex = mm_get_kex(&m); + } + + blob = buffer_get_string(&m, &bloblen); + current_keys[MODE_OUT] = mm_newkeys_from_blob(blob, bloblen); + xfree(blob); + + debug3("%s: Waiting for second key", __func__); + blob = buffer_get_string(&m, &bloblen); + current_keys[MODE_IN] = mm_newkeys_from_blob(blob, bloblen); + xfree(blob); + + /* Now get sequence numbers for the packets */ + seqnr = buffer_get_int(&m); + blocks = buffer_get_int64(&m); + packets = buffer_get_int(&m); + packet_set_state(MODE_OUT, seqnr, blocks, packets); + seqnr = buffer_get_int(&m); + blocks = buffer_get_int64(&m); + packets = buffer_get_int(&m); + packet_set_state(MODE_IN, seqnr, blocks, packets); + + skip: + /* Get the key context */ + child_state.keyout = buffer_get_string(&m, &child_state.keyoutlen); + child_state.keyin = buffer_get_string(&m, &child_state.keyinlen); + + debug3("%s: Getting compression state", __func__); + /* Get compression state */ + p = buffer_get_string(&m, &plen); + if (plen != sizeof(child_state.outgoing)) + fatal("%s: bad request size", __func__); + memcpy(&child_state.outgoing, p, sizeof(child_state.outgoing)); + xfree(p); + + p = buffer_get_string(&m, &plen); + if (plen != sizeof(child_state.incoming)) + fatal("%s: bad request size", __func__); + memcpy(&child_state.incoming, p, sizeof(child_state.incoming)); + xfree(p); + + /* Network I/O buffers */ + debug3("%s: Getting Network I/O buffers", __func__); + child_state.input = buffer_get_string(&m, &child_state.ilen); + child_state.output = buffer_get_string(&m, &child_state.olen); + + buffer_free(&m); +} + + +/* Allocation functions for zlib */ +void * +mm_zalloc(struct mm_master *mm, u_int ncount, u_int size) +{ + size_t len = (size_t) size * ncount; + void *address; + + if (len == 0 || ncount > SIZE_T_MAX / size) + fatal("%s: mm_zalloc(%u, %u)", __func__, ncount, size); + + address = mm_malloc(mm, len); + + return (address); +} + +void +mm_zfree(struct mm_master *mm, void *address) +{ + mm_free(mm, address); +} + +void +mm_init_compression(struct mm_master *mm) +{ + outgoing_stream.zalloc = (alloc_func)mm_zalloc; + outgoing_stream.zfree = (free_func)mm_zfree; + outgoing_stream.opaque = mm; + + incoming_stream.zalloc = (alloc_func)mm_zalloc; + incoming_stream.zfree = (free_func)mm_zfree; + incoming_stream.opaque = mm; +} + +/* XXX */ + +#define FD_CLOSEONEXEC(x) do { \ + if (fcntl(x, F_SETFD, 1) == -1) \ + fatal("fcntl(%d, F_SETFD)", x); \ +} while (0) + +static void +monitor_socketpair(int *pair) +{ +#ifdef HAVE_SOCKETPAIR + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) + fatal("%s: socketpair", __func__); +#else + fatal("%s: UsePrivilegeSeparation=yes not supported", + __func__); +#endif + FD_CLOSEONEXEC(pair[0]); + FD_CLOSEONEXEC(pair[1]); +} + +#define MM_MEMSIZE 65536 + +struct monitor * +monitor_init(void) +{ + struct monitor *mon; + int pair[2]; + + mon = xmalloc(sizeof(*mon)); + + mon->m_pid = 0; + monitor_socketpair(pair); + + mon->m_recvfd = pair[0]; + mon->m_sendfd = pair[1]; + + /* Used to share zlib space across processes */ + if (options.compression) { + mon->m_zback = mm_create(NULL, MM_MEMSIZE); + mon->m_zlib = mm_create(mon->m_zback, 20 * MM_MEMSIZE); + + /* Compression needs to share state across borders */ + mm_init_compression(mon->m_zlib); + } + + return mon; +} + +void +monitor_reinit(struct monitor *mon) +{ + int pair[2]; + + monitor_socketpair(pair); + + mon->m_recvfd = pair[0]; + mon->m_sendfd = pair[1]; +} + +#ifdef GSSAPI +int +mm_answer_gss_setup_ctx(int sock, Buffer *m) +{ + gss_OID_desc goid; + OM_uint32 major; + u_int len; + + goid.elements = buffer_get_string(m, &len); + goid.length = len; + + major = ssh_gssapi_server_ctx(&gsscontext, &goid); + + xfree(goid.elements); + + buffer_clear(m); + buffer_put_int(m, major); + + mm_request_send(sock,MONITOR_ANS_GSSSETUP, m); + + /* Now we have a context, enable the step */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1); + + return (0); +} + +int +mm_answer_gss_accept_ctx(int sock, Buffer *m) +{ + gss_buffer_desc in; + gss_buffer_desc out = GSS_C_EMPTY_BUFFER; + OM_uint32 major,minor; + OM_uint32 flags = 0; /* GSI needs this */ + u_int len; + + in.value = buffer_get_string(m, &len); + in.length = len; + major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags); + xfree(in.value); + + buffer_clear(m); + buffer_put_int(m, major); + buffer_put_string(m, out.value, out.length); + buffer_put_int(m, flags); + mm_request_send(sock, MONITOR_ANS_GSSSTEP, m); + + gss_release_buffer(&minor, &out); + + if (major==GSS_S_COMPLETE) { + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); + } + return (0); +} + +int +mm_answer_gss_checkmic(int sock, Buffer *m) +{ + gss_buffer_desc gssbuf, mic; + OM_uint32 ret; + u_int len; + + gssbuf.value = buffer_get_string(m, &len); + gssbuf.length = len; + mic.value = buffer_get_string(m, &len); + mic.length = len; + + ret = ssh_gssapi_checkmic(gsscontext, &gssbuf, &mic); + + xfree(gssbuf.value); + xfree(mic.value); + + buffer_clear(m); + buffer_put_int(m, ret); + + mm_request_send(sock, MONITOR_ANS_GSSCHECKMIC, m); + + if (!GSS_ERROR(ret)) + monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); + + return (0); +} + +int +mm_answer_gss_userok(int sock, Buffer *m) +{ + int authenticated; + + authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); + + buffer_clear(m); + buffer_put_int(m, authenticated); + + debug3("%s: sending result %d", __func__, authenticated); + mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); + + auth_method="gssapi-with-mic"; + + /* Monitor loop will terminate if authenticated */ + return (authenticated); +} +#endif /* GSSAPI */ diff --git a/crypto/openssh-3.9p1/monitor.h b/crypto/openssh-3.9p1/monitor.h new file mode 100644 index 0000000000..621a4ad181 --- /dev/null +++ b/crypto/openssh-3.9p1/monitor.h @@ -0,0 +1,91 @@ +/* $OpenBSD: monitor.h,v 1.13 2003/11/17 11:06:07 markus Exp $ */ + +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MONITOR_H_ +#define _MONITOR_H_ + +enum monitor_reqtype { + MONITOR_REQ_MODULI, MONITOR_ANS_MODULI, + MONITOR_REQ_FREE, MONITOR_REQ_AUTHSERV, + MONITOR_REQ_SIGN, MONITOR_ANS_SIGN, + MONITOR_REQ_PWNAM, MONITOR_ANS_PWNAM, + MONITOR_REQ_AUTH2_READ_BANNER, MONITOR_ANS_AUTH2_READ_BANNER, + MONITOR_REQ_AUTHPASSWORD, MONITOR_ANS_AUTHPASSWORD, + MONITOR_REQ_BSDAUTHQUERY, MONITOR_ANS_BSDAUTHQUERY, + MONITOR_REQ_BSDAUTHRESPOND, MONITOR_ANS_BSDAUTHRESPOND, + MONITOR_REQ_SKEYQUERY, MONITOR_ANS_SKEYQUERY, + MONITOR_REQ_SKEYRESPOND, MONITOR_ANS_SKEYRESPOND, + MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED, + MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY, + MONITOR_REQ_KEYEXPORT, + MONITOR_REQ_PTY, MONITOR_ANS_PTY, + MONITOR_REQ_PTYCLEANUP, + MONITOR_REQ_SESSKEY, MONITOR_ANS_SESSKEY, + MONITOR_REQ_SESSID, + MONITOR_REQ_RSAKEYALLOWED, MONITOR_ANS_RSAKEYALLOWED, + MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE, + MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE, + MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP, + MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP, + MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK, + MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC, + MONITOR_REQ_PAM_START, + MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT, + MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX, + MONITOR_REQ_PAM_QUERY, MONITOR_ANS_PAM_QUERY, + MONITOR_REQ_PAM_RESPOND, MONITOR_ANS_PAM_RESPOND, + MONITOR_REQ_PAM_FREE_CTX, MONITOR_ANS_PAM_FREE_CTX, + MONITOR_REQ_TERM +}; + +struct mm_master; +struct monitor { + int m_recvfd; + int m_sendfd; + struct mm_master *m_zback; + struct mm_master *m_zlib; + struct Kex **m_pkex; + pid_t m_pid; +}; + +struct monitor *monitor_init(void); +void monitor_reinit(struct monitor *); +void monitor_sync(struct monitor *); + +struct Authctxt; +void monitor_child_preauth(struct Authctxt *, struct monitor *); +void monitor_child_postauth(struct monitor *); + +struct mon_table; +int monitor_read(struct monitor*, struct mon_table *, struct mon_table **); + +/* Prototypes for request sending and receiving */ +void mm_request_send(int, enum monitor_reqtype, Buffer *); +void mm_request_receive(int, Buffer *); +void mm_request_receive_expect(int, enum monitor_reqtype, Buffer *); + +#endif /* _MONITOR_H_ */ diff --git a/crypto/openssh-3.9p1/monitor_fdpass.c b/crypto/openssh-3.9p1/monitor_fdpass.c new file mode 100644 index 0000000000..dd1a139841 --- /dev/null +++ b/crypto/openssh-3.9p1/monitor_fdpass.c @@ -0,0 +1,130 @@ +/* + * Copyright 2001 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: monitor_fdpass.c,v 1.6 2004/08/13 02:51:48 djm Exp $"); + +#include + +#include "log.h" +#include "monitor_fdpass.h" + +void +mm_send_fd(int sock, int fd) +{ +#if defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR)) + struct msghdr msg; + struct iovec vec; + char ch = '\0'; + ssize_t n; +#ifndef HAVE_ACCRIGHTS_IN_MSGHDR + char tmp[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg; +#endif + + memset(&msg, 0, sizeof(msg)); +#ifdef HAVE_ACCRIGHTS_IN_MSGHDR + msg.msg_accrights = (caddr_t)&fd; + msg.msg_accrightslen = sizeof(fd); +#else + msg.msg_control = (caddr_t)tmp; + msg.msg_controllen = CMSG_LEN(sizeof(int)); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = fd; +#endif + + vec.iov_base = &ch; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + + if ((n = sendmsg(sock, &msg, 0)) == -1) + fatal("%s: sendmsg(%d): %s", __func__, fd, + strerror(errno)); + if (n != 1) + fatal("%s: sendmsg: expected sent 1 got %ld", + __func__, (long)n); +#else + fatal("%s: UsePrivilegeSeparation=yes not supported", + __func__); +#endif +} + +int +mm_receive_fd(int sock) +{ +#if defined(HAVE_RECVMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR)) + struct msghdr msg; + struct iovec vec; + ssize_t n; + char ch; + int fd; +#ifndef HAVE_ACCRIGHTS_IN_MSGHDR + char tmp[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsg; +#endif + + memset(&msg, 0, sizeof(msg)); + vec.iov_base = &ch; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; +#ifdef HAVE_ACCRIGHTS_IN_MSGHDR + msg.msg_accrights = (caddr_t)&fd; + msg.msg_accrightslen = sizeof(fd); +#else + msg.msg_control = tmp; + msg.msg_controllen = sizeof(tmp); +#endif + + if ((n = recvmsg(sock, &msg, 0)) == -1) + fatal("%s: recvmsg: %s", __func__, strerror(errno)); + if (n != 1) + fatal("%s: recvmsg: expected received 1 got %ld", + __func__, (long)n); + +#ifdef HAVE_ACCRIGHTS_IN_MSGHDR + if (msg.msg_accrightslen != sizeof(fd)) + fatal("%s: no fd", __func__); +#else + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg == NULL) + fatal("%s: no message header", __func__); +#ifndef BROKEN_CMSG_TYPE + if (cmsg->cmsg_type != SCM_RIGHTS) + fatal("%s: expected type %d got %d", __func__, + SCM_RIGHTS, cmsg->cmsg_type); +#endif + fd = (*(int *)CMSG_DATA(cmsg)); +#endif + return fd; +#else + fatal("%s: UsePrivilegeSeparation=yes not supported", + __func__); +#endif +} diff --git a/crypto/openssh-3.9p1/monitor_fdpass.h b/crypto/openssh-3.9p1/monitor_fdpass.h new file mode 100644 index 0000000000..31d080e21e --- /dev/null +++ b/crypto/openssh-3.9p1/monitor_fdpass.h @@ -0,0 +1,34 @@ +/* $OpenBSD: monitor_fdpass.h,v 1.2 2002/03/26 03:24:01 stevesk Exp $ */ + +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MM_FDPASS_H_ +#define _MM_FDPASS_H_ + +void mm_send_fd(int, int); +int mm_receive_fd(int); + +#endif /* _MM_FDPASS_H_ */ diff --git a/crypto/openssh-3.9p1/monitor_mm.c b/crypto/openssh-3.9p1/monitor_mm.c new file mode 100644 index 0000000000..ff523a5b1e --- /dev/null +++ b/crypto/openssh-3.9p1/monitor_mm.c @@ -0,0 +1,345 @@ +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: monitor_mm.c,v 1.9 2004/05/11 19:01:43 deraadt Exp $"); + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#include "ssh.h" +#include "xmalloc.h" +#include "log.h" +#include "monitor_mm.h" + +static int +mm_compare(struct mm_share *a, struct mm_share *b) +{ + long diff = (char *)a->address - (char *)b->address; + + if (diff == 0) + return (0); + else if (diff < 0) + return (-1); + else + return (1); +} + +RB_GENERATE(mmtree, mm_share, next, mm_compare) + +static struct mm_share * +mm_make_entry(struct mm_master *mm, struct mmtree *head, + void *address, size_t size) +{ + struct mm_share *tmp, *tmp2; + + if (mm->mmalloc == NULL) + tmp = xmalloc(sizeof(struct mm_share)); + else + tmp = mm_xmalloc(mm->mmalloc, sizeof(struct mm_share)); + tmp->address = address; + tmp->size = size; + + tmp2 = RB_INSERT(mmtree, head, tmp); + if (tmp2 != NULL) + fatal("mm_make_entry(%p): double address %p->%p(%lu)", + mm, tmp2, address, (u_long)size); + + return (tmp); +} + +/* Creates a shared memory area of a certain size */ + +struct mm_master * +mm_create(struct mm_master *mmalloc, size_t size) +{ + void *address; + struct mm_master *mm; + + if (mmalloc == NULL) + mm = xmalloc(sizeof(struct mm_master)); + else + mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); + + /* + * If the memory map has a mm_master it can be completely + * shared including authentication between the child + * and the client. + */ + mm->mmalloc = mmalloc; + + address = xmmap(size); + if (address == MAP_FAILED) + fatal("mmap(%lu): %s", (u_long)size, strerror(errno)); + + mm->address = address; + mm->size = size; + + RB_INIT(&mm->rb_free); + RB_INIT(&mm->rb_allocated); + + mm_make_entry(mm, &mm->rb_free, address, size); + + return (mm); +} + +/* Frees either the allocated or the free list */ + +static void +mm_freelist(struct mm_master *mmalloc, struct mmtree *head) +{ + struct mm_share *mms, *next; + + for (mms = RB_ROOT(head); mms; mms = next) { + next = RB_NEXT(mmtree, head, mms); + RB_REMOVE(mmtree, head, mms); + if (mmalloc == NULL) + xfree(mms); + else + mm_free(mmalloc, mms); + } +} + +/* Destroys a memory mapped area */ + +void +mm_destroy(struct mm_master *mm) +{ + mm_freelist(mm->mmalloc, &mm->rb_free); + mm_freelist(mm->mmalloc, &mm->rb_allocated); + +#ifdef HAVE_MMAP + if (munmap(mm->address, mm->size) == -1) + fatal("munmap(%p, %lu): %s", mm->address, (u_long)mm->size, + strerror(errno)); +#else + fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported", + __func__); +#endif + if (mm->mmalloc == NULL) + xfree(mm); + else + mm_free(mm->mmalloc, mm); +} + +void * +mm_xmalloc(struct mm_master *mm, size_t size) +{ + void *address; + + address = mm_malloc(mm, size); + if (address == NULL) + fatal("%s: mm_malloc(%lu)", __func__, (u_long)size); + return (address); +} + + +/* Allocates data from a memory mapped area */ + +void * +mm_malloc(struct mm_master *mm, size_t size) +{ + struct mm_share *mms, *tmp; + + if (size == 0) + fatal("mm_malloc: try to allocate 0 space"); + if (size > SIZE_T_MAX - MM_MINSIZE + 1) + fatal("mm_malloc: size too big"); + + size = ((size + (MM_MINSIZE - 1)) / MM_MINSIZE) * MM_MINSIZE; + + RB_FOREACH(mms, mmtree, &mm->rb_free) { + if (mms->size >= size) + break; + } + + if (mms == NULL) + return (NULL); + + /* Debug */ + memset(mms->address, 0xd0, size); + + tmp = mm_make_entry(mm, &mm->rb_allocated, mms->address, size); + + /* Does not change order in RB tree */ + mms->size -= size; + mms->address = (u_char *)mms->address + size; + + if (mms->size == 0) { + RB_REMOVE(mmtree, &mm->rb_free, mms); + if (mm->mmalloc == NULL) + xfree(mms); + else + mm_free(mm->mmalloc, mms); + } + + return (tmp->address); +} + +/* Frees memory in a memory mapped area */ + +void +mm_free(struct mm_master *mm, void *address) +{ + struct mm_share *mms, *prev, tmp; + + tmp.address = address; + mms = RB_FIND(mmtree, &mm->rb_allocated, &tmp); + if (mms == NULL) + fatal("mm_free(%p): can not find %p", mm, address); + + /* Debug */ + memset(mms->address, 0xd0, mms->size); + + /* Remove from allocated list and insert in free list */ + RB_REMOVE(mmtree, &mm->rb_allocated, mms); + if (RB_INSERT(mmtree, &mm->rb_free, mms) != NULL) + fatal("mm_free(%p): double address %p", mm, address); + + /* Find previous entry */ + prev = mms; + if (RB_LEFT(prev, next)) { + prev = RB_LEFT(prev, next); + while (RB_RIGHT(prev, next)) + prev = RB_RIGHT(prev, next); + } else { + if (RB_PARENT(prev, next) && + (prev == RB_RIGHT(RB_PARENT(prev, next), next))) + prev = RB_PARENT(prev, next); + else { + while (RB_PARENT(prev, next) && + (prev == RB_LEFT(RB_PARENT(prev, next), next))) + prev = RB_PARENT(prev, next); + prev = RB_PARENT(prev, next); + } + } + + /* Check if range does not overlap */ + if (prev != NULL && MM_ADDRESS_END(prev) > address) + fatal("mm_free: memory corruption: %p(%lu) > %p", + prev->address, (u_long)prev->size, address); + + /* See if we can merge backwards */ + if (prev != NULL && MM_ADDRESS_END(prev) == address) { + prev->size += mms->size; + RB_REMOVE(mmtree, &mm->rb_free, mms); + if (mm->mmalloc == NULL) + xfree(mms); + else + mm_free(mm->mmalloc, mms); + } else + prev = mms; + + if (prev == NULL) + return; + + /* Check if we can merge forwards */ + mms = RB_NEXT(mmtree, &mm->rb_free, prev); + if (mms == NULL) + return; + + if (MM_ADDRESS_END(prev) > mms->address) + fatal("mm_free: memory corruption: %p < %p(%lu)", + mms->address, prev->address, (u_long)prev->size); + if (MM_ADDRESS_END(prev) != mms->address) + return; + + prev->size += mms->size; + RB_REMOVE(mmtree, &mm->rb_free, mms); + + if (mm->mmalloc == NULL) + xfree(mms); + else + mm_free(mm->mmalloc, mms); +} + +static void +mm_sync_list(struct mmtree *oldtree, struct mmtree *newtree, + struct mm_master *mm, struct mm_master *mmold) +{ + struct mm_master *mmalloc = mm->mmalloc; + struct mm_share *mms, *new; + + /* Sync free list */ + RB_FOREACH(mms, mmtree, oldtree) { + /* Check the values */ + mm_memvalid(mmold, mms, sizeof(struct mm_share)); + mm_memvalid(mm, mms->address, mms->size); + + new = mm_xmalloc(mmalloc, sizeof(struct mm_share)); + memcpy(new, mms, sizeof(struct mm_share)); + RB_INSERT(mmtree, newtree, new); + } +} + +void +mm_share_sync(struct mm_master **pmm, struct mm_master **pmmalloc) +{ + struct mm_master *mm; + struct mm_master *mmalloc; + struct mm_master *mmold; + struct mmtree rb_free, rb_allocated; + + debug3("%s: Share sync", __func__); + + mm = *pmm; + mmold = mm->mmalloc; + mm_memvalid(mmold, mm, sizeof(*mm)); + + mmalloc = mm_create(NULL, mm->size); + mm = mm_xmalloc(mmalloc, sizeof(struct mm_master)); + memcpy(mm, *pmm, sizeof(struct mm_master)); + mm->mmalloc = mmalloc; + + rb_free = mm->rb_free; + rb_allocated = mm->rb_allocated; + + RB_INIT(&mm->rb_free); + RB_INIT(&mm->rb_allocated); + + mm_sync_list(&rb_free, &mm->rb_free, mm, mmold); + mm_sync_list(&rb_allocated, &mm->rb_allocated, mm, mmold); + + mm_destroy(mmold); + + *pmm = mm; + *pmmalloc = mmalloc; + + debug3("%s: Share sync end", __func__); +} + +void +mm_memvalid(struct mm_master *mm, void *address, size_t size) +{ + void *end = (u_char *)address + size; + + if (address < mm->address) + fatal("mm_memvalid: address too small: %p", address); + if (end < address) + fatal("mm_memvalid: end < address: %p < %p", end, address); + if (end > (void *)((u_char *)mm->address + mm->size)) + fatal("mm_memvalid: address too large: %p", address); +} diff --git a/crypto/openssh-3.9p1/monitor_mm.h b/crypto/openssh-3.9p1/monitor_mm.h new file mode 100644 index 0000000000..a1323b9a8d --- /dev/null +++ b/crypto/openssh-3.9p1/monitor_mm.h @@ -0,0 +1,66 @@ +/* $OpenBSD: monitor_mm.h,v 1.2 2002/03/26 03:24:01 stevesk Exp $ */ + +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MM_H_ +#define _MM_H_ +#include "openbsd-compat/sys-tree.h" + +struct mm_share { + RB_ENTRY(mm_share) next; + void *address; + size_t size; +}; + +struct mm_master { + RB_HEAD(mmtree, mm_share) rb_free; + struct mmtree rb_allocated; + void *address; + size_t size; + + struct mm_master *mmalloc; /* Used to completely share */ + + int write; /* used to writing to other party */ + int read; /* used for reading from other party */ +}; + +RB_PROTOTYPE(mmtree, mm_share, next, mm_compare) + +#define MM_MINSIZE 128 + +#define MM_ADDRESS_END(x) (void *)((u_char *)(x)->address + (x)->size) + +struct mm_master *mm_create(struct mm_master *, size_t); +void mm_destroy(struct mm_master *); + +void mm_share_sync(struct mm_master **, struct mm_master **); + +void *mm_malloc(struct mm_master *, size_t); +void *mm_xmalloc(struct mm_master *, size_t); +void mm_free(struct mm_master *, void *); + +void mm_memvalid(struct mm_master *, void *, size_t); +#endif /* _MM_H_ */ diff --git a/crypto/openssh-3.9p1/monitor_wrap.c b/crypto/openssh-3.9p1/monitor_wrap.c new file mode 100644 index 0000000000..0d7a0e3bd9 --- /dev/null +++ b/crypto/openssh-3.9p1/monitor_wrap.c @@ -0,0 +1,1185 @@ +/* + * Copyright 2002 Niels Provos + * Copyright 2002 Markus Friedl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: monitor_wrap.c,v 1.39 2004/07/17 05:31:41 dtucker Exp $"); + +#include +#include + +#include "ssh.h" +#include "dh.h" +#include "kex.h" +#include "auth.h" +#include "auth-options.h" +#include "buffer.h" +#include "bufaux.h" +#include "packet.h" +#include "mac.h" +#include "log.h" +#ifdef TARGET_OS_MAC /* XXX Broken krb5 headers on Mac */ +#undef TARGET_OS_MAC +#include "zlib.h" +#define TARGET_OS_MAC 1 +#else +#include "zlib.h" +#endif +#include "monitor.h" +#include "monitor_wrap.h" +#include "xmalloc.h" +#include "atomicio.h" +#include "monitor_fdpass.h" +#include "getput.h" +#include "servconf.h" + +#include "auth.h" +#include "channels.h" +#include "session.h" + +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + +/* Imports */ +extern int compat20; +extern Newkeys *newkeys[]; +extern z_stream incoming_stream; +extern z_stream outgoing_stream; +extern struct monitor *pmonitor; +extern Buffer input, output; +extern Buffer loginmsg; +extern ServerOptions options; + +int +mm_is_monitor(void) +{ + /* + * m_pid is only set in the privileged part, and + * points to the unprivileged child. + */ + return (pmonitor && pmonitor->m_pid > 0); +} + +void +mm_request_send(int sock, enum monitor_reqtype type, Buffer *m) +{ + u_int mlen = buffer_len(m); + u_char buf[5]; + + debug3("%s entering: type %d", __func__, type); + + PUT_32BIT(buf, mlen + 1); + buf[4] = (u_char) type; /* 1st byte of payload is mesg-type */ + if (atomicio(vwrite, sock, buf, sizeof(buf)) != sizeof(buf)) + fatal("%s: write", __func__); + if (atomicio(vwrite, sock, buffer_ptr(m), mlen) != mlen) + fatal("%s: write", __func__); +} + +void +mm_request_receive(int sock, Buffer *m) +{ + u_char buf[4]; + u_int msg_len; + ssize_t res; + + debug3("%s entering", __func__); + + res = atomicio(read, sock, buf, sizeof(buf)); + if (res != sizeof(buf)) { + if (res == 0) + cleanup_exit(255); + fatal("%s: read: %ld", __func__, (long)res); + } + msg_len = GET_32BIT(buf); + if (msg_len > 256 * 1024) + fatal("%s: read: bad msg_len %d", __func__, msg_len); + buffer_clear(m); + buffer_append_space(m, msg_len); + res = atomicio(read, sock, buffer_ptr(m), msg_len); + if (res != msg_len) + fatal("%s: read: %ld != msg_len", __func__, (long)res); +} + +void +mm_request_receive_expect(int sock, enum monitor_reqtype type, Buffer *m) +{ + u_char rtype; + + debug3("%s entering: type %d", __func__, type); + + mm_request_receive(sock, m); + rtype = buffer_get_char(m); + if (rtype != type) + fatal("%s: read: rtype %d != type %d", __func__, + rtype, type); +} + +DH * +mm_choose_dh(int min, int nbits, int max) +{ + BIGNUM *p, *g; + int success = 0; + Buffer m; + + buffer_init(&m); + buffer_put_int(&m, min); + buffer_put_int(&m, nbits); + buffer_put_int(&m, max); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_MODULI, &m); + + debug3("%s: waiting for MONITOR_ANS_MODULI", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_MODULI, &m); + + success = buffer_get_char(&m); + if (success == 0) + fatal("%s: MONITOR_ANS_MODULI failed", __func__); + + if ((p = BN_new()) == NULL) + fatal("%s: BN_new failed", __func__); + if ((g = BN_new()) == NULL) + fatal("%s: BN_new failed", __func__); + buffer_get_bignum2(&m, p); + buffer_get_bignum2(&m, g); + + debug3("%s: remaining %d", __func__, buffer_len(&m)); + buffer_free(&m); + + return (dh_new_group(g, p)); +} + +int +mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen) +{ + Kex *kex = *pmonitor->m_pkex; + Buffer m; + + debug3("%s entering", __func__); + + buffer_init(&m); + buffer_put_int(&m, kex->host_key_index(key)); + buffer_put_string(&m, data, datalen); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SIGN, &m); + + debug3("%s: waiting for MONITOR_ANS_SIGN", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SIGN, &m); + *sigp = buffer_get_string(&m, lenp); + buffer_free(&m); + + return (0); +} + +struct passwd * +mm_getpwnamallow(const char *username) +{ + Buffer m; + struct passwd *pw; + u_int pwlen; + + debug3("%s entering", __func__); + + buffer_init(&m); + buffer_put_cstring(&m, username); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PWNAM, &m); + + debug3("%s: waiting for MONITOR_ANS_PWNAM", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PWNAM, &m); + + if (buffer_get_char(&m) == 0) { + buffer_free(&m); + return (NULL); + } + pw = buffer_get_string(&m, &pwlen); + if (pwlen != sizeof(struct passwd)) + fatal("%s: struct passwd size mismatch", __func__); + pw->pw_name = buffer_get_string(&m, NULL); + pw->pw_passwd = buffer_get_string(&m, NULL); + pw->pw_gecos = buffer_get_string(&m, NULL); +#ifdef HAVE_PW_CLASS_IN_PASSWD + pw->pw_class = buffer_get_string(&m, NULL); +#endif + pw->pw_dir = buffer_get_string(&m, NULL); + pw->pw_shell = buffer_get_string(&m, NULL); + buffer_free(&m); + + return (pw); +} + +char * +mm_auth2_read_banner(void) +{ + Buffer m; + char *banner; + + debug3("%s entering", __func__); + + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTH2_READ_BANNER, &m); + buffer_clear(&m); + + mm_request_receive_expect(pmonitor->m_recvfd, + MONITOR_ANS_AUTH2_READ_BANNER, &m); + banner = buffer_get_string(&m, NULL); + buffer_free(&m); + + /* treat empty banner as missing banner */ + if (strlen(banner) == 0) { + xfree(banner); + banner = NULL; + } + return (banner); +} + +/* Inform the privileged process about service and style */ + +void +mm_inform_authserv(char *service, char *style) +{ + Buffer m; + + debug3("%s entering", __func__); + + buffer_init(&m); + buffer_put_cstring(&m, service); + buffer_put_cstring(&m, style ? style : ""); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHSERV, &m); + + buffer_free(&m); +} + +/* Do the password authentication */ +int +mm_auth_password(Authctxt *authctxt, char *password) +{ + Buffer m; + int authenticated = 0; + + debug3("%s entering", __func__); + + buffer_init(&m); + buffer_put_cstring(&m, password); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUTHPASSWORD, &m); + + debug3("%s: waiting for MONITOR_ANS_AUTHPASSWORD", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUTHPASSWORD, &m); + + authenticated = buffer_get_int(&m); + + buffer_free(&m); + + debug3("%s: user %sauthenticated", + __func__, authenticated ? "" : "not "); + return (authenticated); +} + +int +mm_user_key_allowed(struct passwd *pw, Key *key) +{ + return (mm_key_allowed(MM_USERKEY, NULL, NULL, key)); +} + +int +mm_hostbased_key_allowed(struct passwd *pw, char *user, char *host, + Key *key) +{ + return (mm_key_allowed(MM_HOSTKEY, user, host, key)); +} + +int +mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user, + char *host, Key *key) +{ + int ret; + + key->type = KEY_RSA; /* XXX hack for key_to_blob */ + ret = mm_key_allowed(MM_RSAHOSTKEY, user, host, key); + key->type = KEY_RSA1; + return (ret); +} + +static void +mm_send_debug(Buffer *m) +{ + char *msg; + + while (buffer_len(m)) { + msg = buffer_get_string(m, NULL); + debug3("%s: Sending debug: %s", __func__, msg); + packet_send_debug("%s", msg); + xfree(msg); + } +} + +int +mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) +{ + Buffer m; + u_char *blob; + u_int len; + int allowed = 0, have_forced = 0; + + debug3("%s entering", __func__); + + /* Convert the key to a blob and the pass it over */ + if (!key_to_blob(key, &blob, &len)) + return (0); + + buffer_init(&m); + buffer_put_int(&m, type); + buffer_put_cstring(&m, user ? user : ""); + buffer_put_cstring(&m, host ? host : ""); + buffer_put_string(&m, blob, len); + xfree(blob); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYALLOWED, &m); + + debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYALLOWED, &m); + + allowed = buffer_get_int(&m); + + /* fake forced command */ + auth_clear_options(); + have_forced = buffer_get_int(&m); + forced_command = have_forced ? xstrdup("true") : NULL; + + /* Send potential debug messages */ + mm_send_debug(&m); + + buffer_free(&m); + + return (allowed); +} + +/* + * This key verify needs to send the key type along, because the + * privileged parent makes the decision if the key is allowed + * for authentication. + */ + +int +mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) +{ + Buffer m; + u_char *blob; + u_int len; + int verified = 0; + + debug3("%s entering", __func__); + + /* Convert the key to a blob and the pass it over */ + if (!key_to_blob(key, &blob, &len)) + return (0); + + buffer_init(&m); + buffer_put_string(&m, blob, len); + buffer_put_string(&m, sig, siglen); + buffer_put_string(&m, data, datalen); + xfree(blob); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m); + + debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYVERIFY, &m); + + verified = buffer_get_int(&m); + + buffer_free(&m); + + return (verified); +} + +/* Export key state after authentication */ +Newkeys * +mm_newkeys_from_blob(u_char *blob, int blen) +{ + Buffer b; + u_int len; + Newkeys *newkey = NULL; + Enc *enc; + Mac *mac; + Comp *comp; + + debug3("%s: %p(%d)", __func__, blob, blen); +#ifdef DEBUG_PK + dump_base64(stderr, blob, blen); +#endif + buffer_init(&b); + buffer_append(&b, blob, blen); + + newkey = xmalloc(sizeof(*newkey)); + enc = &newkey->enc; + mac = &newkey->mac; + comp = &newkey->comp; + + /* Enc structure */ + enc->name = buffer_get_string(&b, NULL); + buffer_get(&b, &enc->cipher, sizeof(enc->cipher)); + enc->enabled = buffer_get_int(&b); + enc->block_size = buffer_get_int(&b); + enc->key = buffer_get_string(&b, &enc->key_len); + enc->iv = buffer_get_string(&b, &len); + if (len != enc->block_size) + fatal("%s: bad ivlen: expected %u != %u", __func__, + enc->block_size, len); + + if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher) + fatal("%s: bad cipher name %s or pointer %p", __func__, + enc->name, enc->cipher); + + /* Mac structure */ + mac->name = buffer_get_string(&b, NULL); + if (mac->name == NULL || mac_init(mac, mac->name) == -1) + fatal("%s: can not init mac %s", __func__, mac->name); + mac->enabled = buffer_get_int(&b); + mac->key = buffer_get_string(&b, &len); + if (len > mac->key_len) + fatal("%s: bad mac key length: %u > %d", __func__, len, + mac->key_len); + mac->key_len = len; + + /* Comp structure */ + comp->type = buffer_get_int(&b); + comp->enabled = buffer_get_int(&b); + comp->name = buffer_get_string(&b, NULL); + + len = buffer_len(&b); + if (len != 0) + error("newkeys_from_blob: remaining bytes in blob %u", len); + buffer_free(&b); + return (newkey); +} + +int +mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp) +{ + Buffer b; + int len; + Enc *enc; + Mac *mac; + Comp *comp; + Newkeys *newkey = newkeys[mode]; + + debug3("%s: converting %p", __func__, newkey); + + if (newkey == NULL) { + error("%s: newkey == NULL", __func__); + return 0; + } + enc = &newkey->enc; + mac = &newkey->mac; + comp = &newkey->comp; + + buffer_init(&b); + /* Enc structure */ + buffer_put_cstring(&b, enc->name); + /* The cipher struct is constant and shared, you export pointer */ + buffer_append(&b, &enc->cipher, sizeof(enc->cipher)); + buffer_put_int(&b, enc->enabled); + buffer_put_int(&b, enc->block_size); + buffer_put_string(&b, enc->key, enc->key_len); + packet_get_keyiv(mode, enc->iv, enc->block_size); + buffer_put_string(&b, enc->iv, enc->block_size); + + /* Mac structure */ + buffer_put_cstring(&b, mac->name); + buffer_put_int(&b, mac->enabled); + buffer_put_string(&b, mac->key, mac->key_len); + + /* Comp structure */ + buffer_put_int(&b, comp->type); + buffer_put_int(&b, comp->enabled); + buffer_put_cstring(&b, comp->name); + + len = buffer_len(&b); + if (lenp != NULL) + *lenp = len; + if (blobp != NULL) { + *blobp = xmalloc(len); + memcpy(*blobp, buffer_ptr(&b), len); + } + memset(buffer_ptr(&b), 0, len); + buffer_free(&b); + return len; +} + +static void +mm_send_kex(Buffer *m, Kex *kex) +{ + buffer_put_string(m, kex->session_id, kex->session_id_len); + buffer_put_int(m, kex->we_need); + buffer_put_int(m, kex->hostkey_type); + buffer_put_int(m, kex->kex_type); + buffer_put_string(m, buffer_ptr(&kex->my), buffer_len(&kex->my)); + buffer_put_string(m, buffer_ptr(&kex->peer), buffer_len(&kex->peer)); + buffer_put_int(m, kex->flags); + buffer_put_cstring(m, kex->client_version_string); + buffer_put_cstring(m, kex->server_version_string); +} + +void +mm_send_keystate(struct monitor *monitor) +{ + Buffer m; + u_char *blob, *p; + u_int bloblen, plen; + u_int32_t seqnr, packets; + u_int64_t blocks; + + buffer_init(&m); + + if (!compat20) { + u_char iv[24]; + u_char *key; + u_int ivlen, keylen; + + buffer_put_int(&m, packet_get_protocol_flags()); + + buffer_put_int(&m, packet_get_ssh1_cipher()); + + debug3("%s: Sending ssh1 KEY+IV", __func__); + keylen = packet_get_encryption_key(NULL); + key = xmalloc(keylen+1); /* add 1 if keylen == 0 */ + keylen = packet_get_encryption_key(key); + buffer_put_string(&m, key, keylen); + memset(key, 0, keylen); + xfree(key); + + ivlen = packet_get_keyiv_len(MODE_OUT); + packet_get_keyiv(MODE_OUT, iv, ivlen); + buffer_put_string(&m, iv, ivlen); + ivlen = packet_get_keyiv_len(MODE_OUT); + packet_get_keyiv(MODE_IN, iv, ivlen); + buffer_put_string(&m, iv, ivlen); + goto skip; + } else { + /* Kex for rekeying */ + mm_send_kex(&m, *monitor->m_pkex); + } + + debug3("%s: Sending new keys: %p %p", + __func__, newkeys[MODE_OUT], newkeys[MODE_IN]); + + /* Keys from Kex */ + if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen)) + fatal("%s: conversion of newkeys failed", __func__); + + buffer_put_string(&m, blob, bloblen); + xfree(blob); + + if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen)) + fatal("%s: conversion of newkeys failed", __func__); + + buffer_put_string(&m, blob, bloblen); + xfree(blob); + + packet_get_state(MODE_OUT, &seqnr, &blocks, &packets); + buffer_put_int(&m, seqnr); + buffer_put_int64(&m, blocks); + buffer_put_int(&m, packets); + packet_get_state(MODE_IN, &seqnr, &blocks, &packets); + buffer_put_int(&m, seqnr); + buffer_put_int64(&m, blocks); + buffer_put_int(&m, packets); + + debug3("%s: New keys have been sent", __func__); + skip: + /* More key context */ + plen = packet_get_keycontext(MODE_OUT, NULL); + p = xmalloc(plen+1); + packet_get_keycontext(MODE_OUT, p); + buffer_put_string(&m, p, plen); + xfree(p); + + plen = packet_get_keycontext(MODE_IN, NULL); + p = xmalloc(plen+1); + packet_get_keycontext(MODE_IN, p); + buffer_put_string(&m, p, plen); + xfree(p); + + /* Compression state */ + debug3("%s: Sending compression state", __func__); + buffer_put_string(&m, &outgoing_stream, sizeof(outgoing_stream)); + buffer_put_string(&m, &incoming_stream, sizeof(incoming_stream)); + + /* Network I/O buffers */ + buffer_put_string(&m, buffer_ptr(&input), buffer_len(&input)); + buffer_put_string(&m, buffer_ptr(&output), buffer_len(&output)); + + mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, &m); + debug3("%s: Finished sending state", __func__); + + buffer_free(&m); +} + +int +mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen) +{ + Buffer m; + char *p, *msg; + int success = 0; + + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, &m); + + debug3("%s: waiting for MONITOR_ANS_PTY", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PTY, &m); + + success = buffer_get_int(&m); + if (success == 0) { + debug3("%s: pty alloc failed", __func__); + buffer_free(&m); + return (0); + } + p = buffer_get_string(&m, NULL); + msg = buffer_get_string(&m, NULL); + buffer_free(&m); + + strlcpy(namebuf, p, namebuflen); /* Possible truncation */ + xfree(p); + + buffer_append(&loginmsg, msg, strlen(msg)); + xfree(msg); + + *ptyfd = mm_receive_fd(pmonitor->m_recvfd); + *ttyfd = mm_receive_fd(pmonitor->m_recvfd); + + /* Success */ + return (1); +} + +void +mm_session_pty_cleanup2(Session *s) +{ + Buffer m; + + if (s->ttyfd == -1) + return; + buffer_init(&m); + buffer_put_cstring(&m, s->tty); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTYCLEANUP, &m); + buffer_free(&m); + + /* closed dup'ed master */ + if (close(s->ptymaster) < 0) + error("close(s->ptymaster): %s", strerror(errno)); + + /* unlink pty from session */ + s->ttyfd = -1; +} + +#ifdef USE_PAM +void +mm_start_pam(Authctxt *authctxt) +{ + Buffer m; + + debug3("%s entering", __func__); + if (!options.use_pam) + fatal("UsePAM=no, but ended up in %s anyway", __func__); + + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_START, &m); + + buffer_free(&m); +} + +u_int +mm_do_pam_account(void) +{ + Buffer m; + u_int ret; + + debug3("%s entering", __func__); + if (!options.use_pam) + fatal("UsePAM=no, but ended up in %s anyway", __func__); + + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_ACCOUNT, &m); + + mm_request_receive_expect(pmonitor->m_recvfd, + MONITOR_ANS_PAM_ACCOUNT, &m); + ret = buffer_get_int(&m); + + buffer_free(&m); + + debug3("%s returning %d", __func__, ret); + + return (ret); +} + +void * +mm_sshpam_init_ctx(Authctxt *authctxt) +{ + Buffer m; + int success; + + debug3("%s", __func__); + buffer_init(&m); + buffer_put_cstring(&m, authctxt->user); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_INIT_CTX, &m); + debug3("%s: waiting for MONITOR_ANS_PAM_INIT_CTX", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_INIT_CTX, &m); + success = buffer_get_int(&m); + if (success == 0) { + debug3("%s: pam_init_ctx failed", __func__); + buffer_free(&m); + return (NULL); + } + buffer_free(&m); + return (authctxt); +} + +int +mm_sshpam_query(void *ctx, char **name, char **info, + u_int *num, char ***prompts, u_int **echo_on) +{ + Buffer m; + int i, ret; + + debug3("%s", __func__); + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_QUERY, &m); + debug3("%s: waiting for MONITOR_ANS_PAM_QUERY", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_QUERY, &m); + ret = buffer_get_int(&m); + debug3("%s: pam_query returned %d", __func__, ret); + *name = buffer_get_string(&m, NULL); + *info = buffer_get_string(&m, NULL); + *num = buffer_get_int(&m); + *prompts = xmalloc((*num + 1) * sizeof(char *)); + *echo_on = xmalloc((*num + 1) * sizeof(u_int)); + for (i = 0; i < *num; ++i) { + (*prompts)[i] = buffer_get_string(&m, NULL); + (*echo_on)[i] = buffer_get_int(&m); + } + buffer_free(&m); + return (ret); +} + +int +mm_sshpam_respond(void *ctx, u_int num, char **resp) +{ + Buffer m; + int i, ret; + + debug3("%s", __func__); + buffer_init(&m); + buffer_put_int(&m, num); + for (i = 0; i < num; ++i) + buffer_put_cstring(&m, resp[i]); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_RESPOND, &m); + debug3("%s: waiting for MONITOR_ANS_PAM_RESPOND", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_RESPOND, &m); + ret = buffer_get_int(&m); + debug3("%s: pam_respond returned %d", __func__, ret); + buffer_free(&m); + return (ret); +} + +void +mm_sshpam_free_ctx(void *ctxtp) +{ + Buffer m; + + debug3("%s", __func__); + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_FREE_CTX, &m); + debug3("%s: waiting for MONITOR_ANS_PAM_FREE_CTX", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_FREE_CTX, &m); + buffer_free(&m); +} +#endif /* USE_PAM */ + +/* Request process termination */ + +void +mm_terminate(void) +{ + Buffer m; + + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_TERM, &m); + buffer_free(&m); +} + +int +mm_ssh1_session_key(BIGNUM *num) +{ + int rsafail; + Buffer m; + + buffer_init(&m); + buffer_put_bignum2(&m, num); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SESSKEY, &m); + + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SESSKEY, &m); + + rsafail = buffer_get_int(&m); + buffer_get_bignum2(&m, num); + + buffer_free(&m); + + return (rsafail); +} + +static void +mm_chall_setup(char **name, char **infotxt, u_int *numprompts, + char ***prompts, u_int **echo_on) +{ + *name = xstrdup(""); + *infotxt = xstrdup(""); + *numprompts = 1; + *prompts = xmalloc(*numprompts * sizeof(char *)); + *echo_on = xmalloc(*numprompts * sizeof(u_int)); + (*echo_on)[0] = 0; +} + +int +mm_bsdauth_query(void *ctx, char **name, char **infotxt, + u_int *numprompts, char ***prompts, u_int **echo_on) +{ + Buffer m; + u_int success; + char *challenge; + + debug3("%s: entering", __func__); + + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHQUERY, &m); + + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_BSDAUTHQUERY, + &m); + success = buffer_get_int(&m); + if (success == 0) { + debug3("%s: no challenge", __func__); + buffer_free(&m); + return (-1); + } + + /* Get the challenge, and format the response */ + challenge = buffer_get_string(&m, NULL); + buffer_free(&m); + + mm_chall_setup(name, infotxt, numprompts, prompts, echo_on); + (*prompts)[0] = challenge; + + debug3("%s: received challenge: %s", __func__, challenge); + + return (0); +} + +int +mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses) +{ + Buffer m; + int authok; + + debug3("%s: entering", __func__); + if (numresponses != 1) + return (-1); + + buffer_init(&m); + buffer_put_cstring(&m, responses[0]); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHRESPOND, &m); + + mm_request_receive_expect(pmonitor->m_recvfd, + MONITOR_ANS_BSDAUTHRESPOND, &m); + + authok = buffer_get_int(&m); + buffer_free(&m); + + return ((authok == 0) ? -1 : 0); +} + +#ifdef SKEY +int +mm_skey_query(void *ctx, char **name, char **infotxt, + u_int *numprompts, char ***prompts, u_int **echo_on) +{ + Buffer m; + int len; + u_int success; + char *p, *challenge; + + debug3("%s: entering", __func__); + + buffer_init(&m); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYQUERY, &m); + + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SKEYQUERY, + &m); + success = buffer_get_int(&m); + if (success == 0) { + debug3("%s: no challenge", __func__); + buffer_free(&m); + return (-1); + } + + /* Get the challenge, and format the response */ + challenge = buffer_get_string(&m, NULL); + buffer_free(&m); + + debug3("%s: received challenge: %s", __func__, challenge); + + mm_chall_setup(name, infotxt, numprompts, prompts, echo_on); + + len = strlen(challenge) + strlen(SKEY_PROMPT) + 1; + p = xmalloc(len); + strlcpy(p, challenge, len); + strlcat(p, SKEY_PROMPT, len); + (*prompts)[0] = p; + xfree(challenge); + + return (0); +} + +int +mm_skey_respond(void *ctx, u_int numresponses, char **responses) +{ + Buffer m; + int authok; + + debug3("%s: entering", __func__); + if (numresponses != 1) + return (-1); + + buffer_init(&m); + buffer_put_cstring(&m, responses[0]); + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYRESPOND, &m); + + mm_request_receive_expect(pmonitor->m_recvfd, + MONITOR_ANS_SKEYRESPOND, &m); + + authok = buffer_get_int(&m); + buffer_free(&m); + + return ((authok == 0) ? -1 : 0); +} +#endif /* SKEY */ + +void +mm_ssh1_session_id(u_char session_id[16]) +{ + Buffer m; + int i; + + debug3("%s entering", __func__); + + buffer_init(&m); + for (i = 0; i < 16; i++) + buffer_put_char(&m, session_id[i]); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SESSID, &m); + buffer_free(&m); +} + +int +mm_auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey) +{ + Buffer m; + Key *key; + u_char *blob; + u_int blen; + int allowed = 0, have_forced = 0; + + debug3("%s entering", __func__); + + buffer_init(&m); + buffer_put_bignum2(&m, client_n); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_RSAKEYALLOWED, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_RSAKEYALLOWED, &m); + + allowed = buffer_get_int(&m); + + /* fake forced command */ + auth_clear_options(); + have_forced = buffer_get_int(&m); + forced_command = have_forced ? xstrdup("true") : NULL; + + if (allowed && rkey != NULL) { + blob = buffer_get_string(&m, &blen); + if ((key = key_from_blob(blob, blen)) == NULL) + fatal("%s: key_from_blob failed", __func__); + *rkey = key; + xfree(blob); + } + mm_send_debug(&m); + buffer_free(&m); + + return (allowed); +} + +BIGNUM * +mm_auth_rsa_generate_challenge(Key *key) +{ + Buffer m; + BIGNUM *challenge; + u_char *blob; + u_int blen; + + debug3("%s entering", __func__); + + if ((challenge = BN_new()) == NULL) + fatal("%s: BN_new failed", __func__); + + key->type = KEY_RSA; /* XXX cheat for key_to_blob */ + if (key_to_blob(key, &blob, &blen) == 0) + fatal("%s: key_to_blob failed", __func__); + key->type = KEY_RSA1; + + buffer_init(&m); + buffer_put_string(&m, blob, blen); + xfree(blob); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_RSACHALLENGE, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_RSACHALLENGE, &m); + + buffer_get_bignum2(&m, challenge); + buffer_free(&m); + + return (challenge); +} + +int +mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16]) +{ + Buffer m; + u_char *blob; + u_int blen; + int success = 0; + + debug3("%s entering", __func__); + + key->type = KEY_RSA; /* XXX cheat for key_to_blob */ + if (key_to_blob(key, &blob, &blen) == 0) + fatal("%s: key_to_blob failed", __func__); + key->type = KEY_RSA1; + + buffer_init(&m); + buffer_put_string(&m, blob, blen); + buffer_put_string(&m, response, 16); + xfree(blob); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_RSARESPONSE, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_RSARESPONSE, &m); + + success = buffer_get_int(&m); + buffer_free(&m); + + return (success); +} + +#ifdef GSSAPI +OM_uint32 +mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid) +{ + Buffer m; + OM_uint32 major; + + /* Client doesn't get to see the context */ + *ctx = NULL; + + buffer_init(&m); + buffer_put_string(&m, goid->elements, goid->length); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, &m); + + major = buffer_get_int(&m); + + buffer_free(&m); + return (major); +} + +OM_uint32 +mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in, + gss_buffer_desc *out, OM_uint32 *flags) +{ + Buffer m; + OM_uint32 major; + u_int len; + + buffer_init(&m); + buffer_put_string(&m, in->value, in->length); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, &m); + + major = buffer_get_int(&m); + out->value = buffer_get_string(&m, &len); + out->length = len; + if (flags) + *flags = buffer_get_int(&m); + + buffer_free(&m); + + return (major); +} + +OM_uint32 +mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) +{ + Buffer m; + OM_uint32 major; + + buffer_init(&m); + buffer_put_string(&m, gssbuf->value, gssbuf->length); + buffer_put_string(&m, gssmic->value, gssmic->length); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSCHECKMIC, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSCHECKMIC, + &m); + + major = buffer_get_int(&m); + buffer_free(&m); + return(major); +} + +int +mm_ssh_gssapi_userok(char *user) +{ + Buffer m; + int authenticated = 0; + + buffer_init(&m); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK, + &m); + + authenticated = buffer_get_int(&m); + + buffer_free(&m); + debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not "); + return (authenticated); +} +#endif /* GSSAPI */ diff --git a/crypto/openssh-3.9p1/monitor_wrap.h b/crypto/openssh-3.9p1/monitor_wrap.h new file mode 100644 index 0000000000..e5cf5718c4 --- /dev/null +++ b/crypto/openssh-3.9p1/monitor_wrap.h @@ -0,0 +1,108 @@ +/* $OpenBSD: monitor_wrap.h,v 1.14 2004/06/21 17:36:31 avsm Exp $ */ + +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MM_WRAP_H_ +#define _MM_WRAP_H_ +#include "key.h" +#include "buffer.h" + +extern int use_privsep; +#define PRIVSEP(x) (use_privsep ? mm_##x : x) + +enum mm_keytype {MM_NOKEY, MM_HOSTKEY, MM_USERKEY, MM_RSAHOSTKEY, MM_RSAUSERKEY}; + +struct monitor; +struct mm_master; +struct passwd; +struct Authctxt; + +int mm_is_monitor(void); +DH *mm_choose_dh(int, int, int); +int mm_key_sign(Key *, u_char **, u_int *, u_char *, u_int); +void mm_inform_authserv(char *, char *); +struct passwd *mm_getpwnamallow(const char *); +char *mm_auth2_read_banner(void); +int mm_auth_password(struct Authctxt *, char *); +int mm_key_allowed(enum mm_keytype, char *, char *, Key *); +int mm_user_key_allowed(struct passwd *, Key *); +int mm_hostbased_key_allowed(struct passwd *, char *, char *, Key *); +int mm_auth_rhosts_rsa_key_allowed(struct passwd *, char *, char *, Key *); +int mm_key_verify(Key *, u_char *, u_int, u_char *, u_int); +int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); +int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); +BIGNUM *mm_auth_rsa_generate_challenge(Key *); + +#ifdef GSSAPI +#include "ssh-gss.h" +OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); +OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, + gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); +int mm_ssh_gssapi_userok(char *user); +OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); +#endif + +#ifdef USE_PAM +void mm_start_pam(struct Authctxt *); +u_int mm_do_pam_account(void); +void *mm_sshpam_init_ctx(struct Authctxt *); +int mm_sshpam_query(void *, char **, char **, u_int *, char ***, u_int **); +int mm_sshpam_respond(void *, u_int, char **); +void mm_sshpam_free_ctx(void *); +#endif + +struct Session; +void mm_terminate(void); +int mm_pty_allocate(int *, int *, char *, int); +void mm_session_pty_cleanup2(struct Session *); + +/* SSHv1 interfaces */ +void mm_ssh1_session_id(u_char *); +int mm_ssh1_session_key(BIGNUM *); + +/* Key export functions */ +struct Newkeys *mm_newkeys_from_blob(u_char *, int); +int mm_newkeys_to_blob(int, u_char **, u_int *); + +void monitor_apply_keystate(struct monitor *); +void mm_get_keystate(struct monitor *); +void mm_send_keystate(struct monitor*); + +/* bsdauth */ +int mm_bsdauth_query(void *, char **, char **, u_int *, char ***, u_int **); +int mm_bsdauth_respond(void *, u_int, char **); + +/* skey */ +int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **); +int mm_skey_respond(void *, u_int, char **); + +/* zlib allocation hooks */ + +void *mm_zalloc(struct mm_master *, u_int, u_int); +void mm_zfree(struct mm_master *, void *); +void mm_init_compression(struct mm_master *); + +#endif /* _MM_H_ */ diff --git a/crypto/openssh-3.9p1/mpaux.c b/crypto/openssh-3.9p1/mpaux.c new file mode 100644 index 0000000000..0c486275ff --- /dev/null +++ b/crypto/openssh-3.9p1/mpaux.c @@ -0,0 +1,46 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * This file contains various auxiliary functions related to multiple + * precision integers. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: mpaux.c,v 1.16 2001/02/08 19:30:52 itojun Exp $"); + +#include +#include "getput.h" +#include "xmalloc.h" + +#include + +#include "mpaux.h" + +void +compute_session_id(u_char session_id[16], + u_char cookie[8], + BIGNUM* host_key_n, + BIGNUM* session_key_n) +{ + u_int host_key_bytes = BN_num_bytes(host_key_n); + u_int session_key_bytes = BN_num_bytes(session_key_n); + u_int bytes = host_key_bytes + session_key_bytes; + u_char *buf = xmalloc(bytes); + MD5_CTX md; + + BN_bn2bin(host_key_n, buf); + BN_bn2bin(session_key_n, buf + host_key_bytes); + MD5_Init(&md); + MD5_Update(&md, buf, bytes); + MD5_Update(&md, cookie, 8); + MD5_Final(session_id, &md); + memset(buf, 0, bytes); + xfree(buf); +} diff --git a/crypto/openssh-3.9p1/mpaux.h b/crypto/openssh-3.9p1/mpaux.h new file mode 100644 index 0000000000..2a312f5cb2 --- /dev/null +++ b/crypto/openssh-3.9p1/mpaux.h @@ -0,0 +1,22 @@ +/* $OpenBSD: mpaux.h,v 1.12 2002/03/04 17:27:39 stevesk Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * This file contains various auxiliary functions related to multiple + * precision integers. + * + * 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". + */ + +#ifndef MPAUX_H +#define MPAUX_H + +void compute_session_id(u_char[16], u_char[8], BIGNUM *, BIGNUM *); + +#endif /* MPAUX_H */ diff --git a/crypto/openssh-3.9p1/msg.c b/crypto/openssh-3.9p1/msg.c new file mode 100644 index 0000000000..30bc3f1076 --- /dev/null +++ b/crypto/openssh-3.9p1/msg.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2002 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: msg.c,v 1.7 2003/11/17 09:45:39 djm Exp $"); + +#include "buffer.h" +#include "getput.h" +#include "log.h" +#include "atomicio.h" +#include "msg.h" + +int +ssh_msg_send(int fd, u_char type, Buffer *m) +{ + u_char buf[5]; + u_int mlen = buffer_len(m); + + debug3("ssh_msg_send: type %u", (unsigned int)type & 0xff); + + PUT_32BIT(buf, mlen + 1); + buf[4] = type; /* 1st byte of payload is mesg-type */ + if (atomicio(vwrite, fd, buf, sizeof(buf)) != sizeof(buf)) { + error("ssh_msg_send: write"); + return (-1); + } + if (atomicio(vwrite, fd, buffer_ptr(m), mlen) != mlen) { + error("ssh_msg_send: write"); + return (-1); + } + return (0); +} + +int +ssh_msg_recv(int fd, Buffer *m) +{ + u_char buf[4]; + ssize_t res; + u_int msg_len; + + debug3("ssh_msg_recv entering"); + + res = atomicio(read, fd, buf, sizeof(buf)); + if (res != sizeof(buf)) { + if (res != 0) + error("ssh_msg_recv: read: header %ld", (long)res); + return (-1); + } + msg_len = GET_32BIT(buf); + if (msg_len > 256 * 1024) { + error("ssh_msg_recv: read: bad msg_len %u", msg_len); + return (-1); + } + buffer_clear(m); + buffer_append_space(m, msg_len); + res = atomicio(read, fd, buffer_ptr(m), msg_len); + if (res != msg_len) { + error("ssh_msg_recv: read: %ld != msg_len", (long)res); + return (-1); + } + return (0); +} diff --git a/crypto/openssh-3.9p1/msg.h b/crypto/openssh-3.9p1/msg.h new file mode 100644 index 0000000000..0d3ea06582 --- /dev/null +++ b/crypto/openssh-3.9p1/msg.h @@ -0,0 +1,31 @@ +/* $OpenBSD: msg.h,v 1.3 2003/11/17 09:45:39 djm Exp $ */ +/* + * Copyright (c) 2002 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SSH_MSG_H +#define SSH_MSG_H + +int ssh_msg_send(int, u_char, Buffer *); +int ssh_msg_recv(int, Buffer *); + +#endif diff --git a/crypto/openssh-3.9p1/myproposal.h b/crypto/openssh-3.9p1/myproposal.h new file mode 100644 index 0000000000..228ed68828 --- /dev/null +++ b/crypto/openssh-3.9p1/myproposal.h @@ -0,0 +1,53 @@ +/* $OpenBSD: myproposal.h,v 1.16 2004/06/13 12:53:24 djm Exp $ */ + +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define KEX_DEFAULT_KEX "diffie-hellman-group-exchange-sha1," \ + "diffie-hellman-group14-sha1," \ + "diffie-hellman-group1-sha1" +#define KEX_DEFAULT_PK_ALG "ssh-rsa,ssh-dss" +#define KEX_DEFAULT_ENCRYPT \ + "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour," \ + "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se," \ + "aes128-ctr,aes192-ctr,aes256-ctr" +#define KEX_DEFAULT_MAC \ + "hmac-md5,hmac-sha1,hmac-ripemd160," \ + "hmac-ripemd160@openssh.com," \ + "hmac-sha1-96,hmac-md5-96" +#define KEX_DEFAULT_COMP "none,zlib" +#define KEX_DEFAULT_LANG "" + + +static char *myproposal[PROPOSAL_MAX] = { + KEX_DEFAULT_KEX, + KEX_DEFAULT_PK_ALG, + KEX_DEFAULT_ENCRYPT, + KEX_DEFAULT_ENCRYPT, + KEX_DEFAULT_MAC, + KEX_DEFAULT_MAC, + KEX_DEFAULT_COMP, + KEX_DEFAULT_COMP, + KEX_DEFAULT_LANG, + KEX_DEFAULT_LANG +}; diff --git a/crypto/openssh-3.9p1/nchan.c b/crypto/openssh-3.9p1/nchan.c new file mode 100644 index 0000000000..aee3f37b0a --- /dev/null +++ b/crypto/openssh-3.9p1/nchan.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: nchan.c,v 1.51 2004/07/11 17:48:47 deraadt Exp $"); + +#include "ssh1.h" +#include "ssh2.h" +#include "buffer.h" +#include "packet.h" +#include "channels.h" +#include "compat.h" +#include "log.h" + +/* + * SSH Protocol 1.5 aka New Channel Protocol + * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored. + * Written by Markus Friedl in October 1999 + * + * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the + * tear down of channels: + * + * 1.3: strict request-ack-protocol: + * CLOSE -> + * <- CLOSE_CONFIRM + * + * 1.5: uses variations of: + * IEOF -> + * <- OCLOSE + * <- IEOF + * OCLOSE -> + * i.e. both sides have to close the channel + * + * 2.0: the EOF messages are optional + * + * See the debugging output from 'ssh -v' and 'sshd -d' of + * ssh-1.2.27 as an example. + * + */ + +/* functions manipulating channel states */ +/* + * EVENTS update channel input/output states execute ACTIONS + */ +/* + * ACTIONS: should never update the channel states + */ +static void chan_send_ieof1(Channel *); +static void chan_send_oclose1(Channel *); +static void chan_send_close2(Channel *); +static void chan_send_eof2(Channel *); + +/* helper */ +static void chan_shutdown_write(Channel *); +static void chan_shutdown_read(Channel *); + +static char *ostates[] = { "open", "drain", "wait_ieof", "closed" }; +static char *istates[] = { "open", "drain", "wait_oclose", "closed" }; + +static void +chan_set_istate(Channel *c, u_int next) +{ + if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED) + fatal("chan_set_istate: bad state %d -> %d", c->istate, next); + debug2("channel %d: input %s -> %s", c->self, istates[c->istate], + istates[next]); + c->istate = next; +} +static void +chan_set_ostate(Channel *c, u_int next) +{ + if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED) + fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next); + debug2("channel %d: output %s -> %s", c->self, ostates[c->ostate], + ostates[next]); + c->ostate = next; +} + +/* + * SSH1 specific implementation of event functions + */ + +static void +chan_rcvd_oclose1(Channel *c) +{ + debug2("channel %d: rcvd oclose", c->self); + switch (c->istate) { + case CHAN_INPUT_WAIT_OCLOSE: + chan_set_istate(c, CHAN_INPUT_CLOSED); + break; + case CHAN_INPUT_OPEN: + chan_shutdown_read(c); + chan_send_ieof1(c); + chan_set_istate(c, CHAN_INPUT_CLOSED); + break; + case CHAN_INPUT_WAIT_DRAIN: + /* both local read_failed and remote write_failed */ + chan_send_ieof1(c); + chan_set_istate(c, CHAN_INPUT_CLOSED); + break; + default: + error("channel %d: protocol error: rcvd_oclose for istate %d", + c->self, c->istate); + return; + } +} +void +chan_read_failed(Channel *c) +{ + debug2("channel %d: read failed", c->self); + switch (c->istate) { + case CHAN_INPUT_OPEN: + chan_shutdown_read(c); + chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN); + break; + default: + error("channel %d: chan_read_failed for istate %d", + c->self, c->istate); + break; + } +} +void +chan_ibuf_empty(Channel *c) +{ + debug2("channel %d: ibuf empty", c->self); + if (buffer_len(&c->input)) { + error("channel %d: chan_ibuf_empty for non empty buffer", + c->self); + return; + } + switch (c->istate) { + case CHAN_INPUT_WAIT_DRAIN: + if (compat20) { + if (!(c->flags & CHAN_CLOSE_SENT)) + chan_send_eof2(c); + chan_set_istate(c, CHAN_INPUT_CLOSED); + } else { + chan_send_ieof1(c); + chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE); + } + break; + default: + error("channel %d: chan_ibuf_empty for istate %d", + c->self, c->istate); + break; + } +} +static void +chan_rcvd_ieof1(Channel *c) +{ + debug2("channel %d: rcvd ieof", c->self); + switch (c->ostate) { + case CHAN_OUTPUT_OPEN: + chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); + break; + case CHAN_OUTPUT_WAIT_IEOF: + chan_set_ostate(c, CHAN_OUTPUT_CLOSED); + break; + default: + error("channel %d: protocol error: rcvd_ieof for ostate %d", + c->self, c->ostate); + break; + } +} +static void +chan_write_failed1(Channel *c) +{ + debug2("channel %d: write failed", c->self); + switch (c->ostate) { + case CHAN_OUTPUT_OPEN: + chan_shutdown_write(c); + chan_send_oclose1(c); + chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF); + break; + case CHAN_OUTPUT_WAIT_DRAIN: + chan_shutdown_write(c); + chan_send_oclose1(c); + chan_set_ostate(c, CHAN_OUTPUT_CLOSED); + break; + default: + error("channel %d: chan_write_failed for ostate %d", + c->self, c->ostate); + break; + } +} +void +chan_obuf_empty(Channel *c) +{ + debug2("channel %d: obuf empty", c->self); + if (buffer_len(&c->output)) { + error("channel %d: chan_obuf_empty for non empty buffer", + c->self); + return; + } + switch (c->ostate) { + case CHAN_OUTPUT_WAIT_DRAIN: + chan_shutdown_write(c); + if (!compat20) + chan_send_oclose1(c); + chan_set_ostate(c, CHAN_OUTPUT_CLOSED); + break; + default: + error("channel %d: internal error: obuf_empty for ostate %d", + c->self, c->ostate); + break; + } +} +static void +chan_send_ieof1(Channel *c) +{ + debug2("channel %d: send ieof", c->self); + switch (c->istate) { + case CHAN_INPUT_OPEN: + case CHAN_INPUT_WAIT_DRAIN: + packet_start(SSH_MSG_CHANNEL_INPUT_EOF); + packet_put_int(c->remote_id); + packet_send(); + break; + default: + error("channel %d: cannot send ieof for istate %d", + c->self, c->istate); + break; + } +} +static void +chan_send_oclose1(Channel *c) +{ + debug2("channel %d: send oclose", c->self); + switch (c->ostate) { + case CHAN_OUTPUT_OPEN: + case CHAN_OUTPUT_WAIT_DRAIN: + buffer_clear(&c->output); + packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE); + packet_put_int(c->remote_id); + packet_send(); + break; + default: + error("channel %d: cannot send oclose for ostate %d", + c->self, c->ostate); + break; + } +} + +/* + * the same for SSH2 + */ +static void +chan_rcvd_close2(Channel *c) +{ + debug2("channel %d: rcvd close", c->self); + if (c->flags & CHAN_CLOSE_RCVD) + error("channel %d: protocol error: close rcvd twice", c->self); + c->flags |= CHAN_CLOSE_RCVD; + if (c->type == SSH_CHANNEL_LARVAL) { + /* tear down larval channels immediately */ + chan_set_ostate(c, CHAN_OUTPUT_CLOSED); + chan_set_istate(c, CHAN_INPUT_CLOSED); + return; + } + switch (c->ostate) { + case CHAN_OUTPUT_OPEN: + /* + * wait until a data from the channel is consumed if a CLOSE + * is received + */ + chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); + break; + } + switch (c->istate) { + case CHAN_INPUT_OPEN: + chan_shutdown_read(c); + chan_set_istate(c, CHAN_INPUT_CLOSED); + break; + case CHAN_INPUT_WAIT_DRAIN: + chan_send_eof2(c); + chan_set_istate(c, CHAN_INPUT_CLOSED); + break; + } +} +static void +chan_rcvd_eof2(Channel *c) +{ + debug2("channel %d: rcvd eof", c->self); + c->flags |= CHAN_EOF_RCVD; + if (c->ostate == CHAN_OUTPUT_OPEN) + chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); +} +static void +chan_write_failed2(Channel *c) +{ + debug2("channel %d: write failed", c->self); + switch (c->ostate) { + case CHAN_OUTPUT_OPEN: + case CHAN_OUTPUT_WAIT_DRAIN: + chan_shutdown_write(c); + chan_set_ostate(c, CHAN_OUTPUT_CLOSED); + break; + default: + error("channel %d: chan_write_failed for ostate %d", + c->self, c->ostate); + break; + } +} +static void +chan_send_eof2(Channel *c) +{ + debug2("channel %d: send eof", c->self); + switch (c->istate) { + case CHAN_INPUT_WAIT_DRAIN: + packet_start(SSH2_MSG_CHANNEL_EOF); + packet_put_int(c->remote_id); + packet_send(); + c->flags |= CHAN_EOF_SENT; + break; + default: + error("channel %d: cannot send eof for istate %d", + c->self, c->istate); + break; + } +} +static void +chan_send_close2(Channel *c) +{ + debug2("channel %d: send close", c->self); + if (c->ostate != CHAN_OUTPUT_CLOSED || + c->istate != CHAN_INPUT_CLOSED) { + error("channel %d: cannot send close for istate/ostate %d/%d", + c->self, c->istate, c->ostate); + } else if (c->flags & CHAN_CLOSE_SENT) { + error("channel %d: already sent close", c->self); + } else { + packet_start(SSH2_MSG_CHANNEL_CLOSE); + packet_put_int(c->remote_id); + packet_send(); + c->flags |= CHAN_CLOSE_SENT; + } +} + +/* shared */ + +void +chan_rcvd_ieof(Channel *c) +{ + if (compat20) + chan_rcvd_eof2(c); + else + chan_rcvd_ieof1(c); + if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && + buffer_len(&c->output) == 0 && + !CHANNEL_EFD_OUTPUT_ACTIVE(c)) + chan_obuf_empty(c); +} +void +chan_rcvd_oclose(Channel *c) +{ + if (compat20) + chan_rcvd_close2(c); + else + chan_rcvd_oclose1(c); +} +void +chan_write_failed(Channel *c) +{ + if (compat20) + chan_write_failed2(c); + else + chan_write_failed1(c); +} + +void +chan_mark_dead(Channel *c) +{ + c->type = SSH_CHANNEL_ZOMBIE; +} + +int +chan_is_dead(Channel *c, int do_send) +{ + if (c->type == SSH_CHANNEL_ZOMBIE) { + debug2("channel %d: zombie", c->self); + return 1; + } + if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) + return 0; + if (!compat20) { + debug2("channel %d: is dead", c->self); + return 1; + } + if ((datafellows & SSH_BUG_EXTEOF) && + c->extended_usage == CHAN_EXTENDED_WRITE && + c->efd != -1 && + buffer_len(&c->extended) > 0) { + debug2("channel %d: active efd: %d len %d", + c->self, c->efd, buffer_len(&c->extended)); + return 0; + } + if (!(c->flags & CHAN_CLOSE_SENT)) { + if (do_send) { + chan_send_close2(c); + } else { + /* channel would be dead if we sent a close */ + if (c->flags & CHAN_CLOSE_RCVD) { + debug2("channel %d: almost dead", + c->self); + return 1; + } + } + } + if ((c->flags & CHAN_CLOSE_SENT) && + (c->flags & CHAN_CLOSE_RCVD)) { + debug2("channel %d: is dead", c->self); + return 1; + } + return 0; +} + +/* helper */ +static void +chan_shutdown_write(Channel *c) +{ + buffer_clear(&c->output); + if (compat20 && c->type == SSH_CHANNEL_LARVAL) + return; + /* shutdown failure is allowed if write failed already */ + debug2("channel %d: close_write", c->self); + if (c->sock != -1) { + if (shutdown(c->sock, SHUT_WR) < 0) + debug2("channel %d: chan_shutdown_write: " + "shutdown() failed for fd%d: %.100s", + c->self, c->sock, strerror(errno)); + } else { + if (channel_close_fd(&c->wfd) < 0) + logit("channel %d: chan_shutdown_write: " + "close() failed for fd%d: %.100s", + c->self, c->wfd, strerror(errno)); + } +} +static void +chan_shutdown_read(Channel *c) +{ + if (compat20 && c->type == SSH_CHANNEL_LARVAL) + return; + debug2("channel %d: close_read", c->self); + if (c->sock != -1) { + /* + * shutdown(sock, SHUT_READ) may return ENOTCONN if the + * write side has been closed already. (bug on Linux) + * HP-UX may return ENOTCONN also. + */ + if (shutdown(c->sock, SHUT_RD) < 0 + && errno != ENOTCONN) + error("channel %d: chan_shutdown_read: " + "shutdown() failed for fd%d [i%d o%d]: %.100s", + c->self, c->sock, c->istate, c->ostate, + strerror(errno)); + } else { + if (channel_close_fd(&c->rfd) < 0) + logit("channel %d: chan_shutdown_read: " + "close() failed for fd%d: %.100s", + c->self, c->rfd, strerror(errno)); + } +} diff --git a/crypto/openssh-3.9p1/openbsd-compat/base64.c b/crypto/openssh-3.9p1/openbsd-compat/base64.c new file mode 100644 index 0000000000..dcaa03e5d7 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/base64.c @@ -0,0 +1,324 @@ +/* OPENBSD ORIGINAL: lib/libc/net/base64.c */ + +/* $OpenBSD: base64.c,v 1.4 2002/01/02 23:00:10 deraadt Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "includes.h" + +#if (!defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP)) || (!defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON)) + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "base64.h" + +/* XXX abort illegal in library */ +#define Assert(Cond) if (!(Cond)) abort() + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +#if !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) +int +b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) +{ + size_t datalength = 0; + u_char input[3]; + u_char output[4]; + int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + Assert(output[3] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + Assert(output[0] < 64); + Assert(output[1] < 64); + Assert(output[2] < 64); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} +#endif /* !defined(HAVE_B64_NTOP) && !defined(HAVE___B64_NTOP) */ + +#if !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int +b64_pton(char const *src, u_char *target, size_t targsize) +{ + int tarindex, state, ch; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = *src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + target[tarindex+1] = ((pos - Base64) & 0x0f) + << 4 ; + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex + 1 >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + target[tarindex+1] = ((pos - Base64) & 0x03) + << 6; + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = *src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = *src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = *src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + return (tarindex); +} + +#endif /* !defined(HAVE_B64_PTON) && !defined(HAVE___B64_PTON) */ +#endif diff --git a/crypto/openssh-3.9p1/openbsd-compat/base64.h b/crypto/openssh-3.9p1/openbsd-compat/base64.h new file mode 100644 index 0000000000..732c6b3f83 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/base64.h @@ -0,0 +1,65 @@ +/* $Id: base64.h,v 1.6 2003/08/29 16:59:52 mouring Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _BSD_BASE64_H +#define _BSD_BASE64_H + +#include "includes.h" + +#ifndef HAVE___B64_NTOP +# ifndef HAVE_B64_NTOP +int b64_ntop(u_char const *src, size_t srclength, char *target, + size_t targsize); +# endif /* !HAVE_B64_NTOP */ +# define __b64_ntop(a,b,c,d) b64_ntop(a,b,c,d) +#endif /* HAVE___B64_NTOP */ + +#ifndef HAVE___B64_PTON +# ifndef HAVE_B64_PTON +int b64_pton(char const *src, u_char *target, size_t targsize); +# endif /* !HAVE_B64_PTON */ +# define __b64_pton(a,b,c) b64_pton(a,b,c) +#endif /* HAVE___B64_PTON */ + +#endif /* _BSD_BASE64_H */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/basename.c b/crypto/openssh-3.9p1/openbsd-compat/basename.c new file mode 100644 index 0000000000..552dc1e1cd --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/basename.c @@ -0,0 +1,64 @@ +/* OPENBSD ORIGINAL: lib/libc/gen/basename.c */ + +/* $OpenBSD: basename.c,v 1.11 2003/06/17 21:56:23 millert Exp $ */ + +/* + * Copyright (c) 1997 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" +#ifndef HAVE_BASENAME + +#ifndef lint +static char rcsid[] = "$OpenBSD: basename.c,v 1.11 2003/06/17 21:56:23 millert Exp $"; +#endif /* not lint */ + +char * +basename(const char *path) +{ + static char bname[MAXPATHLEN]; + register const char *endp, *startp; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + (void)strlcpy(bname, ".", sizeof bname); + return(bname); + } + + /* Strip trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* All slashes become "/" */ + if (endp == path && *endp == '/') { + (void)strlcpy(bname, "/", sizeof bname); + return(bname); + } + + /* Find the start of the base */ + startp = endp; + while (startp > path && *(startp - 1) != '/') + startp--; + + if (endp - startp + 2 > sizeof(bname)) { + errno = ENAMETOOLONG; + return(NULL); + } + strlcpy(bname, startp, endp - startp + 2); + return(bname); +} + +#endif /* !defined(HAVE_BASENAME) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bindresvport.c b/crypto/openssh-3.9p1/openbsd-compat/bindresvport.c new file mode 100644 index 0000000000..8a273f9b5e --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bindresvport.c @@ -0,0 +1,112 @@ +/* This file has be substantially modified from the original OpenBSD source */ + +/* $OpenBSD: bindresvport.c,v 1.15 2003/05/20 22:42:35 deraadt Exp $ */ + +/* + * Copyright 1996, Jason Downs. All rights reserved. + * Copyright 1998, Theo de Raadt. All rights reserved. + * Copyright 2000, Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#ifndef HAVE_BINDRESVPORT_SA + +#include "includes.h" + +#define STARTPORT 600 +#define ENDPORT (IPPORT_RESERVED - 1) +#define NPORTS (ENDPORT - STARTPORT + 1) + +/* + * Bind a socket to a privileged IP port + */ +int +bindresvport_sa(sd, sa) + int sd; + struct sockaddr *sa; +{ + int error, af; + struct sockaddr_storage myaddr; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + u_int16_t *portp; + u_int16_t port; + socklen_t salen; + int i; + + if (sa == NULL) { + memset(&myaddr, 0, sizeof(myaddr)); + sa = (struct sockaddr *)&myaddr; + + if (getsockname(sd, sa, &salen) == -1) + return -1; /* errno is correctly set */ + + af = sa->sa_family; + memset(&myaddr, 0, salen); + } else + af = sa->sa_family; + + if (af == AF_INET) { + sin = (struct sockaddr_in *)sa; + salen = sizeof(struct sockaddr_in); + portp = &sin->sin_port; + } else if (af == AF_INET6) { + sin6 = (struct sockaddr_in6 *)sa; + salen = sizeof(struct sockaddr_in6); + portp = &sin6->sin6_port; + } else { + errno = EPFNOSUPPORT; + return (-1); + } + sa->sa_family = af; + + port = ntohs(*portp); + if (port == 0) + port = (arc4random() % NPORTS) + STARTPORT; + + /* Avoid warning */ + error = -1; + + for(i = 0; i < NPORTS; i++) { + *portp = htons(port); + + error = bind(sd, sa, salen); + + /* Terminate on success */ + if (error == 0) + break; + + /* Terminate on errors, except "address already in use" */ + if ((error < 0) && !((errno == EADDRINUSE) || (errno == EINVAL))) + break; + + port++; + if (port > ENDPORT) + port = STARTPORT; + } + + return (error); +} + +#endif /* HAVE_BINDRESVPORT_SA */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-arc4random.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-arc4random.c new file mode 100644 index 0000000000..5284e1af80 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-arc4random.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1999,2000,2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" +#include "log.h" + +RCSID("$Id: bsd-arc4random.c,v 1.9 2004/07/18 23:30:40 djm Exp $"); + +#ifndef HAVE_ARC4RANDOM + +#include +#include +#include + +/* Size of key to use */ +#define SEED_SIZE 20 + +/* Number of bytes to reseed after */ +#define REKEY_BYTES (1 << 24) + +static int rc4_ready = 0; +static RC4_KEY rc4; + +unsigned int arc4random(void) +{ + unsigned int r = 0; + static int first_time = 1; + + if (rc4_ready <= 0) { + if (first_time) + seed_rng(); + first_time = 0; + arc4random_stir(); + } + + RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r); + + rc4_ready -= sizeof(r); + + return(r); +} + +void arc4random_stir(void) +{ + unsigned char rand_buf[SEED_SIZE]; + int i; + + memset(&rc4, 0, sizeof(rc4)); + if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0) + fatal("Couldn't obtain random bytes (error %ld)", + ERR_get_error()); + RC4_set_key(&rc4, sizeof(rand_buf), rand_buf); + + /* + * Discard early keystream, as per recommendations in: + * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps + */ + for(i = 0; i <= 256; i += sizeof(rand_buf)) + RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf); + + memset(rand_buf, 0, sizeof(rand_buf)); + + rc4_ready = REKEY_BYTES; +} +#endif /* !HAVE_ARC4RANDOM */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-closefrom.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-closefrom.c new file mode 100644 index 0000000000..61a9fa3916 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-closefrom.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2004 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifndef HAVE_CLOSEFROM + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif + +#ifndef OPEN_MAX +# define OPEN_MAX 256 +#endif + +RCSID("$Id: bsd-closefrom.c,v 1.1 2004/08/15 08:41:00 djm Exp $"); + +#ifndef lint +static const char sudorcsid[] = "$Sudo: closefrom.c,v 1.6 2004/06/01 20:51:56 millert Exp $"; +#endif /* lint */ + +/* + * Close all file descriptors greater than or equal to lowfd. + */ +void +closefrom(int lowfd) +{ + long fd, maxfd; +#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) + char fdpath[PATH_MAX], *endp; + struct dirent *dent; + DIR *dirp; + int len; + + /* Check for a /proc/$$/fd directory. */ + len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); + if (len != -1 && len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { + while ((dent = readdir(dirp)) != NULL) { + fd = strtol(dent->d_name, &endp, 10); + if (dent->d_name != endp && *endp == '\0' && + fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) + (void) close((int) fd); + } + (void) closedir(dirp); + } else +#endif + { + /* + * Fall back on sysconf() or getdtablesize(). We avoid checking + * resource limits since it is possible to open a file descriptor + * and then drop the rlimit such that it is below the open fd. + */ +#ifdef HAVE_SYSCONF + maxfd = sysconf(_SC_OPEN_MAX); +#else + maxfd = getdtablesize(); +#endif /* HAVE_SYSCONF */ + if (maxfd < 0) + maxfd = OPEN_MAX; + + for (fd = lowfd; fd < maxfd; fd++) + (void) close((int) fd); + } +} + +#endif /* HAVE_CLOSEFROM */ + diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-cray.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-cray.c new file mode 100644 index 0000000000..f630366be7 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-cray.c @@ -0,0 +1,816 @@ +/* + * $Id: bsd-cray.c,v 1.13 2004/01/30 03:34:22 dtucker Exp $ + * + * bsd-cray.c + * + * Copyright (c) 2002, Cray Inc. (Wendy Palm ) + * Significant portions provided by + * Wayne Schroeder, SDSC + * William Jones, UTexas + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Created: Apr 22 16.34:00 2002 wp + * + * This file contains functions required for proper execution + * on UNICOS systems. + * + */ +#ifdef _UNICOS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ssh.h" + +#include "includes.h" +#include "sys/types.h" + +#ifndef HAVE_STRUCT_SOCKADDR_STORAGE +# define _SS_MAXSIZE 128 /* Implementation specific max size */ +# define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr)) + +# define ss_family ss_sa.sa_family +#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */ + +#ifndef IN6_IS_ADDR_LOOPBACK +# define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \ + ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1)) +#endif /* !IN6_IS_ADDR_LOOPBACK */ + +#ifndef AF_INET6 +/* Define it to something that should never appear */ +#define AF_INET6 AF_MAX +#endif + +#include "log.h" +#include "servconf.h" +#include "bsd-cray.h" + +#define MAXACID 80 + +extern ServerOptions options; + +char cray_tmpdir[TPATHSIZ + 1]; /* job TMPDIR path */ + +struct sysv sysv; /* system security structure */ +struct usrv usrv; /* user security structure */ + +/* + * Functions. + */ +void cray_retain_utmp(struct utmp *, int); +void cray_delete_tmpdir(char *, int, uid_t); +void cray_init_job(struct passwd *); +void cray_set_tmpdir(struct utmp *); +void cray_login_failure(char *, int); +int cray_setup(uid_t, char *, const char *); +int cray_access_denied(char *); + +void +cray_login_failure(char *username, int errcode) +{ + struct udb *ueptr; /* UDB pointer for username */ + ia_failure_t fsent; /* ia_failure structure */ + ia_failure_ret_t fret; /* ia_failure return stuff */ + struct jtab jtab; /* job table structure */ + int jid = 0; /* job id */ + + if ((jid = getjtab(&jtab)) < 0) + debug("cray_login_failure(): getjtab error"); + + getsysudb(); + if ((ueptr = getudbnam(username)) == UDB_NULL) + debug("cray_login_failure(): getudbname() returned NULL"); + endudb(); + + memset(&fsent, '\0', sizeof(fsent)); + fsent.revision = 0; + fsent.uname = username; + fsent.host = (char *)get_canonical_hostname(options.use_dns); + fsent.ttyn = "sshd"; + fsent.caller = IA_SSHD; + fsent.flags = IA_INTERACTIVE; + fsent.ueptr = ueptr; + fsent.jid = jid; + fsent.errcode = errcode; + fsent.pwdp = NULL; + fsent.exitcode = 0; /* dont exit in ia_failure() */ + + fret.revision = 0; + fret.normal = 0; + + /* + * Call ia_failure because of an login failure. + */ + ia_failure(&fsent, &fret); +} + +/* + * Cray access denied + */ +int +cray_access_denied(char *username) +{ + struct udb *ueptr; /* UDB pointer for username */ + int errcode; /* IA errorcode */ + + errcode = 0; + getsysudb(); + if ((ueptr = getudbnam(username)) == UDB_NULL) + debug("cray_login_failure(): getudbname() returned NULL"); + endudb(); + + if (ueptr != NULL && ueptr->ue_disabled) + errcode = IA_DISABLED; + if (errcode) + cray_login_failure(username, errcode); + + return (errcode); +} + +/* + * record_failed_login: generic "login failed" interface function + */ +void +record_failed_login(const char *user, const char *ttyname) +{ + cray_login_failure((char *)user, IA_UDBERR); +} + +int +cray_setup (uid_t uid, char *username, const char *command) +{ + extern struct udb *getudb(); + extern char *setlimits(); + + int err; /* error return */ + time_t system_time; /* current system clock */ + time_t expiration_time; /* password expiration time */ + int maxattempts; /* maximum no. of failed login attempts */ + int SecureSys; /* unicos security flag */ + int minslevel = 0; /* system minimum security level */ + int i, j; + int valid_acct = -1; /* flag for reading valid acct */ + char acct_name[MAXACID] = { "" }; /* used to read acct name */ + struct jtab jtab; /* Job table struct */ + struct udb ue; /* udb entry for logging-in user */ + struct udb *up; /* pointer to UDB entry */ + struct secstat secinfo; /* file security attributes */ + struct servprov init_info; /* used for sesscntl() call */ + int jid; /* job ID */ + int pid; /* process ID */ + char *sr; /* status return from setlimits() */ + char *ttyn = NULL; /* ttyname or command name*/ + char hostname[MAXHOSTNAMELEN]; + /* passwd stuff for ia_user */ + passwd_t pwdacm, pwddialup, pwdudb, pwdwal, pwddce; + ia_user_ret_t uret; /* stuff returned from ia_user */ + ia_user_t usent; /* ia_user main structure */ + int ia_rcode; /* ia_user return code */ + ia_failure_t fsent; /* ia_failure structure */ + ia_failure_ret_t fret; /* ia_failure return stuff */ + ia_success_t ssent; /* ia_success structure */ + ia_success_ret_t sret; /* ia_success return stuff */ + int ia_mlsrcode; /* ia_mlsuser return code */ + int secstatrc; /* [f]secstat return code */ + + if (SecureSys = (int)sysconf(_SC_CRAY_SECURE_SYS)) { + getsysv(&sysv, sizeof(struct sysv)); + minslevel = sysv.sy_minlvl; + if (getusrv(&usrv) < 0) + fatal("getusrv() failed, errno = %d", errno); + } + hostname[0] = '\0'; + strlcpy(hostname, + (char *)get_canonical_hostname(options.use_dns), + MAXHOSTNAMELEN); + /* + * Fetch user's UDB entry. + */ + getsysudb(); + if ((up = getudbnam(username)) == UDB_NULL) + fatal("cannot fetch user's UDB entry"); + + /* + * Prevent any possible fudging so perform a data + * safety check and compare the supplied uid against + * the udb's uid. + */ + if (up->ue_uid != uid) + fatal("IA uid missmatch"); + endudb(); + + if ((jid = getjtab(&jtab)) < 0) { + debug("getjtab"); + return(-1); + } + pid = getpid(); + ttyn = ttyname(0); + if (SecureSys) { + if (ttyn != NULL) + secstatrc = secstat(ttyn, &secinfo); + else + secstatrc = fsecstat(1, &secinfo); + + if (secstatrc == 0) + debug("[f]secstat() successful"); + else + fatal("[f]secstat() error, rc = %d", secstatrc); + } + if ((ttyn == NULL) && ((char *)command != NULL)) + ttyn = (char *)command; + /* + * Initialize all structures to call ia_user + */ + usent.revision = 0; + usent.uname = username; + usent.host = hostname; + usent.ttyn = ttyn; + usent.caller = IA_SSHD; + usent.pswdlist = &pwdacm; + usent.ueptr = &ue; + usent.flags = IA_INTERACTIVE | IA_FFLAG; + pwdacm.atype = IA_SECURID; + pwdacm.pwdp = NULL; + pwdacm.next = &pwdudb; + + pwdudb.atype = IA_UDB; + pwdudb.pwdp = NULL; + pwdudb.next = &pwddce; + + pwddce.atype = IA_DCE; + pwddce.pwdp = NULL; + pwddce.next = &pwddialup; + + pwddialup.atype = IA_DIALUP; + pwddialup.pwdp = NULL; + /* pwddialup.next = &pwdwal; */ + pwddialup.next = NULL; + + pwdwal.atype = IA_WAL; + pwdwal.pwdp = NULL; + pwdwal.next = NULL; + + uret.revision = 0; + uret.pswd = NULL; + uret.normal = 0; + + ia_rcode = ia_user(&usent, &uret); + switch (ia_rcode) { + /* + * These are acceptable return codes from ia_user() + */ + case IA_UDBWEEK: /* Password Expires in 1 week */ + expiration_time = ue.ue_pwage.time + ue.ue_pwage.maxage; + printf ("WARNING - your current password will expire %s\n", + ctime((const time_t *)&expiration_time)); + break; + case IA_UDBEXPIRED: + if (ttyname(0) != NULL) { + /* Force a password change */ + printf("Your password has expired; Choose a new one.\n"); + execl("/bin/passwd", "passwd", username, 0); + exit(9); + } + break; + case IA_NORMAL: /* Normal Return Code */ + break; + case IA_BACKDOOR: + /* XXX: can we memset it to zero here so save some of this */ + strlcpy(ue.ue_name, "root", sizeof(ue.ue_name)); + strlcpy(ue.ue_dir, "/", sizeof(ue.ue_dir)); + strlcpy(ue.ue_shell, "/bin/sh", sizeof(ue.ue_shell)); + + ue.ue_passwd[0] = '\0'; + ue.ue_age[0] = '\0'; + ue.ue_comment[0] = '\0'; + ue.ue_loghost[0] = '\0'; + ue.ue_logline[0] = '\0'; + + ue.ue_uid = -1; + ue.ue_nice[UDBRC_INTER] = 0; + + for (i = 0; i < MAXVIDS; i++) + ue.ue_gids[i] = 0; + + ue.ue_logfails = 0; + ue.ue_minlvl = ue.ue_maxlvl = ue.ue_deflvl = minslevel; + ue.ue_defcomps = 0; + ue.ue_comparts = 0; + ue.ue_permits = 0; + ue.ue_trap = 0; + ue.ue_disabled = 0; + ue.ue_logtime = 0; + break; + case IA_CONSOLE: /* Superuser not from Console */ + case IA_TRUSTED: /* Trusted user */ + if (options.permit_root_login > PERMIT_NO) + break; /* Accept root login */ + default: + /* + * These are failed return codes from ia_user() + */ + switch (ia_rcode) + { + case IA_BADAUTH: + printf("Bad authorization, access denied.\n"); + break; + case IA_DISABLED: + printf("Your login has been disabled. Contact the system "); + printf("administrator for assistance.\n"); + break; + case IA_GETSYSV: + printf("getsysv() failed - errno = %d\n", errno); + break; + case IA_MAXLOGS: + printf("Maximum number of failed login attempts exceeded.\n"); + printf("Access denied.\n"); + break; + case IA_UDBPWDNULL: + if (SecureSys) + printf("NULL Password not allowed on MLS systems.\n"); + break; + default: + break; + } + + /* + * Authentication failed. + */ + printf("sshd: Login incorrect, (0%o)\n", + ia_rcode-IA_ERRORCODE); + + /* + * Initialize structure for ia_failure + * which will exit. + */ + fsent.revision = 0; + fsent.uname = username; + fsent.host = hostname; + fsent.ttyn = ttyn; + fsent.caller = IA_SSHD; + fsent.flags = IA_INTERACTIVE; + fsent.ueptr = &ue; + fsent.jid = jid; + fsent.errcode = ia_rcode; + fsent.pwdp = uret.pswd; + fsent.exitcode = 1; + + fret.revision = 0; + fret.normal = 0; + + /* + * Call ia_failure because of an IA failure. + * There is no return because ia_failure exits. + */ + ia_failure(&fsent, &fret); + + exit(1); + } + + ia_mlsrcode = IA_NORMAL; + if (SecureSys) { + debug("calling ia_mlsuser()"); + ia_mlsrcode = ia_mlsuser(&ue, &secinfo, &usrv, NULL, 0); + } + if (ia_mlsrcode != IA_NORMAL) { + printf("sshd: Login incorrect, (0%o)\n", + ia_mlsrcode-IA_ERRORCODE); + /* + * Initialize structure for ia_failure + * which will exit. + */ + fsent.revision = 0; + fsent.uname = username; + fsent.host = hostname; + fsent.ttyn = ttyn; + fsent.caller = IA_SSHD; + fsent.flags = IA_INTERACTIVE; + fsent.ueptr = &ue; + fsent.jid = jid; + fsent.errcode = ia_mlsrcode; + fsent.pwdp = uret.pswd; + fsent.exitcode = 1; + fret.revision = 0; + fret.normal = 0; + + /* + * Call ia_failure because of an IA failure. + * There is no return because ia_failure exits. + */ + ia_failure(&fsent,&fret); + exit(1); + } + + /* Provide login status information */ + if (options.print_lastlog && ue.ue_logtime != 0) { + printf("Last successful login was : %.*s ", 19, + (char *)ctime(&ue.ue_logtime)); + + if (*ue.ue_loghost != '\0') { + printf("from %.*s\n", sizeof(ue.ue_loghost), + ue.ue_loghost); + } else { + printf("on %.*s\n", sizeof(ue.ue_logline), + ue.ue_logline); + } + + if (SecureSys && (ue.ue_logfails != 0)) { + printf(" followed by %d failed attempts\n", + ue.ue_logfails); + } + } + + /* + * Call ia_success to process successful I/A. + */ + ssent.revision = 0; + ssent.uname = username; + ssent.host = hostname; + ssent.ttyn = ttyn; + ssent.caller = IA_SSHD; + ssent.flags = IA_INTERACTIVE; + ssent.ueptr = &ue; + ssent.jid = jid; + ssent.errcode = ia_rcode; + ssent.us = NULL; + ssent.time = 1; /* Set ue_logtime */ + + sret.revision = 0; + sret.normal = 0; + + ia_success(&ssent, &sret); + + /* + * Query for account, iff > 1 valid acid & askacid permbit + */ + if (((ue.ue_permbits & PERMBITS_ACCTID) || + (ue.ue_acids[0] >= 0) && (ue.ue_acids[1] >= 0)) && + ue.ue_permbits & PERMBITS_ASKACID) { + if (ttyname(0) != NULL) { + debug("cray_setup: ttyname true case, %.100s", ttyname); + while (valid_acct == -1) { + printf("Account (? for available accounts)" + " [%s]: ", acid2nam(ue.ue_acids[0])); + fgets(acct_name, MAXACID, stdin); + switch (acct_name[0]) { + case EOF: + exit(0); + break; + case '\0': + valid_acct = ue.ue_acids[0]; + strlcpy(acct_name, acid2nam(valid_acct), MAXACID); + break; + case '?': + /* Print the list 3 wide */ + for (i = 0, j = 0; i < MAXVIDS; i++) { + if (ue.ue_acids[i] == -1) { + printf("\n"); + break; + } + if (++j == 4) { + j = 1; + printf("\n"); + } + printf(" %s", + acid2nam(ue.ue_acids[i])); + } + if (ue.ue_permbits & PERMBITS_ACCTID) { + printf("\"acctid\" permbit also allows" + " you to select any valid " + "account name.\n"); + } + printf("\n"); + break; + default: + valid_acct = nam2acid(acct_name); + if (valid_acct == -1) + printf( + "Account id not found for" + " account name \"%s\"\n\n", + acct_name); + break; + } + /* + * If an account was given, search the user's + * acids array to verify they can use this account. + */ + if ((valid_acct != -1) && + !(ue.ue_permbits & PERMBITS_ACCTID)) { + for (i = 0; i < MAXVIDS; i++) { + if (ue.ue_acids[i] == -1) + break; + if (valid_acct == ue.ue_acids[i]) + break; + } + if (i == MAXVIDS || + ue.ue_acids[i] == -1) { + fprintf(stderr, "Cannot set" + " account name to " + "\"%s\", permission " + "denied\n\n", acct_name); + valid_acct = -1; + } + } + } + } else { + /* + * The client isn't connected to a terminal and can't + * respond to an acid prompt. Use default acid. + */ + debug("cray_setup: ttyname false case, %.100s", + ttyname); + valid_acct = ue.ue_acids[0]; + } + } else { + /* + * The user doesn't have the askacid permbit set or + * only has one valid account to use. + */ + valid_acct = ue.ue_acids[0]; + } + if (acctid(0, valid_acct) < 0) { + printf ("Bad account id: %d\n", valid_acct); + exit(1); + } + + /* + * Now set shares, quotas, limits, including CPU time for the + * (interactive) job and process, and set up permissions + * (for chown etc), etc. + */ + if (setshares(ue.ue_uid, valid_acct, printf, 0, 0)) { + printf("Unable to give %d shares to <%s>(%d/%d)\n", + ue.ue_shares, ue.ue_name, ue.ue_uid, valid_acct); + exit(1); + } + + sr = setlimits(username, C_PROC, pid, UDBRC_INTER); + if (sr != NULL) { + debug("%.200s", sr); + exit(1); + } + sr = setlimits(username, C_JOB, jid, UDBRC_INTER); + if (sr != NULL) { + debug("%.200s", sr); + exit(1); + } + /* + * Place the service provider information into + * the session table (Unicos) or job table (Unicos/mk). + * There exist double defines for the job/session table in + * unicos/mk (jtab.h) so no need for a compile time switch. + */ + memset(&init_info, '\0', sizeof(init_info)); + init_info.s_sessinit.si_id = URM_SPT_LOGIN; + init_info.s_sessinit.si_pid = getpid(); + init_info.s_sessinit.si_sid = jid; + sesscntl(0, S_SETSERVPO, (int)&init_info); + + /* + * Set user and controlling tty security attributes. + */ + if (SecureSys) { + if (setusrv(&usrv) == -1) { + debug("setusrv() failed, errno = %d",errno); + exit(1); + } + } + + return (0); +} + +/* + * The rc.* and /etc/sdaemon methods of starting a program on unicos/unicosmk + * can have pal privileges that sshd can inherit which + * could allow a user to su to root with out a password. + * This subroutine clears all privileges. + */ +void +drop_cray_privs() +{ +#if defined(_SC_CRAY_PRIV_SU) + priv_proc_t *privstate; + int result; + extern int priv_set_proc(); + extern priv_proc_t *priv_init_proc(); + + /* + * If ether of theses two flags are not set + * then don't allow this version of ssh to run. + */ + if (!sysconf(_SC_CRAY_PRIV_SU)) + fatal("Not PRIV_SU system."); + if (!sysconf(_SC_CRAY_POSIX_PRIV)) + fatal("Not POSIX_PRIV."); + + debug("Setting MLS labels.");; + + if (sysconf(_SC_CRAY_SECURE_MAC)) { + usrv.sv_minlvl = SYSLOW; + usrv.sv_actlvl = SYSHIGH; + usrv.sv_maxlvl = SYSHIGH; + } else { + usrv.sv_minlvl = sysv.sy_minlvl; + usrv.sv_actlvl = sysv.sy_minlvl; + usrv.sv_maxlvl = sysv.sy_maxlvl; + } + usrv.sv_actcmp = 0; + usrv.sv_valcmp = sysv.sy_valcmp; + + usrv.sv_intcat = TFM_SYSTEM; + usrv.sv_valcat |= (TFM_SYSTEM | TFM_SYSFILE); + + if (setusrv(&usrv) < 0) { + fatal("%s(%d): setusrv(): %s", __FILE__, __LINE__, + strerror(errno)); + } + + if ((privstate = priv_init_proc()) != NULL) { + result = priv_set_proc(privstate); + if (result != 0 ) { + fatal("%s(%d): priv_set_proc(): %s", + __FILE__, __LINE__, strerror(errno)); + } + priv_free_proc(privstate); + } + debug ("Privileges should be cleared..."); +#else + /* XXX: do this differently */ +# error Cray systems must be run with _SC_CRAY_PRIV_SU on! +#endif +} + + +/* + * Retain utmp/wtmp information - used by cray accounting. + */ +void +cray_retain_utmp(struct utmp *ut, int pid) +{ + int fd; + struct utmp utmp; + + if ((fd = open(UTMP_FILE, O_RDONLY)) != -1) { + /* XXX use atomicio */ + while (read(fd, (char *)&utmp, sizeof(utmp)) == sizeof(utmp)) { + if (pid == utmp.ut_pid) { + ut->ut_jid = utmp.ut_jid; + strncpy(ut->ut_tpath, utmp.ut_tpath, sizeof(utmp.ut_tpath)); + strncpy(ut->ut_host, utmp.ut_host, sizeof(utmp.ut_host)); + strncpy(ut->ut_name, utmp.ut_name, sizeof(utmp.ut_name)); + break; + } + } + close(fd); + } else + fatal("Unable to open utmp file"); +} + +/* + * tmpdir support. + */ + +/* + * find and delete jobs tmpdir. + */ +void +cray_delete_tmpdir(char *login, int jid, uid_t uid) +{ + static char jtmp[TPATHSIZ]; + struct stat statbuf; + int child, c, wstat; + + for (c = 'a'; c <= 'z'; c++) { + snprintf(jtmp, TPATHSIZ, "%s/jtmp.%06d%c", JTMPDIR, jid, c); + if (stat(jtmp, &statbuf) == 0 && statbuf.st_uid == uid) + break; + } + + if (c > 'z') + return; + + if ((child = fork()) == 0) { + execl(CLEANTMPCMD, CLEANTMPCMD, login, jtmp, (char *)NULL); + fatal("cray_delete_tmpdir: execl of CLEANTMPCMD failed"); + } + + while (waitpid(child, &wstat, 0) == -1 && errno == EINTR) + ; +} + +/* + * Remove tmpdir on job termination. + */ +void +cray_job_termination_handler(int sig) +{ + int jid; + char *login = NULL; + struct jtab jtab; + + debug("received signal %d",sig); + + if ((jid = waitjob(&jtab)) == -1 || + (login = uid2nam(jtab.j_uid)) == NULL) + return; + + cray_delete_tmpdir(login, jid, jtab.j_uid); +} + +/* + * Set job id and create tmpdir directory. + */ +void +cray_init_job(struct passwd *pw) +{ + int jid; + int c; + + jid = setjob(pw->pw_uid, WJSIGNAL); + if (jid < 0) + fatal("System call setjob failure"); + + for (c = 'a'; c <= 'z'; c++) { + snprintf(cray_tmpdir, TPATHSIZ, "%s/jtmp.%06d%c", JTMPDIR, jid, c); + if (mkdir(cray_tmpdir, JTMPMODE) != 0) + continue; + if (chown(cray_tmpdir, pw->pw_uid, pw->pw_gid) != 0) { + rmdir(cray_tmpdir); + continue; + } + break; + } + + if (c > 'z') + cray_tmpdir[0] = '\0'; +} + +void +cray_set_tmpdir(struct utmp *ut) +{ + int jid; + struct jtab jbuf; + + if ((jid = getjtab(&jbuf)) < 0) + return; + + /* + * Set jid and tmpdir in utmp record. + */ + ut->ut_jid = jid; + strncpy(ut->ut_tpath, cray_tmpdir, TPATHSIZ); +} +#endif /* UNICOS */ + +#ifdef _UNICOSMP +#include +/* + * Set job id and create tmpdir directory. + */ +void +cray_init_job(struct passwd *pw) +{ + initrm_silent(pw->pw_uid); + return; +} +#endif /* _UNICOSMP */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-cray.h b/crypto/openssh-3.9p1/openbsd-compat/bsd-cray.h new file mode 100644 index 0000000000..de6ba1a8d1 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-cray.h @@ -0,0 +1,61 @@ +/* $Id: bsd-cray.h,v 1.11 2004/01/30 03:34:22 dtucker Exp $ */ + +/* + * Copyright (c) 2002, Cray Inc. (Wendy Palm ) + * Significant portions provided by + * Wayne Schroeder, SDSC + * William Jones, UTexas + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Created: Apr 22 16.34:00 2002 wp + * + * This file contains functions required for proper execution + * on UNICOS systems. + * + */ + +#ifndef _BSD_CRAY_H +#define _BSD_CRAY_H + +#ifdef _UNICOS + +void cray_init_job(struct passwd *); +void cray_job_termination_handler(int); +void cray_login_failure(char *, int ); +int cray_access_denied(char *); +#define CUSTOM_FAILED_LOGIN 1 +void record_failed_login(const char *, const char *); +extern char cray_tmpdir[]; + +#ifndef IA_SSHD +# define IA_SSHD IA_LOGIN +#endif +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 64 +#endif +#ifndef _CRAYT3E +# define TIOCGPGRP (tIOC|20) +#endif + +#endif /* UNICOS */ + +#endif /* _BSD_CRAY_H */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-cygwin_util.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-cygwin_util.c new file mode 100644 index 0000000000..92cdba6e09 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-cygwin_util.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2000, 2001, Corinna Vinschen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Created: Sat Sep 02 12:17:00 2000 cv + * + * This file contains functions for forcing opened file descriptors to + * binary mode on Windows systems. + */ + +#include "includes.h" + +RCSID("$Id: bsd-cygwin_util.c,v 1.12 2004/04/18 11:15:45 djm Exp $"); + +#ifdef HAVE_CYGWIN + +#include +#include +#include +#include +#include +#define is_winnt (GetVersion() < 0x80000000) + +#define ntsec_on(c) ((c) && strstr((c),"ntsec") && !strstr((c),"nontsec")) +#define ntsec_off(c) ((c) && strstr((c),"nontsec")) +#define ntea_on(c) ((c) && strstr((c),"ntea") && !strstr((c),"nontea")) + +#if defined(open) && open == binary_open +# undef open +#endif +#if defined(pipe) && open == binary_pipe +# undef pipe +#endif + +int +binary_open(const char *filename, int flags, ...) +{ + va_list ap; + mode_t mode; + + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + return (open(filename, flags | O_BINARY, mode)); +} + +int +binary_pipe(int fd[2]) +{ + int ret = pipe(fd); + + if (!ret) { + setmode(fd[0], O_BINARY); + setmode(fd[1], O_BINARY); + } + return (ret); +} + +#define HAS_CREATE_TOKEN 1 +#define HAS_NTSEC_BY_DEFAULT 2 +#define HAS_CREATE_TOKEN_WO_NTSEC 3 + +static int +has_capability(int what) +{ + static int inited; + static int has_create_token; + static int has_ntsec_by_default; + static int has_create_token_wo_ntsec; + + /* + * has_capability() basically calls uname() and checks if + * specific capabilities of Cygwin can be evaluated from that. + * This simplifies the calling functions which only have to ask + * for a capability using has_capability() instead of having + * to figure that out by themselves. + */ + if (!inited) { + struct utsname uts; + char *c; + + if (!uname(&uts)) { + int major_high = 0, major_low = 0, minor = 0; + int api_major_version = 0, api_minor_version = 0; + char *c; + + sscanf(uts.release, "%d.%d.%d", &major_high, + &major_low, &minor); + if ((c = strchr(uts.release, '(')) != NULL) { + sscanf(c + 1, "%d.%d", &api_major_version, + &api_minor_version); + } + if (major_high > 1 || + (major_high == 1 && (major_low > 3 || + (major_low == 3 && minor >= 2)))) + has_create_token = 1; + if (api_major_version > 0 || api_minor_version >= 56) + has_ntsec_by_default = 1; + if (major_high > 1 || + (major_high == 1 && major_low >= 5)) + has_create_token_wo_ntsec = 1; + inited = 1; + } + } + switch (what) { + case HAS_CREATE_TOKEN: + return (has_create_token); + case HAS_NTSEC_BY_DEFAULT: + return (has_ntsec_by_default); + case HAS_CREATE_TOKEN_WO_NTSEC: + return (has_create_token_wo_ntsec); + } + return (0); +} + +int +check_nt_auth(int pwd_authenticated, struct passwd *pw) +{ + /* + * The only authentication which is able to change the user + * context on NT systems is the password authentication. So + * we deny all requsts for changing the user context if another + * authentication method is used. + * + * This doesn't apply to Cygwin versions >= 1.3.2 anymore which + * uses the undocumented NtCreateToken() call to create a user + * token if the process has the appropriate privileges and if + * CYGWIN ntsec setting is on. + */ + static int has_create_token = -1; + + if (pw == NULL) + return 0; + if (is_winnt) { + if (has_create_token < 0) { + char *cygwin = getenv("CYGWIN"); + + has_create_token = 0; + if (has_capability(HAS_CREATE_TOKEN) && + (ntsec_on(cygwin) || + (has_capability(HAS_NTSEC_BY_DEFAULT) && + !ntsec_off(cygwin)) || + has_capability(HAS_CREATE_TOKEN_WO_NTSEC))) + has_create_token = 1; + } + if (has_create_token < 1 && + !pwd_authenticated && geteuid() != pw->pw_uid) + return (0); + } + return (1); +} + +int +check_ntsec(const char *filename) +{ + char *cygwin; + int allow_ntea = 0, allow_ntsec = 0; + struct statfs fsstat; + + /* Windows 95/98/ME don't support file system security at all. */ + if (!is_winnt) + return (0); + + /* Evaluate current CYGWIN settings. */ + cygwin = getenv("CYGWIN"); + allow_ntea = ntea_on(cygwin); + allow_ntsec = ntsec_on(cygwin) || + (has_capability(HAS_NTSEC_BY_DEFAULT) && !ntsec_off(cygwin)); + + /* + * `ntea' is an emulation of POSIX attributes. It doesn't support + * real file level security as ntsec on NTFS file systems does + * but it supports FAT filesystems. `ntea' is minimum requirement + * for security checks. + */ + if (allow_ntea) + return (1); + + /* + * Retrieve file system flags. In Cygwin, file system flags are + * copied to f_type which has no meaning in Win32 itself. + */ + if (statfs(filename, &fsstat)) + return (1); + + /* + * Only file systems supporting ACLs are able to set permissions. + * `ntsec' is the setting in Cygwin which switches using of NTFS + * ACLs to support POSIX permissions on files. + */ + if (fsstat.f_type & FS_PERSISTENT_ACLS) + return (allow_ntsec); + + return (0); +} + +void +register_9x_service(void) +{ + HINSTANCE kerneldll; + DWORD (*RegisterServiceProcess)(DWORD, DWORD); + + /* The service register mechanism in 9x/Me is pretty different from + * NT/2K/XP. In NT/2K/XP we're using a special service starter + * application to register and control sshd as service. This method + * doesn't play nicely with 9x/Me. For that reason we register here + * as service when running under 9x/Me. This function is only called + * by the child sshd when it's going to daemonize. + */ + if (is_winnt) + return; + if (!(kerneldll = LoadLibrary("KERNEL32.DLL"))) + return; + if (!(RegisterServiceProcess = (DWORD (*)(DWORD, DWORD)) + GetProcAddress(kerneldll, "RegisterServiceProcess"))) + return; + RegisterServiceProcess(0, 1); +} + +#endif /* HAVE_CYGWIN */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-cygwin_util.h b/crypto/openssh-3.9p1/openbsd-compat/bsd-cygwin_util.h new file mode 100644 index 0000000000..5ccb0fba27 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-cygwin_util.h @@ -0,0 +1,55 @@ +/* $Id: bsd-cygwin_util.h,v 1.10 2003/08/07 06:28:16 dtucker Exp $ */ + +/* + * Copyright (c) 2000, 2001, Corinna Vinschen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Created: Sat Sep 02 12:17:00 2000 cv + * + * This file contains functions for forcing opened file descriptors to + * binary mode on Windows systems. + */ + +#ifndef _BSD_CYGWIN_UTIL_H +#define _BSD_CYGWIN_UTIL_H + +#ifdef HAVE_CYGWIN + +#undef ERROR +#define is_winnt (GetVersion() < 0x80000000) + +#include +#include +#include + +int binary_open(const char *, int , ...); +int binary_pipe(int fd[2]); +int check_nt_auth(int, struct passwd *); +int check_ntsec(const char *); +void register_9x_service(void); + +#define open binary_open +#define pipe binary_pipe + +#endif /* HAVE_CYGWIN */ + +#endif /* _BSD_CYGWIN_UTIL_H */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-getpeereid.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-getpeereid.c new file mode 100644 index 0000000000..fe2edad710 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-getpeereid.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2002,2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +RCSID("$Id: bsd-getpeereid.c,v 1.3 2004/02/17 05:49:55 djm Exp $"); + +#if !defined(HAVE_GETPEEREID) + +#if defined(SO_PEERCRED) +int +getpeereid(int s, uid_t *euid, gid_t *gid) +{ + struct ucred cred; + socklen_t len = sizeof(cred); + + if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0) + return (-1); + *euid = cred.uid; + *gid = cred.gid; + + return (0); +} +#else +int +getpeereid(int s, uid_t *euid, gid_t *gid) +{ + *euid = geteuid(); + *gid = getgid(); + + return (0); +} +#endif /* defined(SO_PEERCRED) */ + +#endif /* !defined(HAVE_GETPEEREID) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-misc.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-misc.c new file mode 100644 index 0000000000..1b276b4f42 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-misc.c @@ -0,0 +1,225 @@ + +/* + * Copyright (c) 1999-2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" +#include "xmalloc.h" + +RCSID("$Id: bsd-misc.c,v 1.25 2004/08/15 08:41:00 djm Exp $"); + +#ifndef HAVE___PROGNAME +char *__progname; +#endif + +/* + * NB. duplicate __progname in case it is an alias for argv[0] + * Otherwise it may get clobbered by setproctitle() + */ +char *ssh_get_progname(char *argv0) +{ +#ifdef HAVE___PROGNAME + extern char *__progname; + + return xstrdup(__progname); +#else + char *p; + + if (argv0 == NULL) + return ("unknown"); /* XXX */ + p = strrchr(argv0, '/'); + if (p == NULL) + p = argv0; + else + p++; + + return (xstrdup(p)); +#endif +} + +#ifndef HAVE_SETLOGIN +int setlogin(const char *name) +{ + return (0); +} +#endif /* !HAVE_SETLOGIN */ + +#ifndef HAVE_INNETGR +int innetgr(const char *netgroup, const char *host, + const char *user, const char *domain) +{ + return (0); +} +#endif /* HAVE_INNETGR */ + +#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) +int seteuid(uid_t euid) +{ + return (setreuid(-1, euid)); +} +#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ + +#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) +int setegid(uid_t egid) +{ + return(setresgid(-1, egid, -1)); +} +#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */ + +#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR) +const char *strerror(int e) +{ + extern int sys_nerr; + extern char *sys_errlist[]; + + if ((e >= 0) && (e < sys_nerr)) + return (sys_errlist[e]); + + return ("unlisted error"); +} +#endif + +#ifndef HAVE_UTIMES +int utimes(char *filename, struct timeval *tvp) +{ + struct utimbuf ub; + + ub.actime = tvp[0].tv_sec; + ub.modtime = tvp[1].tv_sec; + + return (utime(filename, &ub)); +} +#endif + +#ifndef HAVE_TRUNCATE +int truncate(const char *path, off_t length) +{ + int fd, ret, saverrno; + + fd = open(path, O_WRONLY); + if (fd < 0) + return (-1); + + ret = ftruncate(fd, length); + saverrno = errno; + close(fd); + if (ret == -1) + errno = saverrno; + + return(ret); +} +#endif /* HAVE_TRUNCATE */ + +#if !defined(HAVE_SETGROUPS) && defined(SETGROUPS_NOOP) +/* + * Cygwin setgroups should be a noop. + */ +int +setgroups(size_t size, const gid_t *list) +{ + return (0); +} +#endif + +#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP) +int nanosleep(const struct timespec *req, struct timespec *rem) +{ + int rc, saverrno; + extern int errno; + struct timeval tstart, tstop, tremain, time2wait; + + TIMESPEC_TO_TIMEVAL(&time2wait, req) + (void) gettimeofday(&tstart, NULL); + rc = select(0, NULL, NULL, NULL, &time2wait); + if (rc == -1) { + saverrno = errno; + (void) gettimeofday (&tstop, NULL); + errno = saverrno; + tremain.tv_sec = time2wait.tv_sec - + (tstop.tv_sec - tstart.tv_sec); + tremain.tv_usec = time2wait.tv_usec - + (tstop.tv_usec - tstart.tv_usec); + tremain.tv_sec += tremain.tv_usec / 1000000L; + tremain.tv_usec %= 1000000L; + } else { + tremain.tv_sec = 0; + tremain.tv_usec = 0; + } + TIMEVAL_TO_TIMESPEC(&tremain, rem) + + return(rc); +} +#endif + +#ifndef HAVE_TCGETPGRP +pid_t +tcgetpgrp(int fd) +{ + int ctty_pgrp; + + if (ioctl(fd, TIOCGPGRP, &ctty_pgrp) == -1) + return(-1); + else + return(ctty_pgrp); +} +#endif /* HAVE_TCGETPGRP */ + +#ifndef HAVE_TCSENDBREAK +int +tcsendbreak(int fd, int duration) +{ +# if defined(TIOCSBRK) && defined(TIOCCBRK) + struct timeval sleepytime; + + sleepytime.tv_sec = 0; + sleepytime.tv_usec = 400000; + if (ioctl(fd, TIOCSBRK, 0) == -1) + return (-1); + (void)select(0, 0, 0, 0, &sleepytime); + if (ioctl(fd, TIOCCBRK, 0) == -1) + return (-1); + return (0); +# else + return -1; +# endif +} +#endif /* HAVE_TCSENDBREAK */ + +mysig_t +mysignal(int sig, mysig_t act) +{ +#ifdef HAVE_SIGACTION + struct sigaction sa, osa; + + if (sigaction(sig, NULL, &osa) == -1) + return (mysig_t) -1; + if (osa.sa_handler != act) { + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; +#ifdef SA_INTERRUPT + if (sig == SIGALRM) + sa.sa_flags |= SA_INTERRUPT; +#endif + sa.sa_handler = act; + if (sigaction(sig, &sa, NULL) == -1) + return (mysig_t) -1; + } + return (osa.sa_handler); +#else + #undef signal + return (signal(sig, act)); +#endif +} diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-misc.h b/crypto/openssh-3.9p1/openbsd-compat/bsd-misc.h new file mode 100644 index 0000000000..33a1d707fc --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-misc.h @@ -0,0 +1,102 @@ +/* $Id: bsd-misc.h,v 1.17 2004/08/15 08:41:00 djm Exp $ */ + +/* + * Copyright (c) 1999-2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _BSD_MISC_H +#define _BSD_MISC_H + +#include "includes.h" + +char *ssh_get_progname(char *); + +#ifndef HAVE_SETSID +#define setsid() setpgrp(0, getpid()) +#endif /* !HAVE_SETSID */ + +#ifndef HAVE_SETENV +int setenv(const char *, const char *, int); +#endif /* !HAVE_SETENV */ + +#ifndef HAVE_SETLOGIN +int setlogin(const char *); +#endif /* !HAVE_SETLOGIN */ + +#ifndef HAVE_INNETGR +int innetgr(const char *, const char *, const char *, const char *); +#endif /* HAVE_INNETGR */ + +#if !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) +int seteuid(uid_t); +#endif /* !defined(HAVE_SETEUID) && defined(HAVE_SETREUID) */ + +#if !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) +int setegid(uid_t); +#endif /* !defined(HAVE_SETEGID) && defined(HAVE_SETRESGID) */ + +#if !defined(HAVE_STRERROR) && defined(HAVE_SYS_ERRLIST) && defined(HAVE_SYS_NERR) +const char *strerror(int); +#endif + + +#ifndef HAVE_UTIMES +#ifndef HAVE_STRUCT_TIMEVAL +struct timeval { + long tv_sec; + long tv_usec; +} +#endif /* HAVE_STRUCT_TIMEVAL */ + +int utimes(char *, struct timeval *); +#endif /* HAVE_UTIMES */ + +#ifndef HAVE_TRUNCATE +int truncate (const char *, off_t); +#endif /* HAVE_TRUNCATE */ + +#if !defined(HAVE_SETGROUPS) && defined(SETGROUPS_NOOP) +int setgroups(size_t, const gid_t *); +#endif + +#if !defined(HAVE_NANOSLEEP) && !defined(HAVE_NSLEEP) +#ifndef HAVE_STRUCT_TIMESPEC +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif +int nanosleep(const struct timespec *, struct timespec *); +#endif + +#ifndef HAVE_TCGETPGRP +pid_t tcgetpgrp(int); +#endif + +#ifndef HAVE_TCSENDBREAK +int tcsendbreak(int, int); +#endif + +#ifndef HAVE_UNSETENV +void unsetenv(const char *); +#endif + +/* wrapper for signal interface */ +typedef void (*mysig_t)(int); +mysig_t mysignal(int sig, mysig_t act); + +#define signal(a,b) mysignal(a,b) + +#endif /* _BSD_MISC_H */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-nextstep.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-nextstep.c new file mode 100644 index 0000000000..bd35a3afc9 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-nextstep.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000,2001 Ben Lindstrom. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +RCSID("$Id: bsd-nextstep.c,v 1.6 2003/06/01 03:23:57 mouring Exp $"); + +#ifdef HAVE_NEXT +#include +#include +#include "bsd-nextstep.h" + +pid_t +posix_wait(int *status) +{ + union wait statusp; + pid_t wait_pid; + + #undef wait /* Use NeXT's wait() function */ + wait_pid = wait(&statusp); + if (status) + *status = (int) statusp.w_status; + + return (wait_pid); +} + +int +tcgetattr(int fd, struct termios *t) +{ + return (ioctl(fd, TIOCGETA, t)); +} + +int +tcsetattr(int fd, int opt, const struct termios *t) +{ + struct termios localterm; + + if (opt & TCSASOFT) { + localterm = *t; + localterm.c_cflag |= CIGNORE; + t = &localterm; + } + switch (opt & ~TCSASOFT) { + case TCSANOW: + return (ioctl(fd, TIOCSETA, t)); + case TCSADRAIN: + return (ioctl(fd, TIOCSETAW, t)); + case TCSAFLUSH: + return (ioctl(fd, TIOCSETAF, t)); + default: + errno = EINVAL; + return (-1); + } +} + +int tcsetpgrp(int fd, pid_t pgrp) +{ + return (ioctl(fd, TIOCSPGRP, &pgrp)); +} + +speed_t cfgetospeed(const struct termios *t) +{ + return (t->c_ospeed); +} + +speed_t cfgetispeed(const struct termios *t) +{ + return (t->c_ispeed); +} + +int +cfsetospeed(struct termios *t,int speed) +{ + t->c_ospeed = speed; + return (0); +} + +int +cfsetispeed(struct termios *t, int speed) +{ + t->c_ispeed = speed; + return (0); +} +#endif /* HAVE_NEXT */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-nextstep.h b/crypto/openssh-3.9p1/openbsd-compat/bsd-nextstep.h new file mode 100644 index 0000000000..ca5b4b54a4 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-nextstep.h @@ -0,0 +1,59 @@ +/* $Id: bsd-nextstep.h,v 1.9 2003/08/29 16:59:52 mouring Exp $ */ + +/* + * Copyright (c) 2000,2001 Ben Lindstrom. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _NEXT_POSIX_H +#define _NEXT_POSIX_H + +#ifdef HAVE_NEXT +#include + +/* NGROUPS_MAX is behind -lposix. Use the BSD version which is NGROUPS */ +#undef NGROUPS_MAX +#define NGROUPS_MAX NGROUPS + +/* NeXT's readdir() is BSD (struct direct) not POSIX (struct dirent) */ +#define dirent direct + +/* Swap out NeXT's BSD wait() for a more POSIX complient one */ +pid_t posix_wait(int *); +#define wait(a) posix_wait(a) + +/* #ifdef wrapped functions that need defining for clean compiling */ +pid_t getppid(void); +void vhangup(void); +int innetgr(const char *, const char *, const char *, const char *); + +/* TERMCAP */ +int tcgetattr(int, struct termios *); +int tcsetattr(int, int, const struct termios *); +int tcsetpgrp(int, pid_t); +speed_t cfgetospeed(const struct termios *); +speed_t cfgetispeed(const struct termios *); +int cfsetospeed(struct termios *, int); +int cfsetispeed(struct termios *, int); +#endif /* HAVE_NEXT */ +#endif /* _NEXT_POSIX_H */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-openpty.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-openpty.c new file mode 100644 index 0000000000..daf5f8b811 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-openpty.c @@ -0,0 +1,203 @@ +/* + * Please note: this implementation of openpty() is far from complete. + * it is just enough for portable OpenSSH's needs. + */ + +/* + * Copyright (c) 2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Allocating a pseudo-terminal, and making it the controlling tty. + * + * 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". + */ + +#include "includes.h" +#if !defined(HAVE_OPENPTY) + +#ifdef HAVE_UTIL_H +# include +#endif /* HAVE_UTIL_H */ + +#ifdef HAVE_PTY_H +# include +#endif +#if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H) +# include +#endif + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +int +openpty(int *amaster, int *aslave, char *name, struct termios *termp, + struct winsize *winp) +{ +#if defined(HAVE__GETPTY) + /* + * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more + * pty's automagically when needed + */ + char *slave; + + if ((slave = _getpty(amaster, O_RDWR, 0622, 0)) == NULL) + return (-1); + + /* Open the slave side. */ + if ((*aslave = open(slave, O_RDWR | O_NOCTTY)) == -1) { + close(*amaster); + return (-1); + } + return (0); + +#elif defined(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; + mysig_t old_signal; + + if ((ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1) + return (-1); + + /* XXX: need to close ptm on error? */ + old_signal = signal(SIGCHLD, SIG_DFL); + if (grantpt(ptm) < 0) + return (-1); + signal(SIGCHLD, old_signal); + + if (unlockpt(ptm) < 0) + return (-1); + + if ((pts = ptsname(ptm)) == NULL) + return (-1); + *amaster = ptm; + + /* Open the slave side. */ + if ((*aslave = open(pts, O_RDWR | O_NOCTTY)) == -1) { + close(*amaster); + return (-1); + } + +#ifndef HAVE_CYGWIN + /* + * Try to push the appropriate streams modules, as described + * in Solaris pts(7). + */ + ioctl(*aslave, I_PUSH, "ptem"); + ioctl(*aslave, I_PUSH, "ldterm"); +# ifndef __hpux + ioctl(*aslave, I_PUSH, "ttcompat"); +# endif /* __hpux */ +#endif /* HAVE_CYGWIN */ + + return (0); + +#elif defined(HAVE_DEV_PTS_AND_PTC) + /* AIX-style pty code. */ + const char *ttname; + + if ((*amaster = open("/dev/ptc", O_RDWR | O_NOCTTY)) == -1) + return (-1); + if ((ttname = ttyname(*amaster)) == NULL) + return (-1); + if ((*aslave = open(ttname, O_RDWR | O_NOCTTY)) == -1) { + close(*amaster); + return (-1); + } + return (0); + +#elif defined(_UNICOS) + char ptbuf[64], ttbuf[64]; + int i; + int highpty; + + highpty = 128; +#ifdef _SC_CRAY_NPTY + if ((highpty = sysconf(_SC_CRAY_NPTY)) == -1) + highpty = 128; +#endif /* _SC_CRAY_NPTY */ + + for (i = 0; i < highpty; i++) { + snprintf(ptbuf, sizeof(ptbuf), "/dev/pty/%03d", i); + snprintf(ttbuf, sizeof(ttbuf), "/dev/ttyp%03d", i); + if ((*amaster = open(ptbuf, O_RDWR|O_NOCTTY)) == -1) + continue; + /* Open the slave side. */ + if ((*aslave = open(ttbuf, O_RDWR|O_NOCTTY)) == -1) { + close(*amaster); + return (-1); + } + return (0); + } + return (-1); + +#else + /* BSD-style pty code. */ + char ptbuf[64], ttbuf[64]; + int i; + const char *ptymajors = "pqrstuvwxyzabcdefghijklmno" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const char *ptyminors = "0123456789abcdef"; + int num_minors = strlen(ptyminors); + int num_ptys = strlen(ptymajors) * num_minors; + struct termios tio; + + for (i = 0; i < num_ptys; i++) { + snprintf(ptbuf, sizeof(ptbuf), "/dev/pty%c%c", + ptymajors[i / num_minors], ptyminors[i % num_minors]); + snprintf(ttbuf, sizeof(ttbuf), "/dev/tty%c%c", + ptymajors[i / num_minors], ptyminors[i % num_minors]); + + if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1) { + /* Try SCO style naming */ + snprintf(ptbuf, sizeof(ptbuf), "/dev/ptyp%d", i); + snprintf(ttbuf, sizeof(ttbuf), "/dev/ttyp%d", i); + if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1) + continue; + } + + /* Open the slave side. */ + if ((*aslave = open(ttbuf, O_RDWR | O_NOCTTY)) == -1) { + close(*amaster); + return (-1); + } + /* set tty modes to a sane state for broken clients */ + if (tcgetattr(*amaster, &tio) != -1) { + tio.c_lflag |= (ECHO | ISIG | ICANON); + tio.c_oflag |= (OPOST | ONLCR); + tio.c_iflag |= ICRNL; + tcsetattr(*amaster, TCSANOW, &tio); + } + + return (0); + } + return (-1); +#endif +} + +#endif /* !defined(HAVE_OPENPTY) */ + diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-snprintf.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-snprintf.c new file mode 100644 index 0000000000..e4d8a439a4 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-snprintf.c @@ -0,0 +1,652 @@ +/* + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell (papowell@astart.com) + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions + */ + +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + * + * More Recently: + * Brandon Long 9/15/96 for mutt 0.43 + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything + * from the normal C string format, at least as far as I can tell from + * the Solaris 2.5 printf(3S) man page. + * + * Brandon Long 10/22/97 for mutt 0.87.1 + * Ok, added some minimal floating point support, which means this + * probably requires libm on most operating systems. Don't yet + * support the exponent (e,E) and sigfig (g,G). Also, fmtint() + * was pretty badly broken, it just wasn't being exercised in ways + * which showed it, so that's been fixed. Also, formated the code + * to mutt conventions, and removed dead code left over from the + * original. Also, there is now a builtin-test, just compile with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm + * and run snprintf for results. + * + * Thomas Roessler 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins 03/05/98 for mutt 0.90.8 + * The original code assumed that both snprintf() and vsnprintf() were + * missing. Some systems only have snprintf() but not vsnprintf(), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + * Ben Lindstrom 09/27/00 for OpenSSH + * Welcome to the world of %lld and %qd support. With other + * long long support. This is needed for sftp-server to work + * right. + * + * Ben Lindstrom 02/12/01 for OpenSSH + * Removed all hint of VARARGS stuff and banished it to the void, + * and did a bit of KNF style work to make things a bit more + * acceptable. Consider stealing from mutt or enlightenment. + **************************************************************/ + +#include "includes.h" + +RCSID("$Id: bsd-snprintf.c,v 1.7 2003/05/18 14:13:39 djm Exp $"); + +#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */ +# undef HAVE_SNPRINTF +# undef HAVE_VSNPRINTF +#endif + +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) + +static void +dopr(char *buffer, size_t maxlen, const char *format, va_list args); + +static void +fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, + int min, int max); + +static void +fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, + int min, int max, int flags); + +static void +fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, + int min, int max, int flags); + +static void +dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); + +/* + * dopr(): poor man's version of doprintf + */ + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) + +/* Conversion Flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LDOUBLE 3 +#define DP_C_LONG_LONG 4 + +#define char_to_int(p) (p - '0') +#define abs_val(p) (p < 0 ? -p : p) + + +static void +dopr(char *buffer, size_t maxlen, const char *format, va_list args) +{ + char *strvalue, ch; + long value; + long double fvalue; + int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0; + size_t currlen = 0; + + ch = *format++; + + while (state != DP_S_DONE) { + if ((ch == '\0') || (currlen >= maxlen)) + state = DP_S_DONE; + + switch(state) { + case DP_S_DEFAULT: + if (ch == '%') + state = DP_S_FLAGS; + else + dopr_outch(buffer, &currlen, maxlen, ch); + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (isdigit((unsigned char)ch)) { + min = 10 * min + char_to_int (ch); + ch = *format++; + } else if (ch == '*') { + min = va_arg (args, int); + ch = *format++; + state = DP_S_DOT; + } else + state = DP_S_DOT; + break; + case DP_S_DOT: + if (ch == '.') { + state = DP_S_MAX; + ch = *format++; + } else + state = DP_S_MOD; + break; + case DP_S_MAX: + if (isdigit((unsigned char)ch)) { + if (max < 0) + max = 0; + max = 10 * max + char_to_int(ch); + ch = *format++; + } else if (ch == '*') { + max = va_arg (args, int); + ch = *format++; + state = DP_S_MOD; + } else + state = DP_S_MOD; + break; + case DP_S_MOD: + switch (ch) { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + cflags = DP_C_LONG; + ch = *format++; + if (ch == 'l') { + cflags = DP_C_LONG_LONG; + ch = *format++; + } + break; + case 'q': + cflags = DP_C_LONG_LONG; + ch = *format++; + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) { + case 'd': + case 'i': + if (cflags == DP_C_SHORT) + value = va_arg(args, int); + else if (cflags == DP_C_LONG) + value = va_arg(args, long int); + else if (cflags == DP_C_LONG_LONG) + value = va_arg (args, long long); + else + value = va_arg (args, int); + fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'o': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg(args, unsigned int); + else if (cflags == DP_C_LONG) + value = va_arg(args, unsigned long int); + else if (cflags == DP_C_LONG_LONG) + value = va_arg(args, unsigned long long); + else + value = va_arg(args, unsigned int); + fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags); + break; + case 'u': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg(args, unsigned int); + else if (cflags == DP_C_LONG) + value = va_arg(args, unsigned long int); + else if (cflags == DP_C_LONG_LONG) + value = va_arg(args, unsigned long long); + else + value = va_arg(args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'X': + flags |= DP_F_UP; + case 'x': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg(args, unsigned int); + else if (cflags == DP_C_LONG) + value = va_arg(args, unsigned long int); + else if (cflags == DP_C_LONG_LONG) + value = va_arg(args, unsigned long long); + else + value = va_arg(args, unsigned int); + fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags); + break; + case 'f': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, long double); + else + fvalue = va_arg(args, double); + /* um, floating point? */ + fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'E': + flags |= DP_F_UP; + case 'e': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, long double); + else + fvalue = va_arg(args, double); + break; + case 'G': + flags |= DP_F_UP; + case 'g': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, long double); + else + fvalue = va_arg(args, double); + break; + case 'c': + dopr_outch(buffer, &currlen, maxlen, va_arg(args, int)); + break; + case 's': + strvalue = va_arg(args, char *); + if (max < 0) + max = maxlen; /* ie, no max */ + fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max); + break; + case 'p': + strvalue = va_arg(args, void *); + fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + break; + case 'n': + if (cflags == DP_C_SHORT) { + short int *num; + num = va_arg(args, short int *); + *num = currlen; + } else if (cflags == DP_C_LONG) { + long int *num; + num = va_arg(args, long int *); + *num = currlen; + } else if (cflags == DP_C_LONG_LONG) { + long long *num; + num = va_arg(args, long long *); + *num = currlen; + } else { + int *num; + num = va_arg(args, int *); + *num = currlen; + } + break; + case '%': + dopr_outch(buffer, &currlen, maxlen, ch); + break; + case 'w': /* not supported yet, treat as next char */ + ch = *format++; + break; + default: /* Unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: /* hmm? */ + break; /* some picky compilers need this */ + } + } + if (currlen < maxlen - 1) + buffer[currlen] = '\0'; + else + buffer[maxlen - 1] = '\0'; +} + +static void +fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max) +{ + int cnt = 0, padlen, strln; /* amount to pad */ + + if (value == 0) + value = ""; + + for (strln = 0; value[strln]; ++strln); /* strlen */ + padlen = min - strln; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justify */ + + while ((padlen > 0) && (cnt < max)) { + dopr_outch(buffer, currlen, maxlen, ' '); + --padlen; + ++cnt; + } + while (*value && (cnt < max)) { + dopr_outch(buffer, currlen, maxlen, *value++); + ++cnt; + } + while ((padlen < 0) && (cnt < max)) { + dopr_outch(buffer, currlen, maxlen, ' '); + ++padlen; + ++cnt; + } +} + +/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ + +static void +fmtint(char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags) +{ + unsigned long uvalue; + char convert[20]; + int signvalue = 0, place = 0, caps = 0; + int spadlen = 0; /* amount to space pad */ + int zpadlen = 0; /* amount to zero pad */ + + if (max < 0) + max = 0; + + uvalue = value; + + if (!(flags & DP_F_UNSIGNED)) { + if (value < 0) { + signvalue = '-'; + uvalue = -value; + } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + } + + if (flags & DP_F_UP) + caps = 1; /* Should characters be upper case? */ + do { + convert[place++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [uvalue % (unsigned)base]; + uvalue = (uvalue / (unsigned)base ); + } while (uvalue && (place < 20)); + if (place == 20) + place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); + if (zpadlen < 0) + zpadlen = 0; + if (spadlen < 0) + spadlen = 0; + if (flags & DP_F_ZERO) { + zpadlen = MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; /* Left Justifty */ + + /* Spaces */ + while (spadlen > 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + --spadlen; + } + + /* Sign */ + if (signvalue) + dopr_outch(buffer, currlen, maxlen, signvalue); + + /* Zeros */ + if (zpadlen > 0) { + while (zpadlen > 0) { + dopr_outch(buffer, currlen, maxlen, '0'); + --zpadlen; + } + } + + /* Digits */ + while (place > 0) + dopr_outch(buffer, currlen, maxlen, convert[--place]); + + /* Left Justified spaces */ + while (spadlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++spadlen; + } +} + +static long double +pow10(int exp) +{ + long double result = 1; + + while (exp) { + result *= 10; + exp--; + } + + return result; +} + +static long +round(long double value) +{ + long intpart = value; + + value -= intpart; + if (value >= 0.5) + intpart++; + + return intpart; +} + +static void +fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, + int min, int max, int flags) +{ + char iconvert[20], fconvert[20]; + int signvalue = 0, iplace = 0, fplace = 0; + int padlen = 0; /* amount to pad */ + int zpadlen = 0, caps = 0; + long intpart, fracpart; + long double ufvalue; + + /* + * AIX manpage says the default is 0, but Solaris says the default + * is 6, and sprintf on AIX defaults to 6 + */ + if (max < 0) + max = 6; + + ufvalue = abs_val(fvalue); + + if (fvalue < 0) + signvalue = '-'; + else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + + intpart = ufvalue; + + /* + * Sorry, we only support 9 digits past the decimal because of our + * conversion method + */ + if (max > 9) + max = 9; + + /* We "cheat" by converting the fractional part to integer by + * multiplying by a factor of 10 + */ + fracpart = round((pow10 (max)) * (ufvalue - intpart)); + + if (fracpart >= pow10 (max)) { + intpart++; + fracpart -= pow10 (max); + } + + /* Convert integer part */ + do { + iconvert[iplace++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [intpart % 10]; + intpart = (intpart / 10); + } while(intpart && (iplace < 20)); + if (iplace == 20) + iplace--; + iconvert[iplace] = 0; + + /* Convert fractional part */ + do { + fconvert[fplace++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [fracpart % 10]; + fracpart = (fracpart / 10); + } while(fracpart && (fplace < 20)); + if (fplace == 20) + fplace--; + fconvert[fplace] = 0; + + /* -1 for decimal point, another -1 if we are printing a sign */ + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + zpadlen = max - fplace; + if (zpadlen < 0) + zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justifty */ + + if ((flags & DP_F_ZERO) && (padlen > 0)) { + if (signvalue) { + dopr_outch(buffer, currlen, maxlen, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) { + dopr_outch(buffer, currlen, maxlen, '0'); + --padlen; + } + } + while (padlen > 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + --padlen; + } + if (signvalue) + dopr_outch(buffer, currlen, maxlen, signvalue); + + while (iplace > 0) + dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); + + /* + * Decimal point. This should probably use locale to find the + * correct char to print out. + */ + dopr_outch(buffer, currlen, maxlen, '.'); + + while (fplace > 0) + dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); + + while (zpadlen > 0) { + dopr_outch(buffer, currlen, maxlen, '0'); + --zpadlen; + } + + while (padlen < 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + ++padlen; + } +} + +static void +dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) +{ + if (*currlen < maxlen) + buffer[(*currlen)++] = c; +} +#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ + +#ifndef HAVE_VSNPRINTF +int +vsnprintf(char *str, size_t count, const char *fmt, va_list args) +{ + str[0] = 0; + dopr(str, count, fmt, args); + + return(strlen(str)); +} +#endif /* !HAVE_VSNPRINTF */ + +#ifndef HAVE_SNPRINTF +int +snprintf(char *str,size_t count,const char *fmt,...) +{ + va_list ap; + + va_start(ap, fmt); + (void) vsnprintf(str, count, fmt, ap); + va_end(ap); + + return(strlen(str)); +} + +#endif /* !HAVE_SNPRINTF */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-waitpid.c b/crypto/openssh-3.9p1/openbsd-compat/bsd-waitpid.c new file mode 100644 index 0000000000..93c9ec35ee --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-waitpid.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000 Ben Lindstrom. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +RCSID("$Id: bsd-waitpid.c,v 1.5 2003/06/01 03:23:57 mouring Exp $"); + +#ifndef HAVE_WAITPID +#include +#include +#include "bsd-waitpid.h" + +pid_t +waitpid(int pid, int *stat_loc, int options) +{ + union wait statusp; + pid_t wait_pid; + + if (pid <= 0) { + if (pid != -1) { + errno = EINVAL; + return (-1); + } + /* wait4() wants pid=0 for indiscriminate wait. */ + pid = 0; + } + wait_pid = wait4(pid, &statusp, options, NULL); + if (stat_loc) + *stat_loc = (int) statusp.w_status; + + return (wait_pid); +} + +#endif /* !HAVE_WAITPID */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/bsd-waitpid.h b/crypto/openssh-3.9p1/openbsd-compat/bsd-waitpid.h new file mode 100644 index 0000000000..2d853db616 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/bsd-waitpid.h @@ -0,0 +1,51 @@ +/* $Id: bsd-waitpid.h,v 1.5 2003/08/29 16:59:52 mouring Exp $ */ + +/* + * Copyright (c) 2000 Ben Lindstrom. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _BSD_WAITPID_H +#define _BSD_WAITPID_H + +#ifndef HAVE_WAITPID +/* Clean out any potental issues */ +#undef WIFEXITED +#undef WIFSTOPPED +#undef WIFSIGNALED + +/* Define required functions to mimic a POSIX look and feel */ +#define _W_INT(w) (*(int*)&(w)) /* convert union wait to int */ +#define WIFEXITED(w) (!((_W_INT(w)) & 0377)) +#define WIFSTOPPED(w) ((_W_INT(w)) & 0100) +#define WIFSIGNALED(w) (!WIFEXITED(w) && !WIFSTOPPED(w)) +#define WEXITSTATUS(w) (int)(WIFEXITED(w) ? ((_W_INT(w) >> 8) & 0377) : -1) +#define WTERMSIG(w) (int)(WIFSIGNALED(w) ? (_W_INT(w) & 0177) : -1) +#define WCOREFLAG 0x80 +#define WCOREDUMP(w) ((_W_INT(w)) & WCOREFLAG) + +/* Prototype */ +pid_t waitpid(int, int *, int); + +#endif /* !HAVE_WAITPID */ +#endif /* _BSD_WAITPID_H */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/daemon.c b/crypto/openssh-3.9p1/openbsd-compat/daemon.c new file mode 100644 index 0000000000..c0be5fff9d --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/daemon.c @@ -0,0 +1,81 @@ +/* OPENBSD ORIGINAL: lib/libc/gen/daemon.c */ + +/*- + * Copyright (c) 1990, 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. 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. + */ + +#include "includes.h" + +#ifndef HAVE_DAEMON + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$OpenBSD: daemon.c,v 1.5 2003/07/15 17:32:41 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +int +daemon(int nochdir, int noclose) +{ + int fd; + + switch (fork()) { + case -1: + return (-1); + case 0: +#ifdef HAVE_CYGWIN + register_9x_service(); +#endif + break; + default: +#ifdef HAVE_CYGWIN + /* + * This sleep avoids a race condition which kills the + * child process if parent is started by a NT/W2K service. + */ + sleep(1); +#endif + _exit(0); + } + + if (setsid() == -1) + return (-1); + + if (!nochdir) + (void)chdir("/"); + + if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); + if (fd > 2) + (void)close (fd); + } + return (0); +} + +#endif /* !HAVE_DAEMON */ + diff --git a/crypto/openssh-3.9p1/openbsd-compat/dirname.c b/crypto/openssh-3.9p1/openbsd-compat/dirname.c new file mode 100644 index 0000000000..25ab34dd68 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/dirname.c @@ -0,0 +1,70 @@ +/* OPENBSD ORIGINAL: lib/libc/gen/dirname.c */ + +/* $OpenBSD: dirname.c,v 1.10 2003/06/17 21:56:23 millert Exp $ */ + +/* + * Copyright (c) 1997 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" +#ifndef HAVE_DIRNAME + +#ifndef lint +static char rcsid[] = "$OpenBSD: dirname.c,v 1.10 2003/06/17 21:56:23 millert Exp $"; +#endif /* not lint */ + +#include +#include +#include + +char * +dirname(const char *path) +{ + static char bname[MAXPATHLEN]; + register const char *endp; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + (void)strlcpy(bname, ".", sizeof bname); + return(bname); + } + + /* Strip trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* Find the start of the dir */ + while (endp > path && *endp != '/') + endp--; + + /* Either the dir is "/" or there are no slashes */ + if (endp == path) { + (void)strlcpy(bname, *endp == '/' ? "/" : ".", sizeof bname); + return(bname); + } else { + do { + endp--; + } while (endp > path && *endp == '/'); + } + + if (endp - path + 2 > sizeof(bname)) { + errno = ENAMETOOLONG; + return(NULL); + } + strlcpy(bname, path, endp - path + 2); + return(bname); +} +#endif diff --git a/crypto/openssh-3.9p1/openbsd-compat/fake-rfc2553.c b/crypto/openssh-3.9p1/openbsd-compat/fake-rfc2553.c new file mode 100644 index 0000000000..0186b53006 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/fake-rfc2553.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2000-2003 Damien Miller. All rights reserved. + * Copyright (C) 1999 WIDE Project. 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. + */ + +/* + * Pseudo-implementation of RFC2553 name / address resolution functions + * + * But these functions are not implemented correctly. The minimum subset + * is implemented for ssh use only. For example, this routine assumes + * that ai_family is AF_INET. Don't use it for another purpose. + */ + +#include "includes.h" + +RCSID("$Id: fake-rfc2553.c,v 1.5 2003/09/22 02:08:23 dtucker Exp $"); + +#ifndef HAVE_GETNAMEINFO +int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, + size_t hostlen, char *serv, size_t servlen, int flags) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + struct hostent *hp; + char tmpserv[16]; + + if (serv != NULL) { + snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port)); + if (strlcpy(serv, tmpserv, servlen) >= servlen) + return (EAI_MEMORY); + } + + if (host != NULL) { + if (flags & NI_NUMERICHOST) { + if (strlcpy(host, inet_ntoa(sin->sin_addr), + hostlen) >= hostlen) + return (EAI_MEMORY); + else + return (0); + } else { + hp = gethostbyaddr((char *)&sin->sin_addr, + sizeof(struct in_addr), AF_INET); + if (hp == NULL) + return (EAI_NODATA); + + if (strlcpy(host, hp->h_name, hostlen) >= hostlen) + return (EAI_MEMORY); + else + return (0); + } + } + return (0); +} +#endif /* !HAVE_GETNAMEINFO */ + +#ifndef HAVE_GAI_STRERROR +#ifdef HAVE_CONST_GAI_STRERROR_PROTO +const char * +#else +char * +#endif +gai_strerror(int err) +{ + switch (err) { + case EAI_NODATA: + return ("no address associated with name"); + case EAI_MEMORY: + return ("memory allocation failure."); + case EAI_NONAME: + return ("nodename nor servname provided, or not known"); + default: + return ("unknown/invalid error."); + } +} +#endif /* !HAVE_GAI_STRERROR */ + +#ifndef HAVE_FREEADDRINFO +void +freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + + for(; ai != NULL;) { + next = ai->ai_next; + free(ai); + ai = next; + } +} +#endif /* !HAVE_FREEADDRINFO */ + +#ifndef HAVE_GETADDRINFO +static struct +addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints) +{ + struct addrinfo *ai; + + ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in)); + if (ai == NULL) + return (NULL); + + memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in)); + + ai->ai_addr = (struct sockaddr *)(ai + 1); + /* XXX -- ssh doesn't use sa_len */ + ai->ai_addrlen = sizeof(struct sockaddr_in); + ai->ai_addr->sa_family = ai->ai_family = AF_INET; + + ((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port; + ((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr; + + /* XXX: the following is not generally correct, but does what we want */ + if (hints->ai_socktype) + ai->ai_socktype = hints->ai_socktype; + else + ai->ai_socktype = SOCK_STREAM; + + if (hints->ai_protocol) + ai->ai_protocol = hints->ai_protocol; + + return (ai); +} + +int +getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + struct hostent *hp; + struct servent *sp; + struct in_addr in; + int i; + long int port; + u_long addr; + + port = 0; + if (servname != NULL) { + char *cp; + + port = strtol(servname, &cp, 10); + if (port > 0 && port <= 65535 && *cp == '\0') + port = htons(port); + else if ((sp = getservbyname(servname, NULL)) != NULL) + port = sp->s_port; + else + port = 0; + } + + if (hints && hints->ai_flags & AI_PASSIVE) { + addr = htonl(0x00000000); + if (hostname && inet_aton(hostname, &in) != 0) + addr = in.s_addr; + *res = malloc_ai(port, addr, hints); + if (*res == NULL) + return (EAI_MEMORY); + return (0); + } + + if (!hostname) { + *res = malloc_ai(port, htonl(0x7f000001), hints); + if (*res == NULL) + return (EAI_MEMORY); + return (0); + } + + if (inet_aton(hostname, &in)) { + *res = malloc_ai(port, in.s_addr, hints); + if (*res == NULL) + return (EAI_MEMORY); + return (0); + } + + /* Don't try DNS if AI_NUMERICHOST is set */ + if (hints && hints->ai_flags & AI_NUMERICHOST) + return (EAI_NONAME); + + hp = gethostbyname(hostname); + if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { + struct addrinfo *cur, *prev; + + cur = prev = *res = NULL; + for (i = 0; hp->h_addr_list[i]; i++) { + struct in_addr *in = (struct in_addr *)hp->h_addr_list[i]; + + cur = malloc_ai(port, in->s_addr, hints); + if (cur == NULL) { + if (*res != NULL) + freeaddrinfo(*res); + return (EAI_MEMORY); + } + if (prev) + prev->ai_next = cur; + else + *res = cur; + + prev = cur; + } + return (0); + } + + return (EAI_NODATA); +} +#endif /* !HAVE_GETADDRINFO */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/fake-rfc2553.h b/crypto/openssh-3.9p1/openbsd-compat/fake-rfc2553.h new file mode 100644 index 0000000000..baea070380 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/fake-rfc2553.h @@ -0,0 +1,161 @@ +/* $Id: fake-rfc2553.h,v 1.9 2004/03/10 10:06:33 dtucker Exp $ */ + +/* + * Copyright (C) 2000-2003 Damien Miller. All rights reserved. + * Copyright (C) 1999 WIDE Project. 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. Neither the name of the project 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 PROJECT 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 PROJECT 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. + */ + +/* + * Pseudo-implementation of RFC2553 name / address resolution functions + * + * But these functions are not implemented correctly. The minimum subset + * is implemented for ssh use only. For example, this routine assumes + * that ai_family is AF_INET. Don't use it for another purpose. + */ + +#ifndef _FAKE_RFC2553_H +#define _FAKE_RFC2553_H + +#include "includes.h" +#include "sys/types.h" + +/* + * First, socket and INET6 related definitions + */ +#ifndef HAVE_STRUCT_SOCKADDR_STORAGE +# define _SS_MAXSIZE 128 /* Implementation specific max size */ +# define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr)) +struct sockaddr_storage { + struct sockaddr ss_sa; + char __ss_pad2[_SS_PADSIZE]; +}; +# define ss_family ss_sa.sa_family +#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */ + +#ifndef IN6_IS_ADDR_LOOPBACK +# define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *)(a))[0] == 0 && ((u_int32_t *)(a))[1] == 0 && \ + ((u_int32_t *)(a))[2] == 0 && ((u_int32_t *)(a))[3] == htonl(1)) +#endif /* !IN6_IS_ADDR_LOOPBACK */ + +#ifndef HAVE_STRUCT_IN6_ADDR +struct in6_addr { + u_int8_t s6_addr[16]; +}; +#endif /* !HAVE_STRUCT_IN6_ADDR */ + +#ifndef HAVE_STRUCT_SOCKADDR_IN6 +struct sockaddr_in6 { + unsigned short sin6_family; + u_int16_t sin6_port; + u_int32_t sin6_flowinfo; + struct in6_addr sin6_addr; +}; +#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */ + +#ifndef AF_INET6 +/* Define it to something that should never appear */ +#define AF_INET6 AF_MAX +#endif + +/* + * Next, RFC2553 name / address resolution API + */ + +#ifndef NI_NUMERICHOST +# define NI_NUMERICHOST (1) +#endif +#ifndef NI_NAMEREQD +# define NI_NAMEREQD (1<<1) +#endif +#ifndef NI_NUMERICSERV +# define NI_NUMERICSERV (1<<2) +#endif + +#ifndef AI_PASSIVE +# define AI_PASSIVE (1) +#endif +#ifndef AI_CANONNAME +# define AI_CANONNAME (1<<1) +#endif +#ifndef AI_NUMERICHOST +# define AI_NUMERICHOST (1<<2) +#endif + +#ifndef NI_MAXSERV +# define NI_MAXSERV 32 +#endif /* !NI_MAXSERV */ +#ifndef NI_MAXHOST +# define NI_MAXHOST 1025 +#endif /* !NI_MAXHOST */ + +#ifndef EAI_NODATA +# define EAI_NODATA 1 +# define EAI_MEMORY 2 +# define EAI_NONAME 3 +#endif + +#ifndef HAVE_STRUCT_ADDRINFO +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif /* !HAVE_STRUCT_ADDRINFO */ + +#ifndef HAVE_GETADDRINFO +#ifdef getaddrinfo +# undef getaddrinfo +#endif +#define getaddrinfo(a,b,c,d) (ssh_getaddrinfo(a,b,c,d)) +int getaddrinfo(const char *, const char *, + const struct addrinfo *, struct addrinfo **); +#endif /* !HAVE_GETADDRINFO */ + +#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO) +#define gai_strerror(a) (ssh_gai_strerror(a)) +char *gai_strerror(int); +#endif /* !HAVE_GAI_STRERROR */ + +#ifndef HAVE_FREEADDRINFO +#define freeaddrinfo(a) (ssh_freeaddrinfo(a)) +void freeaddrinfo(struct addrinfo *); +#endif /* !HAVE_FREEADDRINFO */ + +#ifndef HAVE_GETNAMEINFO +#define getnameinfo(a,b,c,d,e,f,g) (ssh_getnameinfo(a,b,c,d,e,f,g)) +int getnameinfo(const struct sockaddr *, size_t, char *, size_t, + char *, size_t, int); +#endif /* !HAVE_GETNAMEINFO */ + +#endif /* !_FAKE_RFC2553_H */ + diff --git a/crypto/openssh-3.9p1/openbsd-compat/getcwd.c b/crypto/openssh-3.9p1/openbsd-compat/getcwd.c new file mode 100644 index 0000000000..19be59172e --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/getcwd.c @@ -0,0 +1,242 @@ +/* OPENBSD ORIGINAL: lib/libc/gen/getcwd.c */ + +/* + * Copyright (c) 1989, 1991, 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. 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. + */ + +#include "includes.h" + +#if !defined(HAVE_GETCWD) + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$OpenBSD: getcwd.c,v 1.9 2003/06/11 21:03:10 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "includes.h" + +#define ISDOT(dp) \ + (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ + (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) + +char * +getcwd(char *pt, size_t size) +{ + register struct dirent *dp; + register DIR *dir = NULL; + register dev_t dev; + register ino_t ino; + register int first; + register char *bpt, *bup; + struct stat s; + dev_t root_dev; + ino_t root_ino; + size_t ptsize, upsize; + int save_errno; + char *ept, *eup, *up; + + /* + * If no buffer specified by the user, allocate one as necessary. + * If a buffer is specified, the size has to be non-zero. The path + * is built from the end of the buffer backwards. + */ + if (pt) { + ptsize = 0; + if (!size) { + errno = EINVAL; + return (NULL); + } + ept = pt + size; + } else { + if ((pt = malloc(ptsize = 1024 - 4)) == NULL) + return (NULL); + ept = pt + ptsize; + } + bpt = ept - 1; + *bpt = '\0'; + + /* + * Allocate bytes (1024 - malloc space) for the string of "../"'s. + * Should always be enough (it's 340 levels). If it's not, allocate + * as necessary. Special * case the first stat, it's ".", not "..". + */ + if ((up = malloc(upsize = 1024 - 4)) == NULL) + goto err; + eup = up + MAXPATHLEN; + bup = up; + up[0] = '.'; + up[1] = '\0'; + + /* Save root values, so know when to stop. */ + if (stat("/", &s)) + goto err; + root_dev = s.st_dev; + root_ino = s.st_ino; + + errno = 0; /* XXX readdir has no error return. */ + + for (first = 1;; first = 0) { + /* Stat the current level. */ + if (lstat(up, &s)) + goto err; + + /* Save current node values. */ + ino = s.st_ino; + dev = s.st_dev; + + /* Check for reaching root. */ + if (root_dev == dev && root_ino == ino) { + *--bpt = '/'; + /* + * It's unclear that it's a requirement to copy the + * path to the beginning of the buffer, but it's always + * been that way and stuff would probably break. + */ + memmove(pt, bpt, ept - bpt); + free(up); + return (pt); + } + + /* + * Build pointer to the parent directory, allocating memory + * as necessary. Max length is 3 for "../", the largest + * possible component name, plus a trailing NUL. + */ + if (bup + 3 + MAXNAMLEN + 1 >= eup) { + char *nup; + + if ((nup = realloc(up, upsize *= 2)) == NULL) + goto err; + up = nup; + bup = up; + eup = up + upsize; + } + *bup++ = '.'; + *bup++ = '.'; + *bup = '\0'; + + /* Open and stat parent directory. + * RACE?? - replaced fstat(dirfd(dir), &s) w/ lstat(up,&s) + */ + if (!(dir = opendir(up)) || lstat(up,&s)) + goto err; + + /* Add trailing slash for next directory. */ + *bup++ = '/'; + + /* + * If it's a mount point, have to stat each element because + * the inode number in the directory is for the entry in the + * parent directory, not the inode number of the mounted file. + */ + save_errno = 0; + if (s.st_dev == dev) { + for (;;) { + if (!(dp = readdir(dir))) + goto notfound; + if (dp->d_fileno == ino) + break; + } + } else + for (;;) { + if (!(dp = readdir(dir))) + goto notfound; + if (ISDOT(dp)) + continue; + memmove(bup, dp->d_name, dp->d_namlen + 1); + + /* Save the first error for later. */ + if (lstat(up, &s)) { + if (!save_errno) + save_errno = errno; + errno = 0; + continue; + } + if (s.st_dev == dev && s.st_ino == ino) + break; + } + + /* + * Check for length of the current name, preceding slash, + * leading slash. + */ + if (bpt - pt < dp->d_namlen + (first ? 1 : 2)) { + size_t len, off; + char *npt; + + if (!ptsize) { + errno = ERANGE; + goto err; + } + off = bpt - pt; + len = ept - bpt; + if ((npt = realloc(pt, ptsize *= 2)) == NULL) + goto err; + pt = npt; + bpt = pt + off; + ept = pt + ptsize; + memmove(ept - len, bpt, len); + bpt = ept - len; + } + if (!first) + *--bpt = '/'; + bpt -= dp->d_namlen; + memmove(bpt, dp->d_name, dp->d_namlen); + (void)closedir(dir); + + /* Truncate any file name. */ + *bup = '\0'; + } + +notfound: + /* + * If readdir set errno, use it, not any saved error; otherwise, + * didn't find the current directory in its parent directory, set + * errno to ENOENT. + */ + if (!errno) + errno = save_errno ? save_errno : ENOENT; + /* FALLTHROUGH */ +err: + if (ptsize) + free(pt); + if (up) + free(up); + if (dir) + (void)closedir(dir); + return (NULL); +} + +#endif /* !defined(HAVE_GETCWD) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/getgrouplist.c b/crypto/openssh-3.9p1/openbsd-compat/getgrouplist.c new file mode 100644 index 0000000000..59c164f445 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/getgrouplist.c @@ -0,0 +1,102 @@ +/* OPENBSD ORIGINAL: lib/libc/gen/getgrouplist.c */ + +/* + * Copyright (c) 1991, 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. 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. + */ + +#include "includes.h" + +#ifndef HAVE_GETGROUPLIST + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$OpenBSD: getgrouplist.c,v 1.9 2003/06/25 21:16:47 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * get credential + */ +#include +#include +#include +#include + +int +getgrouplist(uname, agroup, groups, grpcnt) + const char *uname; + gid_t agroup; + register gid_t *groups; + int *grpcnt; +{ + register struct group *grp; + register int i, ngroups; + int ret, maxgroups; + int bail; + + ret = 0; + ngroups = 0; + maxgroups = *grpcnt; + + /* + * install primary group + */ + if (ngroups >= maxgroups) { + *grpcnt = ngroups; + return (-1); + } + groups[ngroups++] = agroup; + + /* + * Scan the group file to find additional groups. + */ + setgrent(); + while ((grp = getgrent())) { + if (grp->gr_gid == agroup) + continue; + for (bail = 0, i = 0; bail == 0 && i < ngroups; i++) + if (groups[i] == grp->gr_gid) + bail = 1; + if (bail) + continue; + for (i = 0; grp->gr_mem[i]; i++) { + if (!strcmp(grp->gr_mem[i], uname)) { + if (ngroups >= maxgroups) { + ret = -1; + goto out; + } + groups[ngroups++] = grp->gr_gid; + break; + } + } + } +out: + endgrent(); + *grpcnt = ngroups; + return (ret); +} + +#endif /* HAVE_GETGROUPLIST */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/getopt.c b/crypto/openssh-3.9p1/openbsd-compat/getopt.c new file mode 100644 index 0000000000..f5ee6778da --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/getopt.c @@ -0,0 +1,123 @@ +/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */ + +/* + * Copyright (c) 1987, 1993, 1994 + * 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. 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. + */ + +#include "includes.h" +#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: getopt.c,v 1.5 2003/06/02 20:18:37 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +int BSDopterr = 1, /* if error message should be printed */ + BSDoptind = 1, /* index into parent argv vector */ + BSDoptopt, /* character checked for validity */ + BSDoptreset; /* reset getopt */ +char *BSDoptarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +BSDgetopt(nargc, nargv, ostr) + int nargc; + char * const *nargv; + const char *ostr; +{ + extern char *__progname; + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (ostr == NULL) + return (-1); + + if (BSDoptreset || !*place) { /* update scanning pointer */ + BSDoptreset = 0; + if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') { + place = EMSG; + return (-1); + } + if (place[1] && *++place == '-') { /* found "--" */ + ++BSDoptind; + place = EMSG; + return (-1); + } + } /* option letter okay? */ + if ((BSDoptopt = (int)*place++) == (int)':' || + !(oli = strchr(ostr, BSDoptopt))) { + /* + * if the user didn't specify '-' as an option, + * assume it means -1. + */ + if (BSDoptopt == (int)'-') + return (-1); + if (!*place) + ++BSDoptind; + if (BSDopterr && *ostr != ':') + (void)fprintf(stderr, + "%s: illegal option -- %c\n", __progname, BSDoptopt); + return (BADCH); + } + if (*++oli != ':') { /* don't need argument */ + BSDoptarg = NULL; + if (!*place) + ++BSDoptind; + } + else { /* need an argument */ + if (*place) /* no white space */ + BSDoptarg = place; + else if (nargc <= ++BSDoptind) { /* no arg */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (BSDopterr) + (void)fprintf(stderr, + "%s: option requires an argument -- %c\n", + __progname, BSDoptopt); + return (BADCH); + } + else /* white space */ + BSDoptarg = nargv[BSDoptind]; + place = EMSG; + ++BSDoptind; + } + return (BSDoptopt); /* dump back option letter */ +} + +#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/getrrsetbyname.c b/crypto/openssh-3.9p1/openbsd-compat/getrrsetbyname.c new file mode 100644 index 0000000000..660427c1f0 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/getrrsetbyname.c @@ -0,0 +1,581 @@ +/* OPENBSD ORIGINAL: lib/libc/net/getrrsetbyname.c */ + +/* $OpenBSD: getrrsetbyname.c,v 1.7 2003/03/07 07:34:14 itojun Exp $ */ + +/* + * Copyright (c) 2001 Jakob Schlyter. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#ifndef HAVE_GETRRSETBYNAME + +#include "getrrsetbyname.h" + +#define ANSWER_BUFFER_SIZE 1024*64 + +#if defined(HAVE_DECL_H_ERRNO) && !HAVE_DECL_H_ERRNO +extern int h_errno; +#endif + +struct dns_query { + char *name; + u_int16_t type; + u_int16_t class; + struct dns_query *next; +}; + +struct dns_rr { + char *name; + u_int16_t type; + u_int16_t class; + u_int16_t ttl; + u_int16_t size; + void *rdata; + struct dns_rr *next; +}; + +struct dns_response { + HEADER header; + struct dns_query *query; + struct dns_rr *answer; + struct dns_rr *authority; + struct dns_rr *additional; +}; + +static struct dns_response *parse_dns_response(const u_char *, int); +static struct dns_query *parse_dns_qsection(const u_char *, int, + const u_char **, int); +static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **, + int); + +static void free_dns_query(struct dns_query *); +static void free_dns_rr(struct dns_rr *); +static void free_dns_response(struct dns_response *); + +static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t); + +/* + * Inline versions of get/put short/long. Pointer is advanced. + * + * These macros demonstrate the property of C whereby it can be + * portable or it can be elegant but rarely both. + */ + +#ifndef INT32SZ +# define INT32SZ 4 +#endif +#ifndef INT16SZ +# define INT16SZ 2 +#endif + +#ifndef GETSHORT +#define GETSHORT(s, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (s) = ((u_int16_t)t_cp[0] << 8) \ + | ((u_int16_t)t_cp[1]) \ + ; \ + (cp) += INT16SZ; \ +} +#endif + +#ifndef GETLONG +#define GETLONG(l, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (l) = ((u_int32_t)t_cp[0] << 24) \ + | ((u_int32_t)t_cp[1] << 16) \ + | ((u_int32_t)t_cp[2] << 8) \ + | ((u_int32_t)t_cp[3]) \ + ; \ + (cp) += INT32SZ; \ +} +#endif + +/* + * Routines to insert/extract short/long's. + */ + +#ifndef HAVE__GETSHORT +static u_int16_t +_getshort(msgp) + register const u_char *msgp; +{ + register u_int16_t u; + + GETSHORT(u, msgp); + return (u); +} +#endif + +#ifndef HAVE__GETLONG +static u_int32_t +_getlong(msgp) + register const u_char *msgp; +{ + register u_int32_t u; + + GETLONG(u, msgp); + return (u); +} +#endif + +int +getrrsetbyname(const char *hostname, unsigned int rdclass, + unsigned int rdtype, unsigned int flags, + struct rrsetinfo **res) +{ + int result; + struct rrsetinfo *rrset = NULL; + struct dns_response *response; + struct dns_rr *rr; + struct rdatainfo *rdata; + int length; + unsigned int index_ans, index_sig; + u_char answer[ANSWER_BUFFER_SIZE]; + + /* check for invalid class and type */ + if (rdclass > 0xffff || rdtype > 0xffff) { + result = ERRSET_INVAL; + goto fail; + } + + /* don't allow queries of class or type ANY */ + if (rdclass == 0xff || rdtype == 0xff) { + result = ERRSET_INVAL; + goto fail; + } + + /* don't allow flags yet, unimplemented */ + if (flags) { + result = ERRSET_INVAL; + goto fail; + } + + /* initialize resolver */ + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { + result = ERRSET_FAIL; + goto fail; + } + +#ifdef DEBUG + _res.options |= RES_DEBUG; +#endif /* DEBUG */ + +#ifdef RES_USE_DNSSEC + /* turn on DNSSEC if EDNS0 is configured */ + if (_res.options & RES_USE_EDNS0) + _res.options |= RES_USE_DNSSEC; +#endif /* RES_USE_DNSEC */ + + /* make query */ + length = res_query(hostname, (signed int) rdclass, (signed int) rdtype, + answer, sizeof(answer)); + if (length < 0) { + switch(h_errno) { + case HOST_NOT_FOUND: + result = ERRSET_NONAME; + goto fail; + case NO_DATA: + result = ERRSET_NODATA; + goto fail; + default: + result = ERRSET_FAIL; + goto fail; + } + } + + /* parse result */ + response = parse_dns_response(answer, length); + if (response == NULL) { + result = ERRSET_FAIL; + goto fail; + } + + if (response->header.qdcount != 1) { + result = ERRSET_FAIL; + goto fail; + } + + /* initialize rrset */ + rrset = calloc(1, sizeof(struct rrsetinfo)); + if (rrset == NULL) { + result = ERRSET_NOMEMORY; + goto fail; + } + rrset->rri_rdclass = response->query->class; + rrset->rri_rdtype = response->query->type; + rrset->rri_ttl = response->answer->ttl; + rrset->rri_nrdatas = response->header.ancount; + +#ifdef HAVE_HEADER_AD + /* check for authenticated data */ + if (response->header.ad == 1) + rrset->rri_flags |= RRSET_VALIDATED; +#endif + + /* copy name from answer section */ + length = strlen(response->answer->name); + rrset->rri_name = malloc(length + 1); + if (rrset->rri_name == NULL) { + result = ERRSET_NOMEMORY; + goto fail; + } + strlcpy(rrset->rri_name, response->answer->name, length + 1); + + /* count answers */ + rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass, + rrset->rri_rdtype); + rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass, + T_SIG); + + /* allocate memory for answers */ + rrset->rri_rdatas = calloc(rrset->rri_nrdatas, + sizeof(struct rdatainfo)); + if (rrset->rri_rdatas == NULL) { + result = ERRSET_NOMEMORY; + goto fail; + } + + /* allocate memory for signatures */ + rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo)); + if (rrset->rri_sigs == NULL) { + result = ERRSET_NOMEMORY; + goto fail; + } + + /* copy answers & signatures */ + for (rr = response->answer, index_ans = 0, index_sig = 0; + rr; rr = rr->next) { + + rdata = NULL; + + if (rr->class == rrset->rri_rdclass && + rr->type == rrset->rri_rdtype) + rdata = &rrset->rri_rdatas[index_ans++]; + + if (rr->class == rrset->rri_rdclass && + rr->type == T_SIG) + rdata = &rrset->rri_sigs[index_sig++]; + + if (rdata) { + rdata->rdi_length = rr->size; + rdata->rdi_data = malloc(rr->size); + + if (rdata->rdi_data == NULL) { + result = ERRSET_NOMEMORY; + goto fail; + } + memcpy(rdata->rdi_data, rr->rdata, rr->size); + } + } + + *res = rrset; + return (ERRSET_SUCCESS); + +fail: + if (rrset != NULL) + freerrset(rrset); + return (result); +} + +void +freerrset(struct rrsetinfo *rrset) +{ + u_int16_t i; + + if (rrset == NULL) + return; + + if (rrset->rri_rdatas) { + for (i = 0; i < rrset->rri_nrdatas; i++) { + if (rrset->rri_rdatas[i].rdi_data == NULL) + break; + free(rrset->rri_rdatas[i].rdi_data); + } + free(rrset->rri_rdatas); + } + + if (rrset->rri_sigs) { + for (i = 0; i < rrset->rri_nsigs; i++) { + if (rrset->rri_sigs[i].rdi_data == NULL) + break; + free(rrset->rri_sigs[i].rdi_data); + } + free(rrset->rri_sigs); + } + + if (rrset->rri_name) + free(rrset->rri_name); + free(rrset); +} + +/* + * DNS response parsing routines + */ +static struct dns_response * +parse_dns_response(const u_char *answer, int size) +{ + struct dns_response *resp; + const u_char *cp; + + /* allocate memory for the response */ + resp = calloc(1, sizeof(*resp)); + if (resp == NULL) + return (NULL); + + /* initialize current pointer */ + cp = answer; + + /* copy header */ + memcpy(&resp->header, cp, HFIXEDSZ); + cp += HFIXEDSZ; + + /* fix header byte order */ + resp->header.qdcount = ntohs(resp->header.qdcount); + resp->header.ancount = ntohs(resp->header.ancount); + resp->header.nscount = ntohs(resp->header.nscount); + resp->header.arcount = ntohs(resp->header.arcount); + + /* there must be at least one query */ + if (resp->header.qdcount < 1) { + free_dns_response(resp); + return (NULL); + } + + /* parse query section */ + resp->query = parse_dns_qsection(answer, size, &cp, + resp->header.qdcount); + if (resp->header.qdcount && resp->query == NULL) { + free_dns_response(resp); + return (NULL); + } + + /* parse answer section */ + resp->answer = parse_dns_rrsection(answer, size, &cp, + resp->header.ancount); + if (resp->header.ancount && resp->answer == NULL) { + free_dns_response(resp); + return (NULL); + } + + /* parse authority section */ + resp->authority = parse_dns_rrsection(answer, size, &cp, + resp->header.nscount); + if (resp->header.nscount && resp->authority == NULL) { + free_dns_response(resp); + return (NULL); + } + + /* parse additional section */ + resp->additional = parse_dns_rrsection(answer, size, &cp, + resp->header.arcount); + if (resp->header.arcount && resp->additional == NULL) { + free_dns_response(resp); + return (NULL); + } + + return (resp); +} + +static struct dns_query * +parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count) +{ + struct dns_query *head, *curr, *prev; + int i, length; + char name[MAXDNAME]; + + for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { + + /* allocate and initialize struct */ + curr = calloc(1, sizeof(struct dns_query)); + if (curr == NULL) { + free_dns_query(head); + return (NULL); + } + if (head == NULL) + head = curr; + if (prev != NULL) + prev->next = curr; + + /* name */ + length = dn_expand(answer, answer + size, *cp, name, + sizeof(name)); + if (length < 0) { + free_dns_query(head); + return (NULL); + } + curr->name = strdup(name); + if (curr->name == NULL) { + free_dns_query(head); + return (NULL); + } + *cp += length; + + /* type */ + curr->type = _getshort(*cp); + *cp += INT16SZ; + + /* class */ + curr->class = _getshort(*cp); + *cp += INT16SZ; + } + + return (head); +} + +static struct dns_rr * +parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, int count) +{ + struct dns_rr *head, *curr, *prev; + int i, length; + char name[MAXDNAME]; + + for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { + + /* allocate and initialize struct */ + curr = calloc(1, sizeof(struct dns_rr)); + if (curr == NULL) { + free_dns_rr(head); + return (NULL); + } + if (head == NULL) + head = curr; + if (prev != NULL) + prev->next = curr; + + /* name */ + length = dn_expand(answer, answer + size, *cp, name, + sizeof(name)); + if (length < 0) { + free_dns_rr(head); + return (NULL); + } + curr->name = strdup(name); + if (curr->name == NULL) { + free_dns_rr(head); + return (NULL); + } + *cp += length; + + /* type */ + curr->type = _getshort(*cp); + *cp += INT16SZ; + + /* class */ + curr->class = _getshort(*cp); + *cp += INT16SZ; + + /* ttl */ + curr->ttl = _getlong(*cp); + *cp += INT32SZ; + + /* rdata size */ + curr->size = _getshort(*cp); + *cp += INT16SZ; + + /* rdata itself */ + curr->rdata = malloc(curr->size); + if (curr->rdata == NULL) { + free_dns_rr(head); + return (NULL); + } + memcpy(curr->rdata, *cp, curr->size); + *cp += curr->size; + } + + return (head); +} + +static void +free_dns_query(struct dns_query *p) +{ + if (p == NULL) + return; + + if (p->name) + free(p->name); + free_dns_query(p->next); + free(p); +} + +static void +free_dns_rr(struct dns_rr *p) +{ + if (p == NULL) + return; + + if (p->name) + free(p->name); + if (p->rdata) + free(p->rdata); + free_dns_rr(p->next); + free(p); +} + +static void +free_dns_response(struct dns_response *p) +{ + if (p == NULL) + return; + + free_dns_query(p->query); + free_dns_rr(p->answer); + free_dns_rr(p->authority); + free_dns_rr(p->additional); + free(p); +} + +static int +count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type) +{ + int n = 0; + + while(p) { + if (p->class == class && p->type == type) + n++; + p = p->next; + } + + return (n); +} + +#endif /* !defined(HAVE_GETRRSETBYNAME) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/getrrsetbyname.h b/crypto/openssh-3.9p1/openbsd-compat/getrrsetbyname.h new file mode 100644 index 0000000000..39995b63fc --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/getrrsetbyname.h @@ -0,0 +1,110 @@ +/* OPENBSD BASED ON : include/netdb.h */ + +/* $OpenBSD: getrrsetbyname.c,v 1.4 2001/08/16 18:16:43 ho Exp $ */ + +/* + * Copyright (c) 2001 Jakob Schlyter. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1999-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _GETRRSETBYNAME_H +#define _GETRRSETBYNAME_H + +#include "includes.h" + +#ifndef HAVE_GETRRSETBYNAME + +#include +#include +#include +#include +#include + +#ifndef HFIXEDSZ +#define HFIXEDSZ 12 +#endif + +#ifndef T_SIG +#define T_SIG 24 +#endif + +/* + * Flags for getrrsetbyname() + */ +#ifndef RRSET_VALIDATED +# define RRSET_VALIDATED 1 +#endif + +/* + * Return codes for getrrsetbyname() + */ +#ifndef ERRSET_SUCCESS +# define ERRSET_SUCCESS 0 +# define ERRSET_NOMEMORY 1 +# define ERRSET_FAIL 2 +# define ERRSET_INVAL 3 +# define ERRSET_NONAME 4 +# define ERRSET_NODATA 5 +#endif + +struct rdatainfo { + unsigned int rdi_length; /* length of data */ + unsigned char *rdi_data; /* record data */ +}; + +struct rrsetinfo { + unsigned int rri_flags; /* RRSET_VALIDATED ... */ + unsigned int rri_rdclass; /* class number */ + unsigned int rri_rdtype; /* RR type number */ + unsigned int rri_ttl; /* time to live */ + unsigned int rri_nrdatas; /* size of rdatas array */ + unsigned int rri_nsigs; /* size of sigs array */ + char *rri_name; /* canonical name */ + struct rdatainfo *rri_rdatas; /* individual records */ + struct rdatainfo *rri_sigs; /* individual signatures */ +}; + +int getrrsetbyname(const char *, unsigned int, unsigned int, unsigned int, struct rrsetinfo **); +void freerrset(struct rrsetinfo *); + +#endif /* !defined(HAVE_GETRRSETBYNAME) */ + +#endif /* _GETRRSETBYNAME_H */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/glob.c b/crypto/openssh-3.9p1/openbsd-compat/glob.c new file mode 100644 index 0000000000..7fafc8c402 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/glob.c @@ -0,0 +1,914 @@ +/* OPENBSD ORIGINAL: lib/libc/gen/glob.c */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * 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. 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. + */ + +#include "includes.h" +#include + +static long +get_arg_max(void) +{ +#ifdef ARG_MAX + return(ARG_MAX); +#elif defined(HAVE_SYSCONF) && defined(_SC_ARG_MAX) + return(sysconf(_SC_ARG_MAX)); +#else + return(256); /* XXX: arbitrary */ +#endif +} + +#if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \ + !defined(GLOB_HAS_GL_MATCHC) + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; +#else +static char rcsid[] = "$OpenBSD: glob.c,v 1.22 2003/06/25 21:16:47 deraadt Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * glob(3) -- a superset of the one defined in POSIX 1003.2. + * + * The [!...] convention to negate a range is supported (SysV, Posix, ksh). + * + * Optional extra services, controlled by flags not defined by POSIX: + * + * GLOB_QUOTE: + * Escaping convention: \ inhibits any special meaning the following + * character might have (except \ at end of string is retained). + * GLOB_MAGCHAR: + * Set in gl_flags if pattern contained a globbing character. + * GLOB_NOMAGIC: + * Same as GLOB_NOCHECK, but it will only append pattern if it did + * not contain any magic characters. [Used in csh style globbing] + * GLOB_ALTDIRFUNC: + * Use alternately specified directory access functions. + * GLOB_TILDE: + * expand ~user/foo to the /home/dir/of/user/foo + * GLOB_BRACE: + * expand {1,2}{a,b} to 1a 1b 2a 2b + * gl_matchc: + * Number of matches in the current invocation of glob. + */ + + +#define DOLLAR '$' +#define DOT '.' +#define EOS '\0' +#define LBRACKET '[' +#define NOT '!' +#define QUESTION '?' +#define QUOTE '\\' +#define RANGE '-' +#define RBRACKET ']' +#define SEP '/' +#define STAR '*' +#undef TILDE /* Some platforms may already define it */ +#define TILDE '~' +#define UNDERSCORE '_' +#define LBRACE '{' +#define RBRACE '}' +#define SLASH '/' +#define COMMA ',' + +#ifndef DEBUG + +#define M_QUOTE 0x8000 +#define M_PROTECT 0x4000 +#define M_MASK 0xffff +#define M_ASCII 0x00ff + +typedef u_short Char; + +#else + +#define M_QUOTE 0x80 +#define M_PROTECT 0x40 +#define M_MASK 0xff +#define M_ASCII 0x7f + +typedef char Char; + +#endif + + +#define CHAR(c) ((Char)((c)&M_ASCII)) +#define META(c) ((Char)((c)|M_QUOTE)) +#define M_ALL META('*') +#define M_END META(']') +#define M_NOT META('!') +#define M_ONE META('?') +#define M_RNG META('-') +#define M_SET META('[') +#define ismeta(c) (((c)&M_QUOTE) != 0) + + +static int compare(const void *, const void *); +static int g_Ctoc(const Char *, char *, u_int); +static int g_lstat(Char *, struct stat *, glob_t *); +static DIR *g_opendir(Char *, glob_t *); +static Char *g_strchr(Char *, int); +static int g_stat(Char *, struct stat *, glob_t *); +static int glob0(const Char *, glob_t *); +static int glob1(Char *, Char *, glob_t *, size_t *); +static int glob2(Char *, Char *, Char *, Char *, Char *, Char *, + glob_t *, size_t *); +static int glob3(Char *, Char *, Char *, Char *, Char *, Char *, + Char *, Char *, glob_t *, size_t *); +static int globextend(const Char *, glob_t *, size_t *); +static const Char * + globtilde(const Char *, Char *, size_t, glob_t *); +static int globexp1(const Char *, glob_t *); +static int globexp2(const Char *, const Char *, glob_t *, int *); +static int match(Char *, Char *, Char *); +#ifdef DEBUG +static void qprintf(const char *, Char *); +#endif + +int +glob(pattern, flags, errfunc, pglob) + const char *pattern; + int flags, (*errfunc)(const char *, int); + glob_t *pglob; +{ + const u_char *patnext; + int c; + Char *bufnext, *bufend, patbuf[MAXPATHLEN]; + + patnext = (u_char *) pattern; + if (!(flags & GLOB_APPEND)) { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_offs = 0; + } + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_errfunc = errfunc; + pglob->gl_matchc = 0; + + bufnext = patbuf; + bufend = bufnext + MAXPATHLEN - 1; + if (flags & GLOB_NOESCAPE) + while (bufnext < bufend && (c = *patnext++) != EOS) + *bufnext++ = c; + else { + /* Protect the quoted characters. */ + while (bufnext < bufend && (c = *patnext++) != EOS) + if (c == QUOTE) { + if ((c = *patnext++) == EOS) { + c = QUOTE; + --patnext; + } + *bufnext++ = c | M_PROTECT; + } else + *bufnext++ = c; + } + *bufnext = EOS; + + if (flags & GLOB_BRACE) + return globexp1(patbuf, pglob); + else + return glob0(patbuf, pglob); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int +globexp1(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char* ptr = pattern; + int rv; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) + return glob0(pattern, pglob); + + while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) + if (!globexp2(ptr, pattern, pglob, &rv)) + return rv; + + return glob0(pattern, pglob); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int +globexp2(ptr, pattern, pglob, rv) + const Char *ptr, *pattern; + glob_t *pglob; + int *rv; +{ + int i; + Char *lm, *ls; + const Char *pe, *pm, *pl; + Char patbuf[MAXPATHLEN]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + ; + *lm = EOS; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + ; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) { + *rv = glob0(patbuf, pglob); + return 0; + } + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) { + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) + ; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pl; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + ; + + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS; ) + ; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + *rv = globexp1(patbuf, pglob); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + } + *rv = 0; + return 0; +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(pattern, patbuf, patbuf_len, pglob) + const Char *pattern; + Char *patbuf; + size_t patbuf_len; + glob_t *pglob; +{ + struct passwd *pwd; + char *h; + const Char *p; + Char *b, *eb; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return pattern; + + /* Copy up to the end of the string or / */ + eb = &patbuf[patbuf_len - 1]; + for (p = pattern + 1, h = (char *) patbuf; + h < (char *)eb && *p && *p != SLASH; *h++ = *p++) + ; + + *h = EOS; + +#if 0 + if (h == (char *)eb) + return what; +#endif + + if (((char *) patbuf)[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME + * first and then trying the password file + */ +#if 0 + if (issetugid() != 0 || (h = getenv("HOME")) == NULL) { +#endif + if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) { + if ((pwd = getpwuid(getuid())) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + } else { + /* + * Expand a ~user + */ + if ((pwd = getpwnam((char*) patbuf)) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + for (b = patbuf; b < eb && *h; *b++ = *h++) + ; + + /* Append the rest of the pattern */ + while (b < eb && (*b++ = *p++) != EOS) + ; + *b = EOS; + + return patbuf; +} + + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. It is not an error + * to find no matches. + */ +static int +glob0(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char *qpatnext; + int c, err, oldpathc; + Char *bufnext, patbuf[MAXPATHLEN]; + size_t limit = 0; + + qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); + oldpathc = pglob->gl_pathc; + bufnext = patbuf; + + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { + switch (c) { + case LBRACKET: + c = *qpatnext; + if (c == NOT) + ++qpatnext; + if (*qpatnext == EOS || + g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { + *bufnext++ = LBRACKET; + if (c == NOT) + --qpatnext; + break; + } + *bufnext++ = M_SET; + if (c == NOT) + *bufnext++ = M_NOT; + c = *qpatnext++; + do { + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { + *bufnext++ = M_RNG; + *bufnext++ = CHAR(c); + qpatnext += 2; + } + } while ((c = *qpatnext++) != RBRACKET); + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_END; + break; + case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_ONE; + break; + case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; + /* collapse adjacent stars to one, + * to avoid exponential behavior + */ + if (bufnext == patbuf || bufnext[-1] != M_ALL) + *bufnext++ = M_ALL; + break; + default: + *bufnext++ = CHAR(c); + break; + } + } + *bufnext = EOS; +#ifdef DEBUG + qprintf("glob0:", patbuf); +#endif + + if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0) + return(err); + + /* + * If there was no match we are going to append the pattern + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified + * and the pattern did not contain any magic characters + * GLOB_NOMAGIC is there just for compatibility with csh. + */ + if (pglob->gl_pathc == oldpathc) { + if ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR))) + return(globextend(pattern, pglob, &limit)); + else + return(GLOB_NOMATCH); + } + if (!(pglob->gl_flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); + return(0); +} + +static int +compare(p, q) + const void *p, *q; +{ + return(strcmp(*(char **)p, *(char **)q)); +} + +static int +glob1(pattern, pattern_last, pglob, limitp) + Char *pattern, *pattern_last; + glob_t *pglob; + size_t *limitp; +{ + Char pathbuf[MAXPATHLEN]; + + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + if (*pattern == EOS) + return(0); + return(glob2(pathbuf, pathbuf+MAXPATHLEN-1, + pathbuf, pathbuf+MAXPATHLEN-1, + pattern, pattern_last, pglob, limitp)); +} + +/* + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. + */ +static int +glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern, + pattern_last, pglob, limitp) + Char *pathbuf, *pathbuf_last, *pathend, *pathend_last; + Char *pattern, *pattern_last; + glob_t *pglob; + size_t *limitp; +{ + struct stat sb; + Char *p, *q; + int anymeta; + + /* + * Loop over pattern segments until end of pattern or until + * segment with meta character found. + */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ + *pathend = EOS; + if (g_lstat(pathbuf, &sb, pglob)) + return(0); + + if (((pglob->gl_flags & GLOB_MARK) && + pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) || + (S_ISLNK(sb.st_mode) && + (g_stat(pathbuf, &sb, pglob) == 0) && + S_ISDIR(sb.st_mode)))) { + if (pathend+1 > pathend_last) + return (1); + *pathend++ = SEP; + *pathend = EOS; + } + ++pglob->gl_matchc; + return(globextend(pathbuf, pglob, limitp)); + } + + /* Find end of next segment, copy tentatively to pathend. */ + q = pathend; + p = pattern; + while (*p != EOS && *p != SEP) { + if (ismeta(*p)) + anymeta = 1; + if (q+1 > pathend_last) + return (1); + *q++ = *p++; + } + + if (!anymeta) { /* No expansion, do next segment. */ + pathend = q; + pattern = p; + while (*pattern == SEP) { + if (pathend+1 > pathend_last) + return (1); + *pathend++ = *pattern++; + } + } else + /* Need expansion, recurse. */ + return(glob3(pathbuf, pathbuf_last, pathend, + pathend_last, pattern, pattern_last, + p, pattern_last, pglob, limitp)); + } + /* NOTREACHED */ +} + +static int +glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, + restpattern, restpattern_last, pglob, limitp) + Char *pathbuf, *pathbuf_last, *pathend, *pathend_last; + Char *pattern, *pattern_last, *restpattern, *restpattern_last; + glob_t *pglob; + size_t *limitp; +{ + register struct dirent *dp; + DIR *dirp; + int err; + char buf[MAXPATHLEN]; + + /* + * The readdirfunc declaration can't be prototyped, because it is + * assigned, below, to two functions which are prototyped in glob.h + * and dirent.h as taking pointers to differently typed opaque + * structures. + */ + struct dirent *(*readdirfunc)(void *); + + if (pathend > pathend_last) + return (1); + *pathend = EOS; + errno = 0; + + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + /* TODO: don't call for ENOENT or ENOTDIR? */ + if (pglob->gl_errfunc) { + if (g_Ctoc(pathbuf, buf, sizeof(buf))) + return(GLOB_ABORTED); + if (pglob->gl_errfunc(buf, errno) || + pglob->gl_flags & GLOB_ERR) + return(GLOB_ABORTED); + } + return(0); + } + + err = 0; + + /* Search directory for matching names. */ + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + readdirfunc = pglob->gl_readdir; + else + readdirfunc = (struct dirent *(*)(void *))readdir; + while ((dp = (*readdirfunc)(dirp))) { + register u_char *sc; + register Char *dc; + + /* Initial DOT must be matched literally. */ + if (dp->d_name[0] == DOT && *pattern != DOT) + continue; + dc = pathend; + sc = (u_char *) dp->d_name; + while (dc < pathend_last && (*dc++ = *sc++) != EOS) + ; + if (dc >= pathend_last) { + *dc = EOS; + err = 1; + break; + } + + if (!match(pathend, pattern, restpattern)) { + *pathend = EOS; + continue; + } + err = glob2(pathbuf, pathbuf_last, --dc, pathend_last, + restpattern, restpattern_last, pglob, limitp); + if (err) + break; + } + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir)(dirp); + else + closedir(dirp); + return(err); +} + + +/* + * Extend the gl_pathv member of a glob_t structure to accommodate a new item, + * add the new item, and update gl_pathc. + * + * This assumes the BSD realloc, which only copies the block when its size + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic + * behavior. + * + * Return 0 if new item added, error code if memory couldn't be allocated. + * + * Invariant of the glob_t structure: + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and + * gl_pathv points to (gl_offs + gl_pathc + 1) items. + */ +static int +globextend(path, pglob, limitp) + const Char *path; + glob_t *pglob; + size_t *limitp; +{ + register char **pathv; + register int i; + u_int newsize, len; + char *copy; + const Char *p; + + newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); + pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) : + malloc(newsize); + if (pathv == NULL) { + if (pglob->gl_pathv) { + free(pglob->gl_pathv); + pglob->gl_pathv = NULL; + } + return(GLOB_NOSPACE); + } + + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + pathv += pglob->gl_offs; + for (i = pglob->gl_offs; --i >= 0; ) + *--pathv = NULL; + } + pglob->gl_pathv = pathv; + + for (p = path; *p++;) + ; + len = (size_t)(p - path); + *limitp += len; + if ((copy = malloc(len)) != NULL) { + if (g_Ctoc(path, copy, len)) { + free(copy); + return(GLOB_NOSPACE); + } + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; + } + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + + if ((pglob->gl_flags & GLOB_LIMIT) && + newsize + *limitp >= (u_int) get_arg_max()) { + errno = 0; + return(GLOB_NOSPACE); + } + + return(copy == NULL ? GLOB_NOSPACE : 0); +} + + +/* + * pattern matching function for filenames. Each occurrence of the * + * pattern causes a recursion level. + */ +static int +match(name, pat, patend) + register Char *name, *pat, *patend; +{ + int ok, negate_range; + Char c, k; + + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return(1); + do + if (match(name, pat, patend)) + return(1); + while (*name++ != EOS) + ; + return(0); + case M_ONE: + if (*name++ == EOS) + return(0); + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + return(0); + if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { + if (c <= k && k <= pat[1]) + ok = 1; + pat += 2; + } else if (c == k) + ok = 1; + if (ok == negate_range) + return(0); + break; + default: + if (*name++ != c) + return(0); + break; + } + } + return(*name == EOS); +} + +/* Free allocated data belonging to a glob_t structure. */ +void +globfree(pglob) + glob_t *pglob; +{ + register int i; + register char **pp; + + if (pglob->gl_pathv != NULL) { + pp = pglob->gl_pathv + pglob->gl_offs; + for (i = pglob->gl_pathc; i--; ++pp) + if (*pp) + free(*pp); + free(pglob->gl_pathv); + pglob->gl_pathv = NULL; + } +} + +static DIR * +g_opendir(str, pglob) + register Char *str; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + if (!*str) + strlcpy(buf, ".", sizeof buf); + else { + if (g_Ctoc(str, buf, sizeof(buf))) + return(NULL); + } + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_opendir)(buf)); + + return(opendir(buf)); +} + +static int +g_lstat(fn, sb, pglob) + register Char *fn; + struct stat *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + if (g_Ctoc(fn, buf, sizeof(buf))) + return(-1); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_lstat)(buf, sb)); + return(lstat(buf, sb)); +} + +static int +g_stat(fn, sb, pglob) + register Char *fn; + struct stat *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + if (g_Ctoc(fn, buf, sizeof(buf))) + return(-1); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_stat)(buf, sb)); + return(stat(buf, sb)); +} + +static Char * +g_strchr(str, ch) + Char *str; + int ch; +{ + do { + if (*str == ch) + return (str); + } while (*str++); + return (NULL); +} + +static int +g_Ctoc(str, buf, len) + register const Char *str; + char *buf; + u_int len; +{ + + while (len--) { + if ((*buf++ = *str++) == EOS) + return (0); + } + return (1); +} + +#ifdef DEBUG +static void +qprintf(str, s) + const char *str; + register Char *s; +{ + register Char *p; + + (void)printf("%s:\n", str); + for (p = s; *p; p++) + (void)printf("%c", CHAR(*p)); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", *p & M_PROTECT ? '"' : ' '); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", ismeta(*p) ? '_' : ' '); + (void)printf("\n"); +} +#endif + +#endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || + !defined(GLOB_HAS_GL_MATCHC) */ + diff --git a/crypto/openssh-3.9p1/openbsd-compat/glob.h b/crypto/openssh-3.9p1/openbsd-compat/glob.h new file mode 100644 index 0000000000..3428b20135 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/glob.h @@ -0,0 +1,99 @@ +/* OPENBSD ORIGINAL: include/glob.h */ + +/* $OpenBSD: glob.h,v 1.8 2003/06/02 19:34:12 millert Exp $ */ +/* $NetBSD: glob.h,v 1.5 1994/10/26 00:55:56 cgd Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * 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. 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. + * + * @(#)glob.h 8.1 (Berkeley) 6/2/93 + */ + +#if !defined(HAVE_GLOB_H) || !defined(GLOB_HAS_ALTDIRFUNC) || \ + !defined(GLOB_HAS_GL_MATCHC) + +#ifndef _GLOB_H_ +#define _GLOB_H_ + +struct stat; +typedef struct { + int gl_pathc; /* Count of total paths so far. */ + int gl_matchc; /* Count of paths matching pattern. */ + int gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc)(const char *, int); + + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir)(void *); + struct dirent *(*gl_readdir)(void *); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, struct stat *); + int (*gl_stat)(const char *, struct stat *); +} glob_t; + +/* Flags */ +#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ +#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ +#define GLOB_ERR 0x0004 /* Return on error. */ +#define GLOB_MARK 0x0008 /* Append / to matching directories. */ +#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ +#define GLOB_NOSORT 0x0020 /* Don't sort. */ + +#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */ +#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */ +#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ +#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */ +#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ +#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ +#define GLOB_NOESCAPE 0x1000 /* Disable backslash escaping. */ +#define GLOB_LIMIT 0x2000 /* Limit pattern match output to ARG_MAX */ + +/* Error values returned by glob(3) */ +#define GLOB_NOSPACE (-1) /* Malloc call failed. */ +#define GLOB_ABORTED (-2) /* Unignored error. */ +#define GLOB_NOMATCH (-3) /* No match and GLOB_NOCHECK not set. */ +#define GLOB_NOSYS (-4) /* Function not supported. */ +#define GLOB_ABEND GLOB_ABORTED + +int glob(const char *, int, int (*)(const char *, int), glob_t *); +void globfree(glob_t *); + +#endif /* !_GLOB_H_ */ + +#endif /* !defined(HAVE_GLOB_H) || !defined(GLOB_HAS_ALTDIRFUNC) || + !defined(GLOB_HAS_GL_MATCHC */ + diff --git a/crypto/openssh-3.9p1/openbsd-compat/inet_aton.c b/crypto/openssh-3.9p1/openbsd-compat/inet_aton.c new file mode 100644 index 0000000000..c141bcc68a --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/inet_aton.c @@ -0,0 +1,189 @@ +/* OPENBSD ORIGINAL: lib/libc/net/inet_addr.c */ + +/* $OpenBSD: inet_addr.c,v 1.7 2003/06/02 20:18:35 millert Exp $ */ + +/* + * Copyright (c) 1983, 1990, 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. 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. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#include "includes.h" + +#if !defined(HAVE_INET_ATON) + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +static char rcsid[] = "$From: inet_addr.c,v 8.5 1996/08/05 08:31:35 vixie Exp $"; +#else +static char rcsid[] = "$OpenBSD: inet_addr.c,v 1.7 2003/06/02 20:18:35 millert Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include + +#if 0 +/* + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ +in_addr_t +inet_addr(cp) + register const char *cp; +{ + struct in_addr val; + + if (inet_aton(cp, &val)) + return (val.s_addr); + return (INADDR_NONE); +} +#endif + +/* + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(const char *cp, struct in_addr *addr) +{ + register u_int32_t val; + register int base, n; + register char c; + unsigned int parts[4]; + register unsigned int *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit(c)) + return (0); + val = 0; base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else + base = 8; + } + for (;;) { + if (isascii(c) && isdigit(c)) { + val = (val * base) + (c - '0'); + c = *++cp; + } else if (base == 16 && isascii(c) && isxdigit(c)) { + val = (val << 4) | + (c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace(c))) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if ((val > 0xffffff) || (parts[0] > 0xff)) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if ((val > 0xffff) || (parts[0] > 0xff) || (parts[1] > 0xff)) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if ((val > 0xff) || (parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff)) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr) + addr->s_addr = htonl(val); + return (1); +} + +#endif /* !defined(HAVE_INET_ATON) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/inet_ntoa.c b/crypto/openssh-3.9p1/openbsd-compat/inet_ntoa.c new file mode 100644 index 0000000000..dc010dc53f --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/inet_ntoa.c @@ -0,0 +1,61 @@ +/* OPENBSD ORIGINAL: lib/libc/net/inet_ntoa.c */ + +/* + * Copyright (c) 1983, 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. 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. + */ + +#include "includes.h" + +#if defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA) + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$OpenBSD: inet_ntoa.c,v 1.4 2003/06/02 20:18:35 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Convert network-format internet address + * to base 256 d.d.d.d representation. + */ +#include +#include +#include +#include + +char *inet_ntoa(struct in_addr in) +{ + static char b[18]; + register char *p; + + p = (char *)∈ +#define UC(b) (((int)b)&0xff) + (void)snprintf(b, sizeof(b), + "%u.%u.%u.%u", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); + return (b); +} + +#endif /* defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/inet_ntop.c b/crypto/openssh-3.9p1/openbsd-compat/inet_ntop.c new file mode 100644 index 0000000000..7031625b44 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/inet_ntop.c @@ -0,0 +1,231 @@ +/* OPENBSD ORIGINAL: lib/libc/net/inet_ntop.c */ + +/* $OpenBSD: inet_ntop.c,v 1.5 2002/08/23 16:27:31 itojun Exp $ */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "includes.h" + +#ifndef HAVE_INET_NTOP + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char rcsid[] = "$From: inet_ntop.c,v 8.7 1996/08/05 08:41:18 vixie Exp $"; +#else +static char rcsid[] = "$OpenBSD: inet_ntop.c,v 1.5 2002/08/23 16:27:31 itojun Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#ifndef HAVE_CYGWIN +#include +#endif +#include +#include +#include + +#ifndef IN6ADDRSZ +#define IN6ADDRSZ 16 /* IPv6 T_AAAA */ +#endif + +#ifndef INT16SZ +#define INT16SZ 2 /* for systems without 16-bit ints */ +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4(const u_char *src, char *dst, size_t size); +static const char *inet_ntop6(const u_char *src, char *dst, size_t size); + +/* char * + * inet_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +inet_ntop(af, src, dst, size) + int af; + const void *src; + char *dst; + size_t size; +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); + case AF_INET6: + return (inet_ntop6(src, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address, more or less like inet_ntoa() + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a u_char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + static const char fmt[] = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + int l; + + l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]); + if (l <= 0 || l >= size) { + errno = ENOSPC; + return (NULL); + } + strlcpy(dst, tmp, size); + return (dst); +} + +/* const char * + * inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop6(src, dst, size) + const u_char *src; + char *dst; + size_t size; +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; + char *tp, *ep; + struct { int base, len; } best, cur; + u_int words[IN6ADDRSZ / INT16SZ]; + int i; + int advance; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + ep = tmp + sizeof(tmp); + for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) { + if (tp + 1 >= ep) + return (NULL); + *tp++ = ':'; + } + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) { + if (tp + 1 >= ep) + return (NULL); + *tp++ = ':'; + } + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) + return (NULL); + tp += strlen(tp); + break; + } + advance = snprintf(tp, ep - tp, "%x", words[i]); + if (advance <= 0 || advance >= ep - tp) + return (NULL); + tp += advance; + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { + if (tp + 1 >= ep) + return (NULL); + *tp++ = ':'; + } + if (tp + 1 >= ep) + return (NULL); + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + strlcpy(dst, tmp, size); + return (dst); +} + +#endif /* !HAVE_INET_NTOP */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/mktemp.c b/crypto/openssh-3.9p1/openbsd-compat/mktemp.c new file mode 100644 index 0000000000..aff8d20056 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/mktemp.c @@ -0,0 +1,182 @@ +/* OPENBSD ORIGINAL: lib/libc/stdio/mktemp.c */ + +/* THIS FILE HAS BEEN MODIFIED FROM THE ORIGINAL OPENBSD SOURCE */ +/* Changes: Removed mktemp */ + +/* + * Copyright (c) 1987, 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. 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. + */ + +#include "includes.h" + +#if !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$OpenBSD: mktemp.c,v 1.17 2003/06/02 20:18:37 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#ifdef HAVE_CYGWIN +#define open binary_open +extern int binary_open(); +#endif + +static int _gettemp(char *, int *, int, int); + +int +mkstemps(path, slen) + char *path; + int slen; +{ + int fd; + + return (_gettemp(path, &fd, 0, slen) ? fd : -1); +} + +int +mkstemp(path) + char *path; +{ + int fd; + + return (_gettemp(path, &fd, 0, 0) ? fd : -1); +} + +char * +mkdtemp(path) + char *path; +{ + return(_gettemp(path, (int *)NULL, 1, 0) ? path : (char *)NULL); +} + +static int +_gettemp(path, doopen, domkdir, slen) + char *path; + register int *doopen; + int domkdir; + int slen; +{ + register char *start, *trv, *suffp; + struct stat sbuf; + int rval; + pid_t pid; + + if (doopen && domkdir) { + errno = EINVAL; + return(0); + } + + for (trv = path; *trv; ++trv) + ; + trv -= slen; + suffp = trv; + --trv; + if (trv < path) { + errno = EINVAL; + return (0); + } + pid = getpid(); + while (trv >= path && *trv == 'X' && pid != 0) { + *trv-- = (pid % 10) + '0'; + pid /= 10; + } + while (trv >= path && *trv == 'X') { + char c; + + pid = (arc4random() & 0xffff) % (26+26); + if (pid < 26) + c = pid + 'A'; + else + c = (pid - 26) + 'a'; + *trv-- = c; + } + start = trv + 1; + + /* + * check the target directory; if you have six X's and it + * doesn't exist this runs for a *very* long time. + */ + if (doopen || domkdir) { + for (;; --trv) { + if (trv <= path) + break; + if (*trv == '/') { + *trv = '\0'; + rval = stat(path, &sbuf); + *trv = '/'; + if (rval != 0) + return(0); + if (!S_ISDIR(sbuf.st_mode)) { + errno = ENOTDIR; + return(0); + } + break; + } + } + } + + for (;;) { + if (doopen) { + if ((*doopen = + open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0) + return(1); + if (errno != EEXIST) + return(0); + } else if (domkdir) { + if (mkdir(path, 0700) == 0) + return(1); + if (errno != EEXIST) + return(0); + } else if (lstat(path, &sbuf)) + return(errno == ENOENT ? 1 : 0); + + /* tricky little algorithm for backward compatibility */ + for (trv = start;;) { + if (!*trv) + return (0); + if (*trv == 'Z') { + if (trv == suffp) + return (0); + *trv++ = 'a'; + } else { + if (isdigit(*trv)) + *trv = 'a'; + else if (*trv == 'z') /* inc from z to A */ + *trv = 'A'; + else { + if (trv == suffp) + return (0); + ++*trv; + } + break; + } + } + } + /*NOTREACHED*/ +} + +#endif /* !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/openbsd-compat.h b/crypto/openssh-3.9p1/openbsd-compat/openbsd-compat.h new file mode 100644 index 0000000000..89d1454e07 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/openbsd-compat.h @@ -0,0 +1,173 @@ +/* $Id: openbsd-compat.h,v 1.26 2004/08/15 08:41:00 djm Exp $ */ + +/* + * Copyright (c) 1999-2003 Damien Miller. All rights reserved. + * Copyright (c) 2003 Ben Lindstrom. All rights reserved. + * Copyright (c) 2002 Tim Rice. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _OPENBSD_COMPAT_H +#define _OPENBSD_COMPAT_H + +#include "includes.h" + +/* OpenBSD function replacements */ +#include "base64.h" +#include "sigact.h" +#include "glob.h" +#include "readpassphrase.h" +#include "vis.h" +#include "getrrsetbyname.h" + + +#ifndef HAVE_BASENAME +char *basename(const char *path); +#endif + +#ifndef HAVE_BINDRESVPORT_SA +int bindresvport_sa(int sd, struct sockaddr *sa); +#endif + +#ifndef HAVE_CLOSEFROM +void closefrom(int); +#endif + +#ifndef HAVE_GETCWD +char *getcwd(char *pt, size_t size); +#endif + +#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) +char *realpath(const char *path, char *resolved); +#endif + +#ifndef HAVE_RRESVPORT_AF +int rresvport_af(int *alport, sa_family_t af); +#endif + +#ifndef HAVE_STRLCPY +/* #include XXX Still needed? */ +size_t strlcpy(char *dst, const char *src, size_t siz); +#endif + +#ifndef HAVE_STRLCAT +/* #include XXX Still needed? */ +size_t strlcat(char *dst, const char *src, size_t siz); +#endif + +#ifndef HAVE_SETENV +int setenv(register const char *name, register const char *value, int rewrite); +#endif + +#ifndef HAVE_STRMODE +void strmode(int mode, char *p); +#endif + +#if !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) +int mkstemps(char *path, int slen); +int mkstemp(char *path); +char *mkdtemp(char *path); +#endif + +#ifndef HAVE_DAEMON +int daemon(int nochdir, int noclose); +#endif + +#ifndef HAVE_DIRNAME +char *dirname(const char *path); +#endif + +#if defined(BROKEN_INET_NTOA) || !defined(HAVE_INET_NTOA) +char *inet_ntoa(struct in_addr in); +#endif + +#ifndef HAVE_INET_NTOP +const char *inet_ntop(int af, const void *src, char *dst, size_t size); +#endif + +#ifndef HAVE_INET_ATON +int inet_aton(const char *cp, struct in_addr *addr); +#endif + +#ifndef HAVE_STRSEP +char *strsep(char **stringp, const char *delim); +#endif + +#ifndef HAVE_SETPROCTITLE +void setproctitle(const char *fmt, ...); +void compat_init_setproctitle(int argc, char *argv[]); +#endif + +#ifndef HAVE_GETGROUPLIST +/* #include XXXX Still needed ? */ +int getgrouplist(const char *, gid_t, gid_t *, int *); +#endif + +#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET) +int BSDgetopt(int argc, char * const *argv, const char *opts); +#endif + + +/* Home grown routines */ +#include "bsd-misc.h" +#include "bsd-waitpid.h" + +/*#include XXX Still needed? * For uid_t, gid_t * */ + +#ifndef HAVE_GETPEEREID +int getpeereid(int , uid_t *, gid_t *); +#endif + +#ifndef HAVE_ARC4RANDOM +unsigned int arc4random(void); +void arc4random_stir(void); +#endif /* !HAVE_ARC4RANDOM */ + +#ifndef HAVE_OPENPTY +int openpty(int *, int *, char *, struct termios *, struct winsize *); +#endif /* HAVE_OPENPTY */ + +/* #include XXX needed? For size_t */ + +#ifndef HAVE_SNPRINTF +int snprintf(char *, size_t, const char *, ...); +#endif + +#ifndef HAVE_VSNPRINTF +int vsnprintf(char *, size_t, const char *, va_list); +#endif + +void *xmmap(size_t size); +char *xcrypt(const char *password, const char *salt); +char *shadow_pw(struct passwd *pw); + + +/* rfc2553 socket API replacements */ +#include "fake-rfc2553.h" + +/* Routines for a single OS platform */ +#include "bsd-cray.h" +#include "bsd-cygwin_util.h" +#include "port-irix.h" +#include "port-aix.h" + +#endif /* _OPENBSD_COMPAT_H */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/port-aix.c b/crypto/openssh-3.9p1/openbsd-compat/port-aix.c new file mode 100644 index 0000000000..78f4faea3b --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/port-aix.c @@ -0,0 +1,294 @@ +/* + * + * Copyright (c) 2001 Gert Doering. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "includes.h" +#include "auth.h" +#include "ssh.h" +#include "log.h" +#include "servconf.h" +#include "canohost.h" +#include "xmalloc.h" +#include "buffer.h" + +#ifdef _AIX + +#include +#include "port-aix.h" + +extern ServerOptions options; +extern Buffer loginmsg; + +# ifdef HAVE_SETAUTHDB +static char old_registry[REGISTRY_SIZE] = ""; +# endif + +/* + * AIX has a "usrinfo" area where logname and other stuff is stored - + * a few applications actually use this and die if it's not set + * + * NOTE: TTY= should be set, but since no one uses it and it's hard to + * acquire due to privsep code. We will just drop support. + */ +void +aix_usrinfo(struct passwd *pw) +{ + u_int i; + size_t len; + char *cp; + + len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name)); + cp = xmalloc(len); + + i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0', + pw->pw_name, '\0'); + if (usrinfo(SETUINFO, cp, i) == -1) + fatal("Couldn't set usrinfo: %s", strerror(errno)); + debug3("AIX/UsrInfo: set len %d", i); + + xfree(cp); +} + +# ifdef WITH_AIXAUTHENTICATE +/* + * Remove embedded newlines in string (if any). + * Used before logging messages returned by AIX authentication functions + * so the message is logged on one line. + */ +void +aix_remove_embedded_newlines(char *p) +{ + if (p == NULL) + return; + + for (; *p; p++) { + if (*p == '\n') + *p = ' '; + } + /* Remove trailing whitespace */ + if (*--p == ' ') + *p = '\0'; +} + +/* + * Do authentication via AIX's authenticate routine. We loop until the + * reenter parameter is 0, but normally authenticate is called only once. + * + * Note: this function returns 1 on success, whereas AIX's authenticate() + * returns 0. + */ +int +sys_auth_passwd(Authctxt *ctxt, const char *password) +{ + char *authmsg = NULL, *msg, *name = ctxt->pw->pw_name; + int authsuccess = 0, expired, reenter, result; + + do { + result = authenticate((char *)name, (char *)password, &reenter, + &authmsg); + aix_remove_embedded_newlines(authmsg); + debug3("AIX/authenticate result %d, msg %.100s", result, + authmsg); + } while (reenter); + + if (result == 0) { + authsuccess = 1; + + /* + * Record successful login. We don't have a pty yet, so just + * label the line as "ssh" + */ + aix_setauthdb(name); + + /* + * Check if the user's password is expired. + */ + expired = passwdexpired(name, &msg); + if (msg && *msg) { + buffer_append(&loginmsg, msg, strlen(msg)); + aix_remove_embedded_newlines(msg); + } + debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg); + + switch (expired) { + case 0: /* password not expired */ + break; + case 1: /* expired, password change required */ + ctxt->force_pwchange = 1; + disable_forwarding(); + break; + default: /* user can't change(2) or other error (-1) */ + logit("Password can't be changed for user %s: %.100s", + name, msg); + if (msg) + xfree(msg); + authsuccess = 0; + } + + aix_restoreauthdb(); + } + + if (authmsg != NULL) + xfree(authmsg); + + return authsuccess; +} + +/* + * Check if specified account is permitted to log in. + * Returns 1 if login is allowed, 0 if not allowed. + */ +int +sys_auth_allowed_user(struct passwd *pw) +{ + char *msg = NULL; + int result, permitted = 0; + struct stat st; + + /* + * Don't perform checks for root account (PermitRootLogin controls + * logins via * ssh) or if running as non-root user (since + * loginrestrictions will always fail due to insufficient privilege). + */ + if (pw->pw_uid == 0 || geteuid() != 0) { + debug3("%s: not checking", __func__); + return 1; + } + + result = loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg); + if (result == 0) + permitted = 1; + /* + * If restricted because /etc/nologin exists, the login will be denied + * in session.c after the nologin message is sent, so allow for now + * and do not append the returned message. + */ + if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0) + permitted = 1; + else if (msg != NULL) + buffer_append(&loginmsg, msg, strlen(msg)); + if (msg == NULL) + msg = xstrdup("(none)"); + aix_remove_embedded_newlines(msg); + debug3("AIX/loginrestrictions returned %d msg %.100s", result, msg); + + if (!permitted) + logit("Login restricted for %s: %.100s", pw->pw_name, msg); + xfree(msg); + return permitted; +} + +int +sys_auth_record_login(const char *user, const char *host, const char *ttynm) +{ + char *msg; + int success = 0; + + aix_setauthdb(user); + if (loginsuccess((char *)user, host, ttynm, &msg) == 0) { + success = 1; + if (msg != NULL) { + debug("AIX/loginsuccess: msg %s", __func__, msg); + buffer_append(&loginmsg, msg, strlen(msg)); + xfree(msg); + } + } + aix_restoreauthdb(); + return (success); +} + +# ifdef CUSTOM_FAILED_LOGIN +/* + * record_failed_login: generic "login failed" interface function + */ +void +record_failed_login(const char *user, const char *ttyname) +{ + char *hostname = (char *)get_canonical_hostname(options.use_dns); + + if (geteuid() != 0) + return; + + aix_setauthdb(user); +# ifdef AIX_LOGINFAILED_4ARG + loginfailed((char *)user, hostname, (char *)ttyname, AUDIT_FAIL_AUTH); +# else + loginfailed((char *)user, hostname, (char *)ttyname); +# endif + aix_restoreauthdb(); +} +# endif /* CUSTOM_FAILED_LOGIN */ + +/* + * If we have setauthdb, retrieve the password registry for the user's + * account then feed it to setauthdb. This will mean that subsequent AIX auth + * functions will only use the specified loadable module. If we don't have + * setauthdb this is a no-op. + */ +void +aix_setauthdb(const char *user) +{ +# ifdef HAVE_SETAUTHDB + char *registry; + + if (setuserdb(S_READ) == -1) { + debug3("%s: Could not open userdb to read", __func__); + return; + } + + if (getuserattr((char *)user, S_REGISTRY, ®istry, SEC_CHAR) == 0) { + if (setauthdb(registry, old_registry) == 0) + debug3("AIX/setauthdb set registry '%s'", registry); + else + debug3("AIX/setauthdb set registry '%s' failed: %s", + registry, strerror(errno)); + } else + debug3("%s: Could not read S_REGISTRY for user: %s", __func__, + strerror(errno)); + enduserdb(); +# endif /* HAVE_SETAUTHDB */ +} + +/* + * Restore the user's registry settings from old_registry. + * Note that if the first aix_setauthdb fails, setauthdb("") is still safe + * (it restores the system default behaviour). If we don't have setauthdb, + * this is a no-op. + */ +void +aix_restoreauthdb(void) +{ +# ifdef HAVE_SETAUTHDB + if (setauthdb(old_registry, NULL) == 0) + debug3("%s: restoring old registry '%s'", __func__, + old_registry); + else + debug3("%s: failed to restore old registry %s", __func__, + old_registry); +# endif /* HAVE_SETAUTHDB */ +} + +# endif /* WITH_AIXAUTHENTICATE */ + +#endif /* _AIX */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/port-aix.h b/crypto/openssh-3.9p1/openbsd-compat/port-aix.h new file mode 100644 index 0000000000..29e9751ce1 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/port-aix.h @@ -0,0 +1,77 @@ +/* $Id: port-aix.h,v 1.21 2004/08/14 14:09:12 dtucker Exp $ */ + +/* + * + * Copyright (c) 2001 Gert Doering. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _AIX + +#ifdef WITH_AIXAUTHENTICATE +# include +# include +# if defined(HAVE_SYS_AUDIT_H) && defined(AIX_LOGINFAILED_4ARG) +# include +# endif +# include +#endif + +/* Some versions define r_type in the above headers, which causes a conflict */ +#ifdef r_type +# undef r_type +#endif + +/* AIX 4.2.x doesn't have nanosleep but does have nsleep which is equivalent */ +#if !defined(HAVE_NANOSLEEP) && defined(HAVE_NSLEEP) +# define nanosleep(a,b) nsleep(a,b) +#endif + +/* For struct timespec on AIX 4.2.x */ +#ifdef HAVE_SYS_TIMERS_H +# include +#endif + +/* + * According to the setauthdb man page, AIX password registries must be 15 + * chars or less plus terminating NUL. + */ +#ifdef HAVE_SETAUTHDB +# define REGISTRY_SIZE 16 +#endif + +void aix_usrinfo(struct passwd *); + +#ifdef WITH_AIXAUTHENTICATE +# define CUSTOM_SYS_AUTH_PASSWD 1 +# define CUSTOM_SYS_AUTH_ALLOWED_USER 1 +int sys_auth_allowed_user(struct passwd *); +# define CUSTOM_SYS_AUTH_RECORD_LOGIN 1 +int sys_auth_record_login(const char *, const char *, const char *); +# define CUSTOM_FAILED_LOGIN 1 +void record_failed_login(const char *, const char *); +#endif + +void aix_setauthdb(const char *); +void aix_restoreauthdb(void); +void aix_remove_embedded_newlines(char *); +#endif /* _AIX */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/port-irix.c b/crypto/openssh-3.9p1/openbsd-compat/port-irix.c new file mode 100644 index 0000000000..aa6db1cf8c --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/port-irix.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000 Denis Parker. All rights reserved. + * Copyright (c) 2000 Michael Stone. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +#if defined(WITH_IRIX_PROJECT) || \ + defined(WITH_IRIX_JOBS) || \ + defined(WITH_IRIX_ARRAY) + +#ifdef WITH_IRIX_PROJECT +# include +#endif /* WITH_IRIX_PROJECT */ +#ifdef WITH_IRIX_JOBS +# include +#endif +#ifdef WITH_IRIX_AUDIT +# include +#endif /* WITH_IRIX_AUDIT */ + +void +irix_setusercontext(struct passwd *pw) +{ +#ifdef WITH_IRIX_PROJECT + prid_t projid; +#endif +#ifdef WITH_IRIX_JOBS + jid_t jid = 0; +#elif defined(WITH_IRIX_ARRAY) + int jid = 0; +#endif + +#ifdef WITH_IRIX_JOBS + jid = jlimit_startjob(pw->pw_name, pw->pw_uid, "interactive"); + if (jid == -1) + fatal("Failed to create job container: %.100s", + strerror(errno)); +#endif /* WITH_IRIX_JOBS */ +#ifdef WITH_IRIX_ARRAY + /* initialize array session */ + if (jid == 0 && newarraysess() != 0) + fatal("Failed to set up new array session: %.100s", + strerror(errno)); +#endif /* WITH_IRIX_ARRAY */ +#ifdef WITH_IRIX_PROJECT + /* initialize irix project info */ + if ((projid = getdfltprojuser(pw->pw_name)) == -1) { + debug("Failed to get project id, using projid 0"); + projid = 0; + } + if (setprid(projid)) + fatal("Failed to initialize project %d for %s: %.100s", + (int)projid, pw->pw_name, strerror(errno)); +#endif /* WITH_IRIX_PROJECT */ +#ifdef WITH_IRIX_AUDIT + if (sysconf(_SC_AUDIT)) { + debug("Setting sat id to %d", (int) pw->pw_uid); + if (satsetid(pw->pw_uid)) + debug("error setting satid: %.100s", strerror(errno)); + } +#endif /* WITH_IRIX_AUDIT */ +} + + +#endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/port-irix.h b/crypto/openssh-3.9p1/openbsd-compat/port-irix.h new file mode 100644 index 0000000000..67c4863078 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/port-irix.h @@ -0,0 +1,39 @@ +/* $Id: port-irix.h,v 1.4 2003/08/29 16:59:52 mouring Exp $ */ + +/* + * Copyright (c) 2000 Denis Parker. All rights reserved. + * Copyright (c) 2000 Michael Stone. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PORT_IRIX_H +#define _PORT_IRIX_H + +#if defined(WITH_IRIX_PROJECT) || \ + defined(WITH_IRIX_JOBS) || \ + defined(WITH_IRIX_ARRAY) + +void irix_setusercontext(struct passwd *pw); + +#endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ + +#endif /* ! _PORT_IRIX_H */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/readpassphrase.c b/crypto/openssh-3.9p1/openbsd-compat/readpassphrase.c new file mode 100644 index 0000000000..4ee1be5de2 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/readpassphrase.c @@ -0,0 +1,186 @@ +/* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */ + +/* $OpenBSD: readpassphrase.c,v 1.16 2003/06/17 21:56:23 millert Exp $ */ + +/* + * Copyright (c) 2000-2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$OpenBSD: readpassphrase.c,v 1.16 2003/06/17 21:56:23 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "includes.h" + +#ifndef HAVE_READPASSPHRASE + +#include +#include + +#ifdef TCSASOFT +# define _T_FLUSH (TCSAFLUSH|TCSASOFT) +#else +# define _T_FLUSH (TCSAFLUSH) +#endif + +/* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ +#if !defined(_POSIX_VDISABLE) && defined(VDISABLE) +# define _POSIX_VDISABLE VDISABLE +#endif + +static volatile sig_atomic_t signo; + +static void handler(int); + +char * +readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) +{ + ssize_t nr; + int input, output, save_errno; + char ch, *p, *end; + struct termios term, oterm; + struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; + struct sigaction savetstp, savettin, savettou, savepipe; + + /* I suppose we could alloc on demand in this case (XXX). */ + if (bufsiz == 0) { + errno = EINVAL; + return(NULL); + } + +restart: + signo = 0; + /* + * Read and write to /dev/tty if available. If not, read from + * stdin and write to stderr unless a tty is required. + */ + if ((flags & RPP_STDIN) || + (input = output = open(_PATH_TTY, O_RDWR)) == -1) { + if (flags & RPP_REQUIRE_TTY) { + errno = ENOTTY; + return(NULL); + } + input = STDIN_FILENO; + output = STDERR_FILENO; + } + + /* + * Catch signals that would otherwise cause the user to end + * up with echo turned off in the shell. Don't worry about + * things like SIGXCPU and SIGVTALRM for now. + */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; /* don't restart system calls */ + sa.sa_handler = handler; + (void)sigaction(SIGALRM, &sa, &savealrm); + (void)sigaction(SIGHUP, &sa, &savehup); + (void)sigaction(SIGINT, &sa, &saveint); + (void)sigaction(SIGPIPE, &sa, &savepipe); + (void)sigaction(SIGQUIT, &sa, &savequit); + (void)sigaction(SIGTERM, &sa, &saveterm); + (void)sigaction(SIGTSTP, &sa, &savetstp); + (void)sigaction(SIGTTIN, &sa, &savettin); + (void)sigaction(SIGTTOU, &sa, &savettou); + + /* Turn off echo if possible. */ + if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { + memcpy(&term, &oterm, sizeof(term)); + if (!(flags & RPP_ECHO_ON)) + term.c_lflag &= ~(ECHO | ECHONL); +#ifdef VSTATUS + if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) + term.c_cc[VSTATUS] = _POSIX_VDISABLE; +#endif + (void)tcsetattr(input, _T_FLUSH, &term); + } else { + memset(&term, 0, sizeof(term)); + term.c_lflag |= ECHO; + memset(&oterm, 0, sizeof(oterm)); + oterm.c_lflag |= ECHO; + } + + if (!(flags & RPP_STDIN)) + (void)write(output, prompt, strlen(prompt)); + end = buf + bufsiz - 1; + for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) { + if (p < end) { + if ((flags & RPP_SEVENBIT)) + ch &= 0x7f; + if (isalpha(ch)) { + if ((flags & RPP_FORCELOWER)) + ch = tolower(ch); + if ((flags & RPP_FORCEUPPER)) + ch = toupper(ch); + } + *p++ = ch; + } + } + *p = '\0'; + save_errno = errno; + if (!(term.c_lflag & ECHO)) + (void)write(output, "\n", 1); + + /* Restore old terminal settings and signals. */ + if (memcmp(&term, &oterm, sizeof(term)) != 0) + (void)tcsetattr(input, _T_FLUSH, &oterm); + (void)sigaction(SIGALRM, &savealrm, NULL); + (void)sigaction(SIGHUP, &savehup, NULL); + (void)sigaction(SIGINT, &saveint, NULL); + (void)sigaction(SIGQUIT, &savequit, NULL); + (void)sigaction(SIGPIPE, &savepipe, NULL); + (void)sigaction(SIGTERM, &saveterm, NULL); + (void)sigaction(SIGTSTP, &savetstp, NULL); + (void)sigaction(SIGTTIN, &savettin, NULL); + if (input != STDIN_FILENO) + (void)close(input); + + /* + * If we were interrupted by a signal, resend it to ourselves + * now that we have restored the signal handlers. + */ + if (signo) { + kill(getpid(), signo); + switch (signo) { + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + goto restart; + } + } + + errno = save_errno; + return(nr == -1 ? NULL : buf); +} + +#if 0 +char * +getpass(const char *prompt) +{ + static char buf[_PASSWORD_LEN + 1]; + + return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF)); +} +#endif + +static void handler(int s) +{ + + signo = s; +} +#endif /* HAVE_READPASSPHRASE */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/readpassphrase.h b/crypto/openssh-3.9p1/openbsd-compat/readpassphrase.h new file mode 100644 index 0000000000..178edf3461 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/readpassphrase.h @@ -0,0 +1,51 @@ +/* OPENBSD ORIGINAL: include/readpassphrase.h */ + +/* $OpenBSD: readpassphrase.h,v 1.3 2002/06/28 12:32:22 millert Exp $ */ + +/* + * Copyright (c) 2000 Todd C. Miller + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _READPASSPHRASE_H_ +#define _READPASSPHRASE_H_ + +#include "includes.h" + +#ifndef HAVE_READPASSPHRASE + +#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ +#define RPP_ECHO_ON 0x01 /* Leave echo on. */ +#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ +#define RPP_FORCELOWER 0x04 /* Force input to lower case. */ +#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ +#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ +#define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */ + +char * readpassphrase(const char *, char *, size_t, int); + +#endif /* HAVE_READPASSPHRASE */ + +#endif /* !_READPASSPHRASE_H_ */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/realpath.c b/crypto/openssh-3.9p1/openbsd-compat/realpath.c new file mode 100644 index 0000000000..218fbecb2b --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/realpath.c @@ -0,0 +1,171 @@ +/* OPENBSD ORIGINAL: lib/libc/stdlib/realpath.c */ + +/* + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry. + * + * 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. 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. + */ + +#include "includes.h" + +#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: realpath.c,v 1.10 2003/08/01 21:04:59 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +#include +#include +#include +#include +#include + +/* + * MAXSYMLINKS + */ +#ifndef MAXSYMLINKS +#define MAXSYMLINKS 5 +#endif + +/* + * char *realpath(const char *path, char resolved_path[MAXPATHLEN]); + * + * Find the real name of path, by removing all ".", ".." and symlink + * components. Returns (resolved) on success, or (NULL) on failure, + * in which case the path which caused trouble is left in (resolved). + */ +char * +realpath(const char *path, char *resolved) +{ + struct stat sb; + int fd, n, needslash, serrno = 0; + char *p, *q, wbuf[MAXPATHLEN], start[MAXPATHLEN]; + int symlinks = 0; + + /* Save the starting point. */ + getcwd(start,MAXPATHLEN); + if ((fd = open(".", O_RDONLY)) < 0) { + (void)strlcpy(resolved, ".", MAXPATHLEN); + return (NULL); + } + close(fd); + + /* Convert "." -> "" to optimize away a needless lstat() and chdir() */ + if (path[0] == '.' && path[1] == '\0') + path = ""; + + /* + * Find the dirname and basename from the path to be resolved. + * Change directory to the dirname component. + * lstat the basename part. + * if it is a symlink, read in the value and loop. + * if it is a directory, then change to that directory. + * get the current directory name and append the basename. + */ + strlcpy(resolved, path, MAXPATHLEN); +loop: + q = strrchr(resolved, '/'); + if (q != NULL) { + p = q + 1; + if (q == resolved) + q = "/"; + else { + do { + --q; + } while (q > resolved && *q == '/'); + q[1] = '\0'; + q = resolved; + } + if (chdir(q) < 0) + goto err1; + } else + p = resolved; + + /* Deal with the last component. */ + if (*p != '\0' && lstat(p, &sb) == 0) { + if (S_ISLNK(sb.st_mode)) { + if (++symlinks > MAXSYMLINKS) { + serrno = ELOOP; + goto err1; + } + n = readlink(p, resolved, MAXPATHLEN-1); + if (n < 0) + goto err1; + resolved[n] = '\0'; + goto loop; + } + if (S_ISDIR(sb.st_mode)) { + if (chdir(p) < 0) + goto err1; + p = ""; + } + } + + /* + * Save the last component name and get the full pathname of + * the current directory. + */ + (void)strlcpy(wbuf, p, sizeof wbuf); + if (getcwd(resolved, MAXPATHLEN) == 0) + goto err1; + + /* + * Join the two strings together, ensuring that the right thing + * happens if the last component is empty, or the dirname is root. + */ + if (resolved[0] == '/' && resolved[1] == '\0') + needslash = 0; + else + needslash = 1; + + if (*wbuf) { + if (strlen(resolved) + strlen(wbuf) + needslash >= MAXPATHLEN) { + serrno = ENAMETOOLONG; + goto err1; + } + if (needslash) + strlcat(resolved, "/", MAXPATHLEN); + strlcat(resolved, wbuf, MAXPATHLEN); + } + + /* Go back to where we came from. */ + if (chdir(start) < 0) { + serrno = errno; + goto err2; + } + return (resolved); + +err1: chdir(start); +err2: errno = serrno; + return (NULL); +} +#endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/rresvport.c b/crypto/openssh-3.9p1/openbsd-compat/rresvport.c new file mode 100644 index 0000000000..75167065ca --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/rresvport.c @@ -0,0 +1,103 @@ +/* OPENBSD ORIGINAL: lib/libc/net/rresvport.c */ + +/* + * Copyright (c) 1995, 1996, 1998 Theo de Raadt. All rights reserved. + * Copyright (c) 1983, 1993, 1994 + * 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. 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. + */ + +#include "includes.h" + +#ifndef HAVE_RRESVPORT_AF + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: rresvport.c,v 1.6 2003/06/03 02:11:35 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "includes.h" + +#if 0 +int +rresvport(alport) + int *alport; +{ + return rresvport_af(alport, AF_INET); +} +#endif + +int +rresvport_af(int *alport, sa_family_t af) +{ + struct sockaddr_storage ss; + struct sockaddr *sa; + u_int16_t *portp; + int s; + socklen_t salen; + + memset(&ss, '\0', sizeof ss); + sa = (struct sockaddr *)&ss; + + switch (af) { + case AF_INET: + salen = sizeof(struct sockaddr_in); + portp = &((struct sockaddr_in *)sa)->sin_port; + break; + case AF_INET6: + salen = sizeof(struct sockaddr_in6); + portp = &((struct sockaddr_in6 *)sa)->sin6_port; + break; + default: + errno = EPFNOSUPPORT; + return (-1); + } + sa->sa_family = af; + + s = socket(af, SOCK_STREAM, 0); + if (s < 0) + return (-1); + + *portp = htons(*alport); + if (*alport < IPPORT_RESERVED - 1) { + if (bind(s, sa, salen) >= 0) + return (s); + if (errno != EADDRINUSE) { + (void)close(s); + return (-1); + } + } + + *portp = 0; + sa->sa_family = af; + if (bindresvport_sa(s, sa) == -1) { + (void)close(s); + return (-1); + } + *alport = ntohs(*portp); + return (s); +} + +#endif /* HAVE_RRESVPORT_AF */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/setenv.c b/crypto/openssh-3.9p1/openbsd-compat/setenv.c new file mode 100644 index 0000000000..c3a86c651c --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/setenv.c @@ -0,0 +1,165 @@ +/* OPENBSD ORIGINAL: lib/libc/stdlib/setenv.c */ + +/* + * Copyright (c) 1987 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. 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. + */ + +#include "includes.h" +#if !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: setenv.c,v 1.6 2003/06/02 20:18:38 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +char *__findenv(const char *name, int *offset); + +/* + * __findenv -- + * Returns pointer to value associated with name, if any, else NULL. + * Sets offset to be the offset of the name/value combination in the + * environmental array, for use by setenv(3) and unsetenv(3). + * Explicitly removes '=' in argument name. + * + * This routine *should* be a static; don't use it. + */ +char * +__findenv(name, offset) + register const char *name; + int *offset; +{ + extern char **environ; + register int len, i; + register const char *np; + register char **p, *cp; + + if (name == NULL || environ == NULL) + return (NULL); + for (np = name; *np && *np != '='; ++np) + ; + len = np - name; + for (p = environ; (cp = *p) != NULL; ++p) { + for (np = name, i = len; i && *cp; i--) + if (*cp++ != *np++) + break; + if (i == 0 && *cp++ == '=') { + *offset = p - environ; + return (cp); + } + } + return (NULL); +} + +#ifndef HAVE_SETENV +/* + * setenv -- + * Set the value of the environmental variable "name" to be + * "value". If rewrite is set, replace any current value. + */ +int +setenv(name, value, rewrite) + register const char *name; + register const char *value; + int rewrite; +{ + extern char **environ; + static int alloced; /* if allocated space before */ + register char *C; + int l_value, offset; + + if (*value == '=') /* no `=' in value */ + ++value; + l_value = strlen(value); + if ((C = __findenv(name, &offset))) { /* find if already exists */ + if (!rewrite) + return (0); + if (strlen(C) >= l_value) { /* old larger; copy over */ + while ((*C++ = *value++)) + ; + return (0); + } + } else { /* create new slot */ + register int cnt; + register char **P; + + for (P = environ, cnt = 0; *P; ++P, ++cnt); + if (alloced) { /* just increase size */ + P = (char **)realloc((void *)environ, + (size_t)(sizeof(char *) * (cnt + 2))); + if (!P) + return (-1); + environ = P; + } + else { /* get new space */ + alloced = 1; /* copy old entries into it */ + P = (char **)malloc((size_t)(sizeof(char *) * + (cnt + 2))); + if (!P) + return (-1); + memmove(P, environ, cnt * sizeof(char *)); + environ = P; + } + environ[cnt + 1] = NULL; + offset = cnt; + } + for (C = (char *)name; *C && *C != '='; ++C); /* no `=' in name */ + if (!(environ[offset] = /* name + `=' + value */ + malloc((size_t)((int)(C - name) + l_value + 2)))) + return (-1); + for (C = environ[offset]; (*C = *name++) && *C != '='; ++C) + ; + for (*C++ = '='; (*C++ = *value++); ) + ; + return (0); +} +#endif /* HAVE_SETENV */ + +#ifndef HAVE_UNSETENV +/* + * unsetenv(name) -- + * Delete environmental variable "name". + */ +void +unsetenv(name) + const char *name; +{ + extern char **environ; + register char **P; + int offset; + char *__findenv(); + + while (__findenv(name, &offset)) /* if set multiple times */ + for (P = &environ[offset];; ++P) + if (!(*P = *(P + 1))) + break; +} +#endif /* HAVE_UNSETENV */ + +#endif /* !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/setproctitle.c b/crypto/openssh-3.9p1/openbsd-compat/setproctitle.c new file mode 100644 index 0000000000..6e2b19bb4f --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/setproctitle.c @@ -0,0 +1,157 @@ +/* Based on conf.c from UCB sendmail 8.8.8 */ + +/* + * Copyright 2003 Damien Miller + * Copyright (c) 1983, 1995-1997 Eric P. Allman + * Copyright (c) 1988, 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. 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. + */ + +#include "includes.h" + +#ifndef HAVE_SETPROCTITLE + +#include +#ifdef HAVE_SYS_PSTAT_H +#include +#endif + +#define SPT_NONE 0 /* don't use it at all */ +#define SPT_PSTAT 1 /* use pstat(PSTAT_SETCMD, ...) */ +#define SPT_REUSEARGV 2 /* cover argv with title information */ + +#ifndef SPT_TYPE +# define SPT_TYPE SPT_NONE +#endif + +#ifndef SPT_PADCHAR +# define SPT_PADCHAR '\0' +#endif + +#if SPT_TYPE == SPT_REUSEARGV +static char *argv_start = NULL; +static size_t argv_env_len = 0; +#endif + +#endif /* HAVE_SETPROCTITLE */ + +void +compat_init_setproctitle(int argc, char *argv[]) +{ +#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV + extern char **environ; + char *lastargv = NULL; + char **envp = environ; + int i; + + /* + * NB: This assumes that argv has already been copied out of the + * way. This is true for sshd, but may not be true for other + * programs. Beware. + */ + + if (argc == 0 || argv[0] == NULL) + return; + + /* Fail if we can't allocate room for the new environment */ + for (i = 0; envp[i] != NULL; i++) + ; + if ((environ = malloc(sizeof(*environ) * (i + 1))) == NULL) { + environ = envp; /* put it back */ + return; + } + + /* + * Find the last argv string or environment variable within + * our process memory area. + */ + for (i = 0; i < argc; i++) { + if (lastargv == NULL || lastargv + 1 == argv[i]) + lastargv = argv[i] + strlen(argv[i]); + } + for (i = 0; envp[i] != NULL; i++) { + if (lastargv + 1 == envp[i]) + lastargv = envp[i] + strlen(envp[i]); + } + + argv[1] = NULL; + argv_start = argv[0]; + argv_env_len = lastargv - argv[0] - 1; + + /* + * Copy environment + * XXX - will truncate env on strdup fail + */ + for (i = 0; envp[i] != NULL; i++) + environ[i] = strdup(envp[i]); + environ[i] = NULL; +#endif /* SPT_REUSEARGV */ +} + +#ifndef HAVE_SETPROCTITLE +void +setproctitle(const char *fmt, ...) +{ +#if SPT_TYPE != SPT_NONE + va_list ap; + char buf[1024]; + size_t len; + extern char *__progname; +#if SPT_TYPE == SPT_PSTAT + union pstun pst; +#endif + +#if SPT_TYPE == SPT_REUSEARGV + if (argv_env_len <= 0) + return; +#endif + + strlcpy(buf, __progname, sizeof(buf)); + + va_start(ap, fmt); + if (fmt != NULL) { + len = strlcat(buf, ": ", sizeof(buf)); + if (len < sizeof(buf)) + vsnprintf(buf + len, sizeof(buf) - len , fmt, ap); + } + va_end(ap); + +#if SPT_TYPE == SPT_PSTAT + pst.pst_command = buf; + pstat(PSTAT_SETCMD, pst, strlen(buf), 0, 0); +#elif SPT_TYPE == SPT_REUSEARGV +/* debug("setproctitle: copy \"%s\" into len %d", + buf, argv_env_len); */ + len = strlcpy(argv_start, buf, argv_env_len); + for(; len < argv_env_len; len++) + argv_start[len] = SPT_PADCHAR; +#endif + +#endif /* SPT_NONE */ +} + +#endif /* HAVE_SETPROCTITLE */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/sigact.c b/crypto/openssh-3.9p1/openbsd-compat/sigact.c new file mode 100644 index 0000000000..2772ac574a --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/sigact.c @@ -0,0 +1,104 @@ +/* OPENBSD ORIGINAL: lib/libcurses/base/sigaction.c */ + +/* $OpenBSD: sigaction.c,v 1.3 1999/06/27 08:14:21 millert Exp $ */ + +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Zeyd M. Ben-Halim 1992,1995 * + * and: Eric S. Raymond * + ****************************************************************************/ + +#include "includes.h" +#include +#include "sigact.h" + +/* This file provides sigaction() emulation using sigvec() */ +/* Use only if this is non POSIX system */ + +#if !HAVE_SIGACTION && HAVE_SIGVEC + +int +sigaction(int sig, struct sigaction *sigact, struct sigaction *osigact) +{ + return sigvec(sig, &(sigact->sv), &(osigact->sv)); +} + +int +sigemptyset (sigset_t * mask) +{ + *mask = 0; + return 0; +} + +int +sigprocmask (int mode, sigset_t * mask, sigset_t * omask) +{ + sigset_t current = sigsetmask(0); + + if (omask) *omask = current; + + if (mode==SIG_BLOCK) + current |= *mask; + else if (mode==SIG_UNBLOCK) + current &= ~*mask; + else if (mode==SIG_SETMASK) + current = *mask; + + sigsetmask(current); + return 0; +} + +int +sigsuspend (sigset_t * mask) +{ + return sigpause(*mask); +} + +int +sigdelset (sigset_t * mask, int sig) +{ + *mask &= ~sigmask(sig); + return 0; +} + +int +sigaddset (sigset_t * mask, int sig) +{ + *mask |= sigmask(sig); + return 0; +} + +int +sigismember (sigset_t * mask, int sig) +{ + return (*mask & sigmask(sig)) != 0; +} + +#endif diff --git a/crypto/openssh-3.9p1/openbsd-compat/sigact.h b/crypto/openssh-3.9p1/openbsd-compat/sigact.h new file mode 100644 index 0000000000..b37c1f84a8 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/sigact.h @@ -0,0 +1,88 @@ +/* $OpenBSD: SigAction.h,v 1.2 1999/06/27 08:15:19 millert Exp $ */ + +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Zeyd M. Ben-Halim 1992,1995 * + * and: Eric S. Raymond * + ****************************************************************************/ + +/* + * $From: SigAction.h,v 1.5 1999/06/19 23:00:54 tom Exp $ + * + * This file exists to handle non-POSIX systems which don't have , + * and usually no sigaction() nor + */ + +#ifndef _SIGACTION_H +#define _SIGACTION_H + +#if !defined(HAVE_SIGACTION) && defined(HAVE_SIGVEC) + +#undef SIG_BLOCK +#define SIG_BLOCK 00 + +#undef SIG_UNBLOCK +#define SIG_UNBLOCK 01 + +#undef SIG_SETMASK +#define SIG_SETMASK 02 + +/* + * is in the Linux 1.2.8 + gcc 2.7.0 configuration, + * and is useful for testing this header file. + */ +#if HAVE_BSD_SIGNAL_H +# include +#endif + +struct sigaction +{ + struct sigvec sv; +}; + +typedef unsigned long sigset_t; + +#undef sa_mask +#define sa_mask sv.sv_mask +#undef sa_handler +#define sa_handler sv.sv_handler +#undef sa_flags +#define sa_flags sv.sv_flags + +int sigaction(int sig, struct sigaction *sigact, struct sigaction *osigact); +int sigprocmask (int how, sigset_t *mask, sigset_t *omask); +int sigemptyset (sigset_t *mask); +int sigsuspend (sigset_t *mask); +int sigdelset (sigset_t *mask, int sig); +int sigaddset (sigset_t *mask, int sig); + +#endif /* !defined(HAVE_SIGACTION) && defined(HAVE_SIGVEC) */ + +#endif /* !defined(_SIGACTION_H) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/strlcat.c b/crypto/openssh-3.9p1/openbsd-compat/strlcat.c new file mode 100644 index 0000000000..70f01cb2a6 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/strlcat.c @@ -0,0 +1,66 @@ +/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ + +/* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" +#ifndef HAVE_STRLCAT + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} + +#endif /* !HAVE_STRLCAT */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/strlcpy.c b/crypto/openssh-3.9p1/openbsd-compat/strlcpy.c new file mode 100644 index 0000000000..ccfa12a0a5 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/strlcpy.c @@ -0,0 +1,62 @@ +/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ + +/* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" +#ifndef HAVE_STRLCPY + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +#endif /* !HAVE_STRLCPY */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/strmode.c b/crypto/openssh-3.9p1/openbsd-compat/strmode.c new file mode 100644 index 0000000000..ea8d515e38 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/strmode.c @@ -0,0 +1,156 @@ +/* OPENBSD ORIGINAL: lib/libc/string/strmode.c */ + +/*- + * Copyright (c) 1990 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. 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. + */ + +#include "includes.h" +#ifndef HAVE_STRMODE + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strmode.c,v 1.5 2003/06/11 21:08:16 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +/* XXX mode should be mode_t */ + +void +strmode(int mode, char *p) +{ + /* print type */ + switch (mode & S_IFMT) { + case S_IFDIR: /* directory */ + *p++ = 'd'; + break; + case S_IFCHR: /* character special */ + *p++ = 'c'; + break; + case S_IFBLK: /* block special */ + *p++ = 'b'; + break; + case S_IFREG: /* regular */ + *p++ = '-'; + break; + case S_IFLNK: /* symbolic link */ + *p++ = 'l'; + break; +#ifdef S_IFSOCK + case S_IFSOCK: /* socket */ + *p++ = 's'; + break; +#endif +#ifdef S_IFIFO + case S_IFIFO: /* fifo */ + *p++ = 'p'; + break; +#endif +#ifdef S_IFWHT + case S_IFWHT: /* whiteout */ + *p++ = 'w'; + break; +#endif + default: /* unknown */ + *p++ = '?'; + break; + } + /* usr */ + if (mode & S_IRUSR) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWUSR) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXUSR | S_ISUID)) { + case 0: + *p++ = '-'; + break; + case S_IXUSR: + *p++ = 'x'; + break; + case S_ISUID: + *p++ = 'S'; + break; + case S_IXUSR | S_ISUID: + *p++ = 's'; + break; + } + /* group */ + if (mode & S_IRGRP) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWGRP) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXGRP | S_ISGID)) { + case 0: + *p++ = '-'; + break; + case S_IXGRP: + *p++ = 'x'; + break; + case S_ISGID: + *p++ = 'S'; + break; + case S_IXGRP | S_ISGID: + *p++ = 's'; + break; + } + /* other */ + if (mode & S_IROTH) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWOTH) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXOTH | S_ISVTX)) { + case 0: + *p++ = '-'; + break; + case S_IXOTH: + *p++ = 'x'; + break; + case S_ISVTX: + *p++ = 'T'; + break; + case S_IXOTH | S_ISVTX: + *p++ = 't'; + break; + } + *p++ = ' '; /* will be a '+' if ACL's implemented */ + *p = '\0'; +} +#endif diff --git a/crypto/openssh-3.9p1/openbsd-compat/strsep.c b/crypto/openssh-3.9p1/openbsd-compat/strsep.c new file mode 100644 index 0000000000..330d84ce15 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/strsep.c @@ -0,0 +1,87 @@ +/* OPENBSD ORIGINAL: lib/libc/string/strsep.c */ + +/* $OpenBSD: strsep.c,v 1.5 2003/06/11 21:08:16 deraadt Exp $ */ + +/*- + * Copyright (c) 1990, 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. 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. + */ + +#include "includes.h" + +#if !defined(HAVE_STRSEP) + +#include +#include + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93"; +#else +static char *rcsid = "$OpenBSD: strsep.c,v 1.5 2003/06/11 21:08:16 deraadt Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(char **stringp, const char *delim) +{ + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +#endif /* !defined(HAVE_STRSEP) */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/strtoul.c b/crypto/openssh-3.9p1/openbsd-compat/strtoul.c new file mode 100644 index 0000000000..24d0e253dd --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/strtoul.c @@ -0,0 +1,114 @@ +/* OPENBSD ORIGINAL: lib/libc/stdlib/strtoul.c */ + +/* + * Copyright (c) 1990 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. 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. + */ + +#include "includes.h" +#ifndef HAVE_STRTOUL + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strtoul.c,v 1.5 2003/06/02 20:18:38 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include + +/* + * Convert a string to an unsigned long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long +strtoul(nptr, endptr, base) + const char *nptr; + char **endptr; + register int base; +{ + register const char *s; + register unsigned long acc, cutoff; + register int c; + register int neg, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + s = nptr; + do { + c = (unsigned char) *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + cutoff = ULONG_MAX / (unsigned long)base; + cutlim = ULONG_MAX % (unsigned long)base; + for (acc = 0, any = 0;; c = (unsigned char) *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0) + continue; + if (acc > cutoff || acc == cutoff && c > cutlim) { + any = -1; + acc = ULONG_MAX; + errno = ERANGE; + } else { + any = 1; + acc *= (unsigned long)base; + acc += c; + } + } + if (neg && any > 0) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} +#endif /* !HAVE_STRTOUL */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/sys-queue.h b/crypto/openssh-3.9p1/openbsd-compat/sys-queue.h new file mode 100644 index 0000000000..c49a946509 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/sys-queue.h @@ -0,0 +1,593 @@ +/* OPENBSD ORIGINAL: sys/sys/queue.h */ + +/* $OpenBSD: queue.h,v 1.25 2004/04/08 16:08:21 henning Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 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. 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _FAKE_QUEUE_H_ +#define _FAKE_QUEUE_H_ + +/* + * Require for OS/X and other platforms that have old/broken/incomplete + * . + */ +#undef SLIST_HEAD +#undef SLIST_HEAD_INITIALIZER +#undef SLIST_ENTRY +#undef SLIST_FOREACH_PREVPTR +#undef SLIST_FIRST +#undef SLIST_END +#undef SLIST_EMPTY +#undef SLIST_NEXT +#undef SLIST_FOREACH +#undef SLIST_INIT +#undef SLIST_INSERT_AFTER +#undef SLIST_INSERT_HEAD +#undef SLIST_REMOVE_HEAD +#undef SLIST_REMOVE +#undef SLIST_REMOVE_NEXT +#undef LIST_HEAD +#undef LIST_HEAD_INITIALIZER +#undef LIST_ENTRY +#undef LIST_FIRST +#undef LIST_END +#undef LIST_EMPTY +#undef LIST_NEXT +#undef LIST_FOREACH +#undef LIST_INIT +#undef LIST_INSERT_AFTER +#undef LIST_INSERT_BEFORE +#undef LIST_INSERT_HEAD +#undef LIST_REMOVE +#undef LIST_REPLACE +#undef SIMPLEQ_HEAD +#undef SIMPLEQ_HEAD_INITIALIZER +#undef SIMPLEQ_ENTRY +#undef SIMPLEQ_FIRST +#undef SIMPLEQ_END +#undef SIMPLEQ_EMPTY +#undef SIMPLEQ_NEXT +#undef SIMPLEQ_FOREACH +#undef SIMPLEQ_INIT +#undef SIMPLEQ_INSERT_HEAD +#undef SIMPLEQ_INSERT_TAIL +#undef SIMPLEQ_INSERT_AFTER +#undef SIMPLEQ_REMOVE_HEAD +#undef TAILQ_HEAD +#undef TAILQ_HEAD_INITIALIZER +#undef TAILQ_ENTRY +#undef TAILQ_FIRST +#undef TAILQ_END +#undef TAILQ_NEXT +#undef TAILQ_LAST +#undef TAILQ_PREV +#undef TAILQ_EMPTY +#undef TAILQ_FOREACH +#undef TAILQ_FOREACH_REVERSE +#undef TAILQ_INIT +#undef TAILQ_INSERT_HEAD +#undef TAILQ_INSERT_TAIL +#undef TAILQ_INSERT_AFTER +#undef TAILQ_INSERT_BEFORE +#undef TAILQ_REMOVE +#undef TAILQ_REPLACE +#undef CIRCLEQ_HEAD +#undef CIRCLEQ_HEAD_INITIALIZER +#undef CIRCLEQ_ENTRY +#undef CIRCLEQ_FIRST +#undef CIRCLEQ_LAST +#undef CIRCLEQ_END +#undef CIRCLEQ_NEXT +#undef CIRCLEQ_PREV +#undef CIRCLEQ_EMPTY +#undef CIRCLEQ_FOREACH +#undef CIRCLEQ_FOREACH_REVERSE +#undef CIRCLEQ_INIT +#undef CIRCLEQ_INSERT_AFTER +#undef CIRCLEQ_INSERT_BEFORE +#undef CIRCLEQ_INSERT_HEAD +#undef CIRCLEQ_INSERT_TAIL +#undef CIRCLEQ_REMOVE +#undef CIRCLEQ_REPLACE + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != SLIST_END(head); \ + (varp) = &SLIST_NEXT((var), field)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_NEXT(head, elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while( curelm->field.sle_next != (elm) ) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \ + if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ +} while (0) + +#endif /* !_FAKE_QUEUE_H_ */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/sys-tree.h b/crypto/openssh-3.9p1/openbsd-compat/sys-tree.h new file mode 100644 index 0000000000..73cfbe72a6 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/sys-tree.h @@ -0,0 +1,679 @@ +/* OPENBSD ORIGINAL: sys/sys/tree.h */ + +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root))) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-back tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ +void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +struct type *name##_RB_REMOVE(struct name *, struct type *); \ +struct type *name##_RB_INSERT(struct name *, struct type *); \ +struct type *name##_RB_FIND(struct name *, struct type *); \ +struct type *name##_RB_NEXT(struct name *, struct type *); \ +struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ +void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)))\ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)))\ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field))) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field))); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +struct type * \ +name##_RB_NEXT(struct name *head, struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(x, y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(head, x)) + +#endif /* _SYS_TREE_H_ */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/vis.c b/crypto/openssh-3.9p1/openbsd-compat/vis.c new file mode 100644 index 0000000000..1fb7a01e3a --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/vis.c @@ -0,0 +1,239 @@ +/* OPENBSD ORIGINAL: lib/libc/gen/vis.c */ + +/*- + * Copyright (c) 1989, 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. 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. + */ +#include "includes.h" +#if !defined(HAVE_STRNVIS) + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$OpenBSD: vis.c,v 1.12 2003/06/02 20:18:35 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +#include "vis.h" + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define isvisible(c) (((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \ + isgraph((u_char)(c))) || \ + ((flag & VIS_SP) == 0 && (c) == ' ') || \ + ((flag & VIS_TAB) == 0 && (c) == '\t') || \ + ((flag & VIS_NL) == 0 && (c) == '\n') || \ + ((flag & VIS_SAFE) && ((c) == '\b' || \ + (c) == '\007' || (c) == '\r' || \ + isgraph((u_char)(c))))) + +/* + * vis - visually encode characters + */ +char * +vis(dst, c, flag, nextc) + register char *dst; + int c, nextc; + register int flag; +{ + if (isvisible(c)) { + *dst++ = c; + if (c == '\\' && (flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + *dst = '\0'; + return (dst); + } + + if (flag & VIS_CSTYLE) { + switch(c) { + case '\n': + *dst++ = '\\'; + *dst++ = 'n'; + goto done; + case '\r': + *dst++ = '\\'; + *dst++ = 'r'; + goto done; + case '\b': + *dst++ = '\\'; + *dst++ = 'b'; + goto done; + case '\a': + *dst++ = '\\'; + *dst++ = 'a'; + goto done; + case '\v': + *dst++ = '\\'; + *dst++ = 'v'; + goto done; + case '\t': + *dst++ = '\\'; + *dst++ = 't'; + goto done; + case '\f': + *dst++ = '\\'; + *dst++ = 'f'; + goto done; + case ' ': + *dst++ = '\\'; + *dst++ = 's'; + goto done; + case '\0': + *dst++ = '\\'; + *dst++ = '0'; + if (isoctal(nextc)) { + *dst++ = '0'; + *dst++ = '0'; + } + goto done; + } + } + if (((c & 0177) == ' ') || (flag & VIS_OCTAL)) { + *dst++ = '\\'; + *dst++ = ((u_char)c >> 6 & 07) + '0'; + *dst++ = ((u_char)c >> 3 & 07) + '0'; + *dst++ = ((u_char)c & 07) + '0'; + goto done; + } + if ((flag & VIS_NOSLASH) == 0) + *dst++ = '\\'; + if (c & 0200) { + c &= 0177; + *dst++ = 'M'; + } + if (iscntrl(c)) { + *dst++ = '^'; + if (c == 0177) + *dst++ = '?'; + else + *dst++ = c + '@'; + } else { + *dst++ = '-'; + *dst++ = c; + } +done: + *dst = '\0'; + return (dst); +} + +/* + * strvis, strnvis, strvisx - visually encode characters from src into dst + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strnvis will write no more than siz-1 bytes (and will NULL terminate). + * The number of bytes needed to fully encode the string is returned. + * + * Strvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strvis(dst, src, flag) + register char *dst; + register const char *src; + int flag; +{ + register char c; + char *start; + + for (start = dst; (c = *src);) + dst = vis(dst, c, flag, *++src); + *dst = '\0'; + return (dst - start); +} + +int +strnvis(dst, src, siz, flag) + char *dst; + const char *src; + size_t siz; + int flag; +{ + char c; + char *start, *end; + char tbuf[5]; + int i; + + i = 0; + for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) { + if (isvisible(c)) { + i = 1; + *dst++ = c; + if (c == '\\' && (flag & VIS_NOSLASH) == 0) { + /* need space for the extra '\\' */ + if (dst < end) + *dst++ = '\\'; + else { + dst--; + i = 2; + break; + } + } + src++; + } else { + i = vis(tbuf, c, flag, *++src) - tbuf; + if (dst + i <= end) { + memcpy(dst, tbuf, i); + dst += i; + } else { + src--; + break; + } + } + } + if (siz > 0) + *dst = '\0'; + if (dst + i > end) { + /* adjust return value for truncation */ + while ((c = *src)) + dst += vis(tbuf, c, flag, *++src) - tbuf; + } + return (dst - start); +} + +int +strvisx(dst, src, len, flag) + register char *dst; + register const char *src; + register size_t len; + int flag; +{ + register char c; + char *start; + + for (start = dst; len > 1; len--) { + c = *src; + dst = vis(dst, c, flag, *++src); + } + if (len) + dst = vis(dst, *src, flag, '\0'); + *dst = '\0'; + return (dst - start); +} + +#endif diff --git a/crypto/openssh-3.9p1/openbsd-compat/vis.h b/crypto/openssh-3.9p1/openbsd-compat/vis.h new file mode 100644 index 0000000000..663355a240 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/vis.h @@ -0,0 +1,90 @@ +/* OPENBSD ORIGINAL: include/vis.h */ + +/* $OpenBSD: vis.h,v 1.6 2003/06/02 19:34:12 millert Exp $ */ +/* $NetBSD: vis.h,v 1.4 1994/10/26 00:56:41 cgd Exp $ */ + +/*- + * Copyright (c) 1990 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. 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. + * + * @(#)vis.h 5.9 (Berkeley) 4/3/91 + */ + +#include "includes.h" +#if !defined(HAVE_STRNVIS) + +#ifndef _VIS_H_ +#define _VIS_H_ + +#include +#include + +/* + * to select alternate encoding format + */ +#define VIS_OCTAL 0x01 /* use octal \ddd format */ +#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropriate */ + +/* + * to alter set of characters encoded (default is to encode all + * non-graphic except space, tab, and newline). + */ +#define VIS_SP 0x04 /* also encode space */ +#define VIS_TAB 0x08 /* also encode tab */ +#define VIS_NL 0x10 /* also encode newline */ +#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) +#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ + +/* + * other + */ +#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ + +/* + * unvis return codes + */ +#define UNVIS_VALID 1 /* character valid */ +#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ +#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ +#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ +#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ + +/* + * unvis flags + */ +#define UNVIS_END 1 /* no more characters */ + +char *vis(char *, int, int, int); +int strvis(char *, const char *, int); +int strnvis(char *, const char *, size_t, int); +int strvisx(char *, const char *, size_t, int); +int strunvis(char *, const char *); +int unvis(char *, char, int *, int); + +#endif /* !_VIS_H_ */ + +#endif /* !HAVE_STRNVIS */ diff --git a/crypto/openssh-3.9p1/openbsd-compat/xcrypt.c b/crypto/openssh-3.9p1/openbsd-compat/xcrypt.c new file mode 100644 index 0000000000..c3cea3c868 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/xcrypt.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2003 Ben Lindstrom. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" + +# ifdef HAVE_CRYPT_H +# include +# endif + +# ifdef __hpux +# include +# include +# endif + +# ifdef HAVE_SECUREWARE +# include +# include +# include +# endif + +# if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) +# include +# endif + +# if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW) +# include +# include +# include +# endif + +# if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) +# include "md5crypt.h" +# endif + +char * +xcrypt(const char *password, const char *salt) +{ + char *crypted; + +# ifdef HAVE_MD5_PASSWORDS + if (is_md5_salt(salt)) + crypted = md5_crypt(password, salt); + else + crypted = crypt(password, salt); +# elif defined(__hpux) && !defined(HAVE_SECUREWARE) + if (iscomsec()) + crypted = bigcrypt(password, salt); + else + crypted = crypt(password, salt); +# elif defined(HAVE_SECUREWARE) + crypted = bigcrypt(password, salt); +# else + crypted = crypt(password, salt); +# endif + + return crypted; +} + +/* + * Handle shadowed password systems in a cleaner way for portable + * version. + */ + +char * +shadow_pw(struct passwd *pw) +{ + char *pw_password = pw->pw_passwd; + +# if defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) + struct spwd *spw = getspnam(pw->pw_name); + + if (spw != NULL) + pw_password = spw->sp_pwdp; +# endif +# if defined(HAVE_GETPWANAM) && !defined(DISABLE_SHADOW) + struct passwd_adjunct *spw; + if (issecure() && (spw = getpwanam(pw->pw_name)) != NULL) + pw_password = spw->pwa_passwd; +# elif defined(HAVE_SECUREWARE) + struct pr_passwd *spw = getprpwnam(pw->pw_name); + + if (spw != NULL) + pw_password = spw->ufld.fd_encrypt; +# endif + + return pw_password; +} diff --git a/crypto/openssh-3.9p1/openbsd-compat/xmmap.c b/crypto/openssh-3.9p1/openbsd-compat/xmmap.c new file mode 100644 index 0000000000..c8d59dee04 --- /dev/null +++ b/crypto/openssh-3.9p1/openbsd-compat/xmmap.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2002 Tim Rice. All rights reserved. + * MAP_FAILED code by Solar Designer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* $Id: xmmap.c,v 1.5 2004/08/14 13:55:38 dtucker Exp $ */ + +#include "includes.h" + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#include "log.h" + +void *xmmap(size_t size) +{ + void *address; + +#ifdef HAVE_MMAP +# ifdef MAP_ANON + address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_SHARED, + -1, (off_t)0); +# else + address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED, + open("/dev/zero", O_RDWR), (off_t)0); +# endif + +#define MM_SWAP_TEMPLATE "/var/run/sshd.mm.XXXXXXXX" + if (address == MAP_FAILED) { + char tmpname[sizeof(MM_SWAP_TEMPLATE)] = MM_SWAP_TEMPLATE; + int tmpfd; + mode_t old_umask; + + old_umask = umask(0177); + tmpfd = mkstemp(tmpname); + umask(old_umask); + if (tmpfd == -1) + fatal("mkstemp(\"%s\"): %s", + MM_SWAP_TEMPLATE, strerror(errno)); + unlink(tmpname); + ftruncate(tmpfd, size); + address = mmap(NULL, size, PROT_WRITE|PROT_READ, MAP_SHARED, + tmpfd, (off_t)0); + close(tmpfd); + } + + return (address); +#else + fatal("%s: UsePrivilegeSeparation=yes and Compression=yes not supported", + __func__); +#endif /* HAVE_MMAP */ + +} + diff --git a/crypto/openssh-3.9p1/opensshd.init.in b/crypto/openssh-3.9p1/opensshd.init.in new file mode 100644 index 0000000000..ffa7cdac21 --- /dev/null +++ b/crypto/openssh-3.9p1/opensshd.init.in @@ -0,0 +1,82 @@ +#!/sbin/sh +# Donated code that was put under PD license. +# +# Stripped PRNGd out of it for the time being. + +umask 022 + +CAT=@CAT@ +KILL=@KILL@ + +prefix=@prefix@ +sysconfdir=@sysconfdir@ +piddir=@piddir@ + +SSHD=$prefix/sbin/sshd +PIDFILE=$piddir/sshd.pid +SSH_KEYGEN=$prefix/bin/ssh-keygen +HOST_KEY_RSA1=$sysconfdir/ssh_host_key +HOST_KEY_DSA=$sysconfdir/ssh_host_dsa_key +HOST_KEY_RSA=$sysconfdir/ssh_host_rsa_key + + +checkkeys() { + if [ ! -f $HOST_KEY_RSA1 ]; then + ${SSH_KEYGEN} -t rsa1 -f ${HOST_KEY_RSA1} -N "" + fi + if [ ! -f $HOST_KEY_DSA ]; then + ${SSH_KEYGEN} -t dsa -f ${HOST_KEY_DSA} -N "" + fi + if [ ! -f $HOST_KEY_RSA ]; then + ${SSH_KEYGEN} -t rsa -f ${HOST_KEY_RSA} -N "" + fi +} + +stop_service() { + if [ -r $PIDFILE -a ! -z ${PIDFILE} ]; then + PID=`${CAT} ${PIDFILE}` + fi + if [ ${PID:=0} -gt 1 -a ! "X$PID" = "X " ]; then + ${KILL} ${PID} + else + echo "Unable to read PID file" + fi +} + +start_service() { + # XXX We really should check if the service is already going, but + # XXX we will opt out at this time. - Bal + + # Check to see if we have keys that need to be made + checkkeys + + # Start SSHD + echo "starting $SSHD... \c" ; $SSHD + + sshd_rc=$? + if [ $sshd_rc -ne 0 ]; then + echo "$0: Error ${sshd_rc} starting ${SSHD}... bailing." + exit $sshd_rc + fi + echo done. +} + +case $1 in + +'start') + start_service + ;; + +'stop') + stop_service + ;; + +'restart') + stop_service + start_service + ;; + +*) + echo "$0: usage: $0 {start|stop|restart}" + ;; +esac diff --git a/crypto/openssh-3.9p1/packet.c b/crypto/openssh-3.9p1/packet.c new file mode 100644 index 0000000000..82a5694045 --- /dev/null +++ b/crypto/openssh-3.9p1/packet.c @@ -0,0 +1,1522 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * 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. + * + * 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". + * + * + * SSH2 packet format added by Markus Friedl. + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: packet.c,v 1.115 2004/06/21 17:36:31 avsm Exp $"); + +#include "openbsd-compat/sys-queue.h" + +#include "xmalloc.h" +#include "buffer.h" +#include "packet.h" +#include "bufaux.h" +#include "crc32.h" +#include "getput.h" + +#include "compress.h" +#include "deattack.h" +#include "channels.h" + +#include "compat.h" +#include "ssh1.h" +#include "ssh2.h" + +#include "cipher.h" +#include "kex.h" +#include "mac.h" +#include "log.h" +#include "canohost.h" +#include "misc.h" +#include "ssh.h" + +#ifdef PACKET_DEBUG +#define DBG(x) x +#else +#define DBG(x) +#endif + +/* + * 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; + +/* Protocol flags for the remote side. */ +static u_int remote_protocol_flags = 0; + +/* Encryption context for receiving data. This is only used for decryption. */ +static CipherContext receive_context; + +/* Encryption context for sending data. This is only used for encryption. */ +static CipherContext send_context; + +/* Buffer for raw input data from the socket. */ +Buffer input; + +/* Buffer for raw output data going to the socket. */ +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; +static int compression_buffer_ready = 0; + +/* Flag indicating whether packet compression/decompression is enabled. */ +static int packet_compression = 0; + +/* default maximum packet size */ +u_int max_packet_size = 32768; + +/* 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; + +/* Session key information for Encryption and MAC */ +Newkeys *newkeys[MODE_MAX]; +static struct packet_state { + u_int32_t seqnr; + u_int32_t packets; + u_int64_t blocks; +} p_read, p_send; + +static u_int64_t max_blocks_in, max_blocks_out; +static u_int32_t rekey_limit; + +/* Session key for protocol v1 */ +static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; +static u_int ssh1_keylen; + +/* roundup current message to extra_pad bytes */ +static u_char extra_pad = 0; + +struct packet { + TAILQ_ENTRY(packet) next; + u_char type; + Buffer payload; +}; +TAILQ_HEAD(, packet) outgoing; + +/* + * 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) +{ + Cipher *none = cipher_by_name("none"); + + if (none == NULL) + fatal("packet_set_connection: cannot load cipher 'none'"); + connection_in = fd_in; + connection_out = fd_out; + cipher_init(&send_context, none, (const u_char *)"", + 0, NULL, 0, CIPHER_ENCRYPT); + cipher_init(&receive_context, none, (const u_char *)"", + 0, NULL, 0, CIPHER_DECRYPT); + newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL; + if (!initialized) { + initialized = 1; + buffer_init(&input); + buffer_init(&output); + buffer_init(&outgoing_packet); + buffer_init(&incoming_packet); + TAILQ_INIT(&outgoing); + } +} + +/* Returns 1 if remote host is connected via socket, 0 if not. */ + +int +packet_connection_is_on_socket(void) +{ + struct sockaddr_storage from, to; + socklen_t fromlen, tolen; + + /* filedescriptors in and out are the same, so it's a socket */ + if (connection_in == connection_out) + return 1; + fromlen = sizeof(from); + memset(&from, 0, sizeof(from)); + if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0) + return 0; + tolen = sizeof(to); + memset(&to, 0, sizeof(to)); + if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0) + return 0; + if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0) + return 0; + if (from.ss_family != AF_INET && from.ss_family != AF_INET6) + return 0; + return 1; +} + +/* + * Exports an IV from the CipherContext required to export the key + * state back from the unprivileged child to the privileged parent + * process. + */ + +void +packet_get_keyiv(int mode, u_char *iv, u_int len) +{ + CipherContext *cc; + + if (mode == MODE_OUT) + cc = &send_context; + else + cc = &receive_context; + + cipher_get_keyiv(cc, iv, len); +} + +int +packet_get_keycontext(int mode, u_char *dat) +{ + CipherContext *cc; + + if (mode == MODE_OUT) + cc = &send_context; + else + cc = &receive_context; + + return (cipher_get_keycontext(cc, dat)); +} + +void +packet_set_keycontext(int mode, u_char *dat) +{ + CipherContext *cc; + + if (mode == MODE_OUT) + cc = &send_context; + else + cc = &receive_context; + + cipher_set_keycontext(cc, dat); +} + +int +packet_get_keyiv_len(int mode) +{ + CipherContext *cc; + + if (mode == MODE_OUT) + cc = &send_context; + else + cc = &receive_context; + + return (cipher_get_keyiv_len(cc)); +} +void +packet_set_iv(int mode, u_char *dat) +{ + CipherContext *cc; + + if (mode == MODE_OUT) + cc = &send_context; + else + cc = &receive_context; + + cipher_set_keyiv(cc, dat); +} +int +packet_get_ssh1_cipher(void) +{ + return (cipher_get_number(receive_context.cipher)); +} + +void +packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets) +{ + struct packet_state *state; + + state = (mode == MODE_IN) ? &p_read : &p_send; + *seqnr = state->seqnr; + *blocks = state->blocks; + *packets = state->packets; +} + +void +packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets) +{ + struct packet_state *state; + + state = (mode == MODE_IN) ? &p_read : &p_send; + state->seqnr = seqnr; + state->blocks = blocks; + state->packets = packets; +} + +/* returns 1 if connection is via ipv4 */ + +int +packet_connection_is_ipv4(void) +{ + struct sockaddr_storage to; + socklen_t tolen = sizeof(to); + + memset(&to, 0, sizeof(to)); + if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0) + return 0; + if (to.ss_family == AF_INET) + return 1; +#ifdef IPV4_IN_IPV6 + if (to.ss_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&to)->sin6_addr)) + return 1; +#endif + return 0; +} + +/* Sets the connection into non-blocking mode. */ + +void +packet_set_nonblocking(void) +{ + /* Set the socket into non-blocking mode. */ + set_nonblock(connection_in); + + if (connection_out != connection_in) + set_nonblock(connection_out); +} + +/* Returns the socket used for reading. */ + +int +packet_get_connection_in(void) +{ + return connection_in; +} + +/* Returns the descriptor used for writing. */ + +int +packet_get_connection_out(void) +{ + return connection_out; +} + +/* Closes the connection and clears and frees internal data structures. */ + +void +packet_close(void) +{ + if (!initialized) + return; + initialized = 0; + if (connection_in == connection_out) { + shutdown(connection_out, SHUT_RDWR); + close(connection_out); + } else { + close(connection_in); + close(connection_out); + } + buffer_free(&input); + buffer_free(&output); + buffer_free(&outgoing_packet); + buffer_free(&incoming_packet); + if (compression_buffer_ready) { + buffer_free(&compression_buffer); + buffer_compress_uninit(); + } + cipher_cleanup(&send_context); + cipher_cleanup(&receive_context); +} + +/* Sets remote side protocol flags. */ + +void +packet_set_protocol_flags(u_int protocol_flags) +{ + remote_protocol_flags = protocol_flags; +} + +/* Returns the remote protocol flags set earlier by the above function. */ + +u_int +packet_get_protocol_flags(void) +{ + return remote_protocol_flags; +} + +/* + * Starts packet compression from the next packet on in both directions. + * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. + */ + +static void +packet_init_compression(void) +{ + if (compression_buffer_ready == 1) + return; + compression_buffer_ready = 1; + buffer_init(&compression_buffer); +} + +void +packet_start_compression(int level) +{ + if (packet_compression && !compat20) + fatal("Compression already enabled."); + packet_compression = 1; + packet_init_compression(); + buffer_compress_init_send(level); + buffer_compress_init_recv(); +} + +/* + * 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 u_char *key, u_int keylen, + int number) +{ + Cipher *cipher = cipher_by_number(number); + + if (cipher == NULL) + fatal("packet_set_encryption_key: unknown cipher number %d", number); + if (keylen < 20) + fatal("packet_set_encryption_key: keylen too small: %d", keylen); + if (keylen > SSH_SESSION_KEY_LENGTH) + fatal("packet_set_encryption_key: keylen too big: %d", keylen); + memcpy(ssh1_key, key, keylen); + ssh1_keylen = keylen; + cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT); + cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT); +} + +u_int +packet_get_encryption_key(u_char *key) +{ + if (key == NULL) + return (ssh1_keylen); + memcpy(key, ssh1_key, ssh1_keylen); + return (ssh1_keylen); +} + +/* Start constructing a packet to send. */ +void +packet_start(u_char type) +{ + u_char buf[9]; + int len; + + DBG(debug("packet_start[%d]", type)); + len = compat20 ? 6 : 9; + memset(buf, 0, len - 1); + buf[len - 1] = type; + buffer_clear(&outgoing_packet); + buffer_append(&outgoing_packet, buf, len); +} + +/* Append payload. */ +void +packet_put_char(int value) +{ + char ch = value; + + buffer_append(&outgoing_packet, &ch, 1); +} +void +packet_put_int(u_int value) +{ + buffer_put_int(&outgoing_packet, value); +} +void +packet_put_string(const void *buf, u_int len) +{ + buffer_put_string(&outgoing_packet, buf, len); +} +void +packet_put_cstring(const char *str) +{ + buffer_put_cstring(&outgoing_packet, str); +} +void +packet_put_raw(const void *buf, u_int len) +{ + buffer_append(&outgoing_packet, buf, len); +} +void +packet_put_bignum(BIGNUM * value) +{ + buffer_put_bignum(&outgoing_packet, value); +} +void +packet_put_bignum2(BIGNUM * value) +{ + buffer_put_bignum2(&outgoing_packet, value); +} + +/* + * Finalizes and sends the packet. If the encryption key has been set, + * encrypts the packet before sending. + */ + +static void +packet_send1(void) +{ + u_char buf[8], *cp; + int i, padding, len; + u_int checksum; + u_int32_t rnd = 0; + + /* + * If using packet compression, compress the payload of the outgoing + * packet. + */ + if (packet_compression) { + buffer_clear(&compression_buffer); + /* Skip padding. */ + buffer_consume(&outgoing_packet, 8); + /* padding */ + buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); + buffer_compress(&outgoing_packet, &compression_buffer); + buffer_clear(&outgoing_packet); + buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), + buffer_len(&compression_buffer)); + } + /* Compute packet length without padding (add checksum, remove padding). */ + len = buffer_len(&outgoing_packet) + 4 - 8; + + /* Insert padding. Initialized to zero in packet_start1() */ + padding = 8 - len % 8; + if (!send_context.plaintext) { + cp = buffer_ptr(&outgoing_packet); + for (i = 0; i < padding; i++) { + if (i % 4 == 0) + rnd = arc4random(); + cp[7 - i] = rnd & 0xff; + rnd >>= 8; + } + } + buffer_consume(&outgoing_packet, 8 - padding); + + /* Add check bytes. */ + checksum = ssh_crc32(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); + cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); + cipher_crypt(&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. + */ +} + +void +set_newkeys(int mode) +{ + Enc *enc; + Mac *mac; + Comp *comp; + CipherContext *cc; + u_int64_t *max_blocks; + int crypt_type; + + debug2("set_newkeys: mode %d", mode); + + if (mode == MODE_OUT) { + cc = &send_context; + crypt_type = CIPHER_ENCRYPT; + p_send.packets = p_send.blocks = 0; + max_blocks = &max_blocks_out; + } else { + cc = &receive_context; + crypt_type = CIPHER_DECRYPT; + p_read.packets = p_read.blocks = 0; + max_blocks = &max_blocks_in; + } + if (newkeys[mode] != NULL) { + debug("set_newkeys: rekeying"); + cipher_cleanup(cc); + enc = &newkeys[mode]->enc; + mac = &newkeys[mode]->mac; + comp = &newkeys[mode]->comp; + memset(mac->key, 0, mac->key_len); + xfree(enc->name); + xfree(enc->iv); + xfree(enc->key); + xfree(mac->name); + xfree(mac->key); + xfree(comp->name); + xfree(newkeys[mode]); + } + newkeys[mode] = kex_get_newkeys(mode); + if (newkeys[mode] == NULL) + fatal("newkeys: no keys for mode %d", mode); + enc = &newkeys[mode]->enc; + mac = &newkeys[mode]->mac; + comp = &newkeys[mode]->comp; + if (mac->md != NULL) + mac->enabled = 1; + DBG(debug("cipher_init_context: %d", mode)); + cipher_init(cc, enc->cipher, enc->key, enc->key_len, + enc->iv, enc->block_size, crypt_type); + /* Deleting the keys does not gain extra security */ + /* memset(enc->iv, 0, enc->block_size); + memset(enc->key, 0, enc->key_len); */ + if (comp->type != 0 && comp->enabled == 0) { + packet_init_compression(); + if (mode == MODE_OUT) + buffer_compress_init_send(6); + else + buffer_compress_init_recv(); + comp->enabled = 1; + } + /* + * The 2^(blocksize*2) limit is too expensive for 3DES, + * blowfish, etc, so enforce a 1GB limit for small blocksizes. + */ + if (enc->block_size >= 16) + *max_blocks = (u_int64_t)1 << (enc->block_size*2); + else + *max_blocks = ((u_int64_t)1 << 30) / enc->block_size; + if (rekey_limit) + *max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size); +} + +/* + * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) + */ +static void +packet_send2_wrapped(void) +{ + u_char type, *cp, *macbuf = NULL; + u_char padlen, pad; + u_int packet_length = 0; + u_int i, len; + u_int32_t rnd = 0; + Enc *enc = NULL; + Mac *mac = NULL; + Comp *comp = NULL; + int block_size; + + if (newkeys[MODE_OUT] != NULL) { + enc = &newkeys[MODE_OUT]->enc; + mac = &newkeys[MODE_OUT]->mac; + comp = &newkeys[MODE_OUT]->comp; + } + block_size = enc ? enc->block_size : 8; + + cp = buffer_ptr(&outgoing_packet); + type = cp[5]; + +#ifdef PACKET_DEBUG + fprintf(stderr, "plain: "); + buffer_dump(&outgoing_packet); +#endif + + if (comp && comp->enabled) { + len = buffer_len(&outgoing_packet); + /* skip header, compress only payload */ + buffer_consume(&outgoing_packet, 5); + buffer_clear(&compression_buffer); + buffer_compress(&outgoing_packet, &compression_buffer); + buffer_clear(&outgoing_packet); + buffer_append(&outgoing_packet, "\0\0\0\0\0", 5); + buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), + buffer_len(&compression_buffer)); + DBG(debug("compression: raw %d compressed %d", len, + buffer_len(&outgoing_packet))); + } + + /* sizeof (packet_len + pad_len + payload) */ + len = buffer_len(&outgoing_packet); + + /* + * calc size of padding, alloc space, get random data, + * minimum padding is 4 bytes + */ + padlen = block_size - (len % block_size); + if (padlen < 4) + padlen += block_size; + if (extra_pad) { + /* will wrap if extra_pad+padlen > 255 */ + extra_pad = roundup(extra_pad, block_size); + pad = extra_pad - ((len + padlen) % extra_pad); + debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)", + pad, len, padlen, extra_pad); + padlen += pad; + extra_pad = 0; + } + cp = buffer_append_space(&outgoing_packet, padlen); + if (enc && !send_context.plaintext) { + /* random padding */ + for (i = 0; i < padlen; i++) { + if (i % 4 == 0) + rnd = arc4random(); + cp[i] = rnd & 0xff; + rnd >>= 8; + } + } else { + /* clear padding */ + memset(cp, 0, padlen); + } + /* packet_length includes payload, padding and padding length field */ + packet_length = buffer_len(&outgoing_packet) - 4; + cp = buffer_ptr(&outgoing_packet); + PUT_32BIT(cp, packet_length); + cp[4] = padlen; + DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen)); + + /* compute MAC over seqnr and packet(length fields, payload, padding) */ + if (mac && mac->enabled) { + macbuf = mac_compute(mac, p_send.seqnr, + buffer_ptr(&outgoing_packet), + buffer_len(&outgoing_packet)); + DBG(debug("done calc MAC out #%d", p_send.seqnr)); + } + /* encrypt packet and append to output buffer. */ + cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); + cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), + buffer_len(&outgoing_packet)); + /* append unencrypted MAC */ + if (mac && mac->enabled) + buffer_append(&output, (char *)macbuf, mac->mac_len); +#ifdef PACKET_DEBUG + fprintf(stderr, "encrypted: "); + buffer_dump(&output); +#endif + /* increment sequence number for outgoing packets */ + if (++p_send.seqnr == 0) + logit("outgoing seqnr wraps around"); + if (++p_send.packets == 0) + if (!(datafellows & SSH_BUG_NOREKEY)) + fatal("XXX too many packets with same key"); + p_send.blocks += (packet_length + 4) / block_size; + buffer_clear(&outgoing_packet); + + if (type == SSH2_MSG_NEWKEYS) + set_newkeys(MODE_OUT); +} + +static void +packet_send2(void) +{ + static int rekeying = 0; + struct packet *p; + u_char type, *cp; + + cp = buffer_ptr(&outgoing_packet); + type = cp[5]; + + /* during rekeying we can only send key exchange messages */ + if (rekeying) { + if (!((type >= SSH2_MSG_TRANSPORT_MIN) && + (type <= SSH2_MSG_TRANSPORT_MAX))) { + debug("enqueue packet: %u", type); + p = xmalloc(sizeof(*p)); + p->type = type; + memcpy(&p->payload, &outgoing_packet, sizeof(Buffer)); + buffer_init(&outgoing_packet); + TAILQ_INSERT_TAIL(&outgoing, p, next); + return; + } + } + + /* rekeying starts with sending KEXINIT */ + if (type == SSH2_MSG_KEXINIT) + rekeying = 1; + + packet_send2_wrapped(); + + /* after a NEWKEYS message we can send the complete queue */ + if (type == SSH2_MSG_NEWKEYS) { + rekeying = 0; + while ((p = TAILQ_FIRST(&outgoing))) { + type = p->type; + debug("dequeue packet: %u", type); + buffer_free(&outgoing_packet); + memcpy(&outgoing_packet, &p->payload, + sizeof(Buffer)); + TAILQ_REMOVE(&outgoing, p, next); + xfree(p); + packet_send2_wrapped(); + } + } +} + +void +packet_send(void) +{ + if (compat20) + packet_send2(); + else + packet_send1(); + DBG(debug("packet_send done")); +} + +/* + * 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_seqnr(u_int32_t *seqnr_p) +{ + int type, len; + fd_set *setp; + char buf[8192]; + DBG(debug("packet_read()")); + + setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) * + sizeof(fd_mask)); + + /* 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_seqnr(seqnr_p); + if (!compat20 && ( + type == SSH_SMSG_SUCCESS + || type == SSH_SMSG_FAILURE + || type == SSH_CMSG_EOF + || type == SSH_CMSG_EXIT_CONFIRMATION)) + packet_check_eom(); + /* If we got a packet, return it. */ + if (type != SSH_MSG_NONE) { + xfree(setp); + return type; + } + /* + * Otherwise, wait for some data to arrive, add it to the + * buffer, and try again. + */ + memset(setp, 0, howmany(connection_in + 1, NFDBITS) * + sizeof(fd_mask)); + FD_SET(connection_in, setp); + + /* Wait for some data to arrive. */ + while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 && + (errno == EAGAIN || errno == EINTR)) + ; + + /* Read data from the socket. */ + len = read(connection_in, buf, sizeof(buf)); + if (len == 0) { + logit("Connection closed by %.200s", get_remote_ipaddr()); + cleanup_exit(255); + } + if (len < 0) + fatal("Read from socket failed: %.100s", strerror(errno)); + /* Append it to the buffer. */ + packet_process_incoming(buf, len); + } + /* NOTREACHED */ +} + +int +packet_read(void) +{ + return packet_read_seqnr(NULL); +} + +/* + * 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 expected_type) +{ + int type; + + type = packet_read(); + 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. + */ + +static int +packet_read_poll1(void) +{ + u_int len, padded_len; + u_char *cp, type; + u_int checksum, stored_checksum; + + /* 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. */ + cp = buffer_ptr(&input); + len = GET_32BIT(cp); + if (len < 1 + 2 + 2 || len > 256 * 1024) + packet_disconnect("Bad packet length %u.", 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); + + /* + * Cryptographic attack detector for ssh + * (C)1998 CORE-SDI, Buenos Aires Argentina + * Ariel Futoransky(futo@core-sdi.com) + */ + if (!receive_context.plaintext && + detect_attack(buffer_ptr(&input), padded_len, NULL) == DEATTACK_DETECTED) + packet_disconnect("crc32 compensation attack: network attack detected"); + + /* Decrypt data to incoming_packet. */ + buffer_clear(&incoming_packet); + cp = buffer_append_space(&incoming_packet, padded_len); + cipher_crypt(&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 = ssh_crc32(buffer_ptr(&incoming_packet), + buffer_len(&incoming_packet) - 4); + + /* Skip padding. */ + buffer_consume(&incoming_packet, 8 - len % 8); + + /* Test check bytes. */ + if (len != buffer_len(&incoming_packet)) + packet_disconnect("packet_read_poll1: len %d != buffer_len %d.", + len, buffer_len(&incoming_packet)); + + cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4; + stored_checksum = GET_32BIT(cp); + if (checksum != stored_checksum) + packet_disconnect("Corrupted check bytes on input."); + buffer_consume_end(&incoming_packet, 4); + + 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)); + } + type = buffer_get_char(&incoming_packet); + return type; +} + +static int +packet_read_poll2(u_int32_t *seqnr_p) +{ + static u_int packet_length = 0; + u_int padlen, need; + u_char *macbuf, *cp, type; + int maclen, block_size; + Enc *enc = NULL; + Mac *mac = NULL; + Comp *comp = NULL; + + if (newkeys[MODE_IN] != NULL) { + enc = &newkeys[MODE_IN]->enc; + mac = &newkeys[MODE_IN]->mac; + comp = &newkeys[MODE_IN]->comp; + } + maclen = mac && mac->enabled ? mac->mac_len : 0; + block_size = enc ? enc->block_size : 8; + + if (packet_length == 0) { + /* + * check if input size is less than the cipher block size, + * decrypt first block and extract length of incoming packet + */ + if (buffer_len(&input) < block_size) + return SSH_MSG_NONE; + buffer_clear(&incoming_packet); + cp = buffer_append_space(&incoming_packet, block_size); + cipher_crypt(&receive_context, cp, buffer_ptr(&input), + block_size); + cp = buffer_ptr(&incoming_packet); + packet_length = GET_32BIT(cp); + if (packet_length < 1 + 4 || packet_length > 256 * 1024) { +#ifdef PACKET_DEBUG + buffer_dump(&incoming_packet); +#endif + packet_disconnect("Bad packet length %u.", packet_length); + } + DBG(debug("input: packet len %u", packet_length+4)); + buffer_consume(&input, block_size); + } + /* we have a partial packet of block_size bytes */ + need = 4 + packet_length - block_size; + DBG(debug("partial packet %d, need %d, maclen %d", block_size, + need, maclen)); + if (need % block_size != 0) + fatal("padding error: need %d block %d mod %d", + need, block_size, need % block_size); + /* + * check if the entire packet has been received and + * decrypt into incoming_packet + */ + if (buffer_len(&input) < need + maclen) + return SSH_MSG_NONE; +#ifdef PACKET_DEBUG + fprintf(stderr, "read_poll enc/full: "); + buffer_dump(&input); +#endif + cp = buffer_append_space(&incoming_packet, need); + cipher_crypt(&receive_context, cp, buffer_ptr(&input), need); + buffer_consume(&input, need); + /* + * compute MAC over seqnr and packet, + * increment sequence number for incoming packet + */ + if (mac && mac->enabled) { + macbuf = mac_compute(mac, p_read.seqnr, + buffer_ptr(&incoming_packet), + buffer_len(&incoming_packet)); + if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) + packet_disconnect("Corrupted MAC on input."); + DBG(debug("MAC #%d ok", p_read.seqnr)); + buffer_consume(&input, mac->mac_len); + } + if (seqnr_p != NULL) + *seqnr_p = p_read.seqnr; + if (++p_read.seqnr == 0) + logit("incoming seqnr wraps around"); + if (++p_read.packets == 0) + if (!(datafellows & SSH_BUG_NOREKEY)) + fatal("XXX too many packets with same key"); + p_read.blocks += (packet_length + 4) / block_size; + + /* get padlen */ + cp = buffer_ptr(&incoming_packet); + padlen = cp[4]; + DBG(debug("input: padlen %d", padlen)); + if (padlen < 4) + packet_disconnect("Corrupted padlen %d on input.", padlen); + + /* skip packet size + padlen, discard padding */ + buffer_consume(&incoming_packet, 4 + 1); + buffer_consume_end(&incoming_packet, padlen); + + DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet))); + if (comp && comp->enabled) { + 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)); + DBG(debug("input: len after de-compress %d", + buffer_len(&incoming_packet))); + } + /* + * get packet type, implies consume. + * return length of payload (without type field) + */ + type = buffer_get_char(&incoming_packet); + if (type == SSH2_MSG_NEWKEYS) + set_newkeys(MODE_IN); +#ifdef PACKET_DEBUG + fprintf(stderr, "read/plain[%d]:\r\n", type); + buffer_dump(&incoming_packet); +#endif + /* reset for next packet */ + packet_length = 0; + return type; +} + +int +packet_read_poll_seqnr(u_int32_t *seqnr_p) +{ + u_int reason, seqnr; + u_char type; + char *msg; + + for (;;) { + if (compat20) { + type = packet_read_poll2(seqnr_p); + if (type) + DBG(debug("received packet type %d", type)); + switch (type) { + case SSH2_MSG_IGNORE: + break; + case SSH2_MSG_DEBUG: + packet_get_char(); + msg = packet_get_string(NULL); + debug("Remote: %.900s", msg); + xfree(msg); + msg = packet_get_string(NULL); + xfree(msg); + break; + case SSH2_MSG_DISCONNECT: + reason = packet_get_int(); + msg = packet_get_string(NULL); + logit("Received disconnect from %s: %u: %.400s", + get_remote_ipaddr(), reason, msg); + xfree(msg); + cleanup_exit(255); + break; + case SSH2_MSG_UNIMPLEMENTED: + seqnr = packet_get_int(); + debug("Received SSH2_MSG_UNIMPLEMENTED for %u", + seqnr); + break; + default: + return type; + break; + } + } else { + type = packet_read_poll1(); + switch (type) { + case SSH_MSG_IGNORE: + break; + case SSH_MSG_DEBUG: + msg = packet_get_string(NULL); + debug("Remote: %.900s", msg); + xfree(msg); + break; + case SSH_MSG_DISCONNECT: + msg = packet_get_string(NULL); + logit("Received disconnect from %s: %.400s", + get_remote_ipaddr(), msg); + cleanup_exit(255); + xfree(msg); + break; + default: + if (type) + DBG(debug("received packet type %d", type)); + return type; + break; + } + } + } +} + +int +packet_read_poll(void) +{ + return packet_read_poll_seqnr(NULL); +} + +/* + * 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, u_int len) +{ + buffer_append(&input, buf, len); +} + +/* Returns a character from the packet. */ + +u_int +packet_get_char(void) +{ + char ch; + + buffer_get(&incoming_packet, &ch, 1); + return (u_char) ch; +} + +/* Returns an integer from the packet data. */ + +u_int +packet_get_int(void) +{ + 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_bignum(BIGNUM * value) +{ + buffer_get_bignum(&incoming_packet, value); +} + +void +packet_get_bignum2(BIGNUM * value) +{ + buffer_get_bignum2(&incoming_packet, value); +} + +void * +packet_get_raw(int *length_ptr) +{ + int bytes = buffer_len(&incoming_packet); + + if (length_ptr != NULL) + *length_ptr = bytes; + return buffer_ptr(&incoming_packet); +} + +int +packet_remaining(void) +{ + return buffer_len(&incoming_packet); +} + +/* + * 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. + */ + +void * +packet_get_string(u_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; + + if (compat20 && (datafellows & SSH_BUG_DEBUG)) + return; + + va_start(args, fmt); + vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (compat20) { + packet_start(SSH2_MSG_DEBUG); + packet_put_char(0); /* bool: always display */ + packet_put_cstring(buf); + packet_put_cstring(""); + } else { + packet_start(SSH_MSG_DEBUG); + packet_put_cstring(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); + + /* Display the error locally */ + logit("Disconnecting: %.100s", buf); + + /* Send the disconnect message to the other side, and wait for it to get sent. */ + if (compat20) { + packet_start(SSH2_MSG_DISCONNECT); + packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR); + packet_put_cstring(buf); + packet_put_cstring(""); + } else { + packet_start(SSH_MSG_DISCONNECT); + packet_put_cstring(buf); + } + packet_send(); + packet_write_wait(); + + /* Stop listening for connections. */ + channel_close_all(); + + /* Close the connection. */ + packet_close(); + cleanup_exit(255); +} + +/* Checks if there is any buffered output, and tries to write some of the output. */ + +void +packet_write_poll(void) +{ + 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(void) +{ + fd_set *setp; + + setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) * + sizeof(fd_mask)); + packet_write_poll(); + while (packet_have_data_to_write()) { + memset(setp, 0, howmany(connection_out + 1, NFDBITS) * + sizeof(fd_mask)); + FD_SET(connection_out, setp); + while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 && + (errno == EAGAIN || errno == EINTR)) + ; + packet_write_poll(); + } + xfree(setp); +} + +/* Returns true if there is buffered data to write to the connection. */ + +int +packet_have_data_to_write(void) +{ + 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(void) +{ + if (interactive_mode) + return buffer_len(&output) < 16384; + else + return buffer_len(&output) < 128 * 1024; +} + + +static void +packet_set_tos(int interactive) +{ +#if defined(IP_TOS) && !defined(IP_TOS_IS_BROKEN) + int tos = interactive ? IPTOS_LOWDELAY : IPTOS_THROUGHPUT; + + if (!packet_connection_is_on_socket() || + !packet_connection_is_ipv4()) + return; + if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &tos, + sizeof(tos)) < 0) + error("setsockopt IP_TOS %d: %.100s:", + tos, strerror(errno)); +#endif +} + +/* Informs that the current session is interactive. Sets IP flags for that. */ + +void +packet_set_interactive(int interactive) +{ + static int called = 0; + + if (called) + return; + called = 1; + + /* Record that we are in interactive mode. */ + interactive_mode = interactive; + + /* Only set socket options if using a socket. */ + if (!packet_connection_is_on_socket()) + return; + if (interactive) + set_nodelay(connection_in); + packet_set_tos(interactive); +} + +/* Returns true if the current connection is interactive. */ + +int +packet_is_interactive(void) +{ + return interactive_mode; +} + +int +packet_set_maxsize(u_int s) +{ + static int called = 0; + + if (called) { + logit("packet_set_maxsize: called twice: old %d new %d", + max_packet_size, s); + return -1; + } + if (s < 4 * 1024 || s > 1024 * 1024) { + logit("packet_set_maxsize: bad size %d", s); + return -1; + } + called = 1; + debug("packet_set_maxsize: setting to %d", s); + max_packet_size = s; + return s; +} + +/* roundup current message to pad bytes */ +void +packet_add_padding(u_char pad) +{ + extra_pad = pad; +} + +/* + * 9.2. Ignored Data Message + * + * byte SSH_MSG_IGNORE + * string data + * + * All implementations MUST understand (and ignore) this message at any + * time (after receiving the protocol version). No implementation is + * required to send them. This message can be used as an additional + * protection measure against advanced traffic analysis techniques. + */ +void +packet_send_ignore(int nbytes) +{ + u_int32_t rnd = 0; + int i; + + packet_start(compat20 ? SSH2_MSG_IGNORE : SSH_MSG_IGNORE); + packet_put_int(nbytes); + for (i = 0; i < nbytes; i++) { + if (i % 4 == 0) + rnd = arc4random(); + packet_put_char(rnd & 0xff); + rnd >>= 8; + } +} + +#define MAX_PACKETS (1U<<31) +int +packet_need_rekeying(void) +{ + if (datafellows & SSH_BUG_NOREKEY) + return 0; + return + (p_send.packets > MAX_PACKETS) || + (p_read.packets > MAX_PACKETS) || + (max_blocks_out && (p_send.blocks > max_blocks_out)) || + (max_blocks_in && (p_read.blocks > max_blocks_in)); +} + +void +packet_set_rekey_limit(u_int32_t bytes) +{ + rekey_limit = bytes; +} diff --git a/crypto/openssh-3.9p1/packet.h b/crypto/openssh-3.9p1/packet.h new file mode 100644 index 0000000000..37f82f2f60 --- /dev/null +++ b/crypto/openssh-3.9p1/packet.h @@ -0,0 +1,102 @@ +/* $OpenBSD: packet.h,v 1.41 2004/05/11 19:01:43 deraadt Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Interface for the packet protocol functions. + * + * 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". + */ + +#ifndef PACKET_H +#define PACKET_H + +#include + +void packet_set_connection(int, int); +void packet_set_nonblocking(void); +int packet_get_connection_in(void); +int packet_get_connection_out(void); +void packet_close(void); +void packet_set_encryption_key(const u_char *, u_int, int); +u_int packet_get_encryption_key(u_char *); +void packet_set_protocol_flags(u_int); +u_int packet_get_protocol_flags(void); +void packet_start_compression(int); +void packet_set_interactive(int); +int packet_is_interactive(void); + +void packet_start(u_char); +void packet_put_char(int ch); +void packet_put_int(u_int value); +void packet_put_bignum(BIGNUM * value); +void packet_put_bignum2(BIGNUM * value); +void packet_put_string(const void *buf, u_int len); +void packet_put_cstring(const char *str); +void packet_put_raw(const void *buf, u_int len); +void packet_send(void); + +int packet_read(void); +void packet_read_expect(int type); +int packet_read_poll(void); +void packet_process_incoming(const char *buf, u_int len); +int packet_read_seqnr(u_int32_t *seqnr_p); +int packet_read_poll_seqnr(u_int32_t *seqnr_p); + +u_int packet_get_char(void); +u_int packet_get_int(void); +void packet_get_bignum(BIGNUM * value); +void packet_get_bignum2(BIGNUM * value); +void *packet_get_raw(int *length_ptr); +void *packet_get_string(u_int *length_ptr); +void packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2))); +void packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2))); + +void set_newkeys(int mode); +int packet_get_keyiv_len(int); +void packet_get_keyiv(int, u_char *, u_int); +int packet_get_keycontext(int, u_char *); +void packet_set_keycontext(int, u_char *); +void packet_get_state(int, u_int32_t *, u_int64_t *, u_int32_t *); +void packet_set_state(int, u_int32_t, u_int64_t, u_int32_t); +int packet_get_ssh1_cipher(void); +void packet_set_iv(int, u_char *); + +void packet_write_poll(void); +void packet_write_wait(void); +int packet_have_data_to_write(void); +int packet_not_very_much_data_to_write(void); + +int packet_connection_is_on_socket(void); +int packet_connection_is_ipv4(void); +int packet_remaining(void); +void packet_send_ignore(int); +void packet_add_padding(u_char); + +void tty_make_modes(int, struct termios *); +void tty_parse_modes(int, int *); + +extern u_int max_packet_size; +int packet_set_maxsize(u_int); +#define packet_get_maxsize() max_packet_size + +/* don't allow remaining bytes after the end of the message */ +#define packet_check_eom() \ +do { \ + int _len = packet_remaining(); \ + if (_len > 0) { \ + logit("Packet integrity error (%d bytes remaining) at %s:%d", \ + _len ,__FILE__, __LINE__); \ + packet_disconnect("Packet integrity error."); \ + } \ +} while (0) + +int packet_need_rekeying(void); +void packet_set_rekey_limit(u_int32_t); + +#endif /* PACKET_H */ diff --git a/crypto/openssh-3.9p1/pathnames.h b/crypto/openssh-3.9p1/pathnames.h new file mode 100644 index 0000000000..cf42625a4a --- /dev/null +++ b/crypto/openssh-3.9p1/pathnames.h @@ -0,0 +1,174 @@ +/* $OpenBSD: pathnames.h,v 1.15 2004/07/11 17:48:47 deraadt Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#define ETCDIR "/etc" + +#ifndef SSHDIR +#define SSHDIR ETCDIR "/ssh" +#endif + +#ifndef _PATH_SSH_PIDDIR +#define _PATH_SSH_PIDDIR "/var/run" +#endif + +/* + * System-wide file containing host keys of known hosts. This file should be + * world-readable. + */ +#define _PATH_SSH_SYSTEM_HOSTFILE SSHDIR "/ssh_known_hosts" +/* backward compat for protocol 2 */ +#define _PATH_SSH_SYSTEM_HOSTFILE2 SSHDIR "/ssh_known_hosts2" + +/* + * Of these, ssh_host_key must be readable only by root, whereas ssh_config + * should be world-readable. + */ +#define _PATH_SERVER_CONFIG_FILE SSHDIR "/sshd_config" +#define _PATH_HOST_CONFIG_FILE SSHDIR "/ssh_config" +#define _PATH_HOST_KEY_FILE SSHDIR "/ssh_host_key" +#define _PATH_HOST_DSA_KEY_FILE SSHDIR "/ssh_host_dsa_key" +#define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key" +#define _PATH_DH_MODULI SSHDIR "/moduli" +/* Backwards compatibility */ +#define _PATH_DH_PRIMES SSHDIR "/primes" + +#ifndef _PATH_SSH_PROGRAM +#define _PATH_SSH_PROGRAM "/usr/bin/ssh" +#endif + +/* + * The process id of the daemon listening for connections is saved here to + * make it easier to kill the correct daemon when necessary. + */ +#define _PATH_SSH_DAEMON_PID_FILE _PATH_SSH_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 _PATH_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 _PATH_SSH_USER_HOSTFILE "~/.ssh/known_hosts" +/* backward compat for protocol 2 */ +#define _PATH_SSH_USER_HOSTFILE2 "~/.ssh/known_hosts2" + +/* + * Name of the default file containing client-side authentication key. This + * file should only be readable by the user him/herself. + */ +#define _PATH_SSH_CLIENT_IDENTITY ".ssh/identity" +#define _PATH_SSH_CLIENT_ID_DSA ".ssh/id_dsa" +#define _PATH_SSH_CLIENT_ID_RSA ".ssh/id_rsa" + +/* + * 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 _PATH_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 _PATH_SSH_USER_PERMITTED_KEYS ".ssh/authorized_keys" + +/* backward compat for protocol v2 */ +#define _PATH_SSH_USER_PERMITTED_KEYS2 ".ssh/authorized_keys2" + +/* + * 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 _PATH_SSH_USER_RC ".ssh/rc" +#define _PATH_SSH_SYSTEM_RC SSHDIR "/sshrc" + +/* + * Ssh-only version of /etc/hosts.equiv. Additionally, the daemon may use + * ~/.rhosts and /etc/hosts.equiv if rhosts authentication is enabled. + */ +#define _PATH_SSH_HOSTS_EQUIV SSHDIR "/shosts.equiv" +#define _PATH_RHOSTS_EQUIV "/etc/hosts.equiv" + +/* + * Default location of askpass + */ +#ifndef _PATH_SSH_ASKPASS_DEFAULT +#define _PATH_SSH_ASKPASS_DEFAULT "/usr/X11R6/bin/ssh-askpass" +#endif + +/* Location of ssh-keysign for hostbased authentication */ +#ifndef _PATH_SSH_KEY_SIGN +#define _PATH_SSH_KEY_SIGN "/usr/libexec/ssh-keysign" +#endif + +/* xauth for X11 forwarding */ +#ifndef _PATH_XAUTH +#define _PATH_XAUTH "/usr/X11R6/bin/xauth" +#endif + +/* UNIX domain socket for X11 server; displaynum will replace %u */ +#ifndef _PATH_UNIX_X +#define _PATH_UNIX_X "/tmp/.X11-unix/X%u" +#endif + +/* for scp */ +#ifndef _PATH_CP +#define _PATH_CP "cp" +#endif + +/* for sftp */ +#ifndef _PATH_SFTP_SERVER +#define _PATH_SFTP_SERVER "/usr/libexec/sftp-server" +#endif + +/* chroot directory for unprivileged user when UsePrivilegeSeparation=yes */ +#ifndef _PATH_PRIVSEP_CHROOT_DIR +#define _PATH_PRIVSEP_CHROOT_DIR "/var/empty" +#endif + +/* for passwd change */ +#ifndef _PATH_PASSWD_PROG +#define _PATH_PASSWD_PROG "/usr/bin/passwd" +#endif + +#ifndef _PATH_LS +#define _PATH_LS "ls" +#endif + +/* path to login program */ +#ifndef LOGIN_PROGRAM +# ifdef LOGIN_PROGRAM_FALLBACK +# define LOGIN_PROGRAM LOGIN_PROGRAM_FALLBACK +# else +# define LOGIN_PROGRAM "/usr/bin/login" +# endif +#endif /* LOGIN_PROGRAM */ + +/* Askpass program define */ +#ifndef ASKPASS_PROGRAM +#define ASKPASS_PROGRAM "/usr/lib/ssh/ssh-askpass" +#endif /* ASKPASS_PROGRAM */ diff --git a/crypto/openssh-3.9p1/progressmeter.c b/crypto/openssh-3.9p1/progressmeter.c new file mode 100644 index 0000000000..93f5a3e622 --- /dev/null +++ b/crypto/openssh-3.9p1/progressmeter.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2003 Nils Nordman. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: progressmeter.c,v 1.22 2004/07/11 17:48:47 deraadt Exp $"); + +#include "progressmeter.h" +#include "atomicio.h" +#include "misc.h" + +#define DEFAULT_WINSIZE 80 +#define MAX_WINSIZE 512 +#define PADDING 1 /* padding between the progress indicators */ +#define UPDATE_INTERVAL 1 /* update the progress meter every second */ +#define STALL_TIME 5 /* we're stalled after this many seconds */ + +/* determines whether we can output to the terminal */ +static int can_output(void); + +/* formats and inserts the specified size into the given buffer */ +static void format_size(char *, int, off_t); +static void format_rate(char *, int, off_t); + +/* updates the progressmeter to reflect the current state of the transfer */ +void refresh_progress_meter(void); + +/* signal handler for updating the progress meter */ +static void update_progress_meter(int); + +static time_t start; /* start progress */ +static time_t last_update; /* last progress update */ +static char *file; /* name of the file being transferred */ +static off_t end_pos; /* ending position of transfer */ +static off_t cur_pos; /* transfer position as of last refresh */ +static volatile off_t *counter; /* progress counter */ +static long stalled; /* how long we have been stalled */ +static int bytes_per_second; /* current speed in bytes per second */ +static int win_size; /* terminal window size */ + +/* units for format_size */ +static const char unit[] = " KMGT"; + +static int +can_output(void) +{ + return (getpgrp() == tcgetpgrp(STDOUT_FILENO)); +} + +static void +format_rate(char *buf, int size, off_t bytes) +{ + int i; + + bytes *= 100; + for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++) + bytes = (bytes + 512) / 1024; + if (i == 0) { + i++; + bytes = (bytes + 512) / 1024; + } + snprintf(buf, size, "%3lld.%1lld%c%s", + (int64_t) (bytes + 5) / 100, + (int64_t) (bytes + 5) / 10 % 10, + unit[i], + i ? "B" : " "); +} + +static void +format_size(char *buf, int size, off_t bytes) +{ + int i; + + for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++) + bytes = (bytes + 512) / 1024; + snprintf(buf, size, "%4lld%c%s", + (int64_t) bytes, + unit[i], + i ? "B" : " "); +} + +void +refresh_progress_meter(void) +{ + char buf[MAX_WINSIZE + 1]; + time_t now; + off_t transferred; + double elapsed; + int percent; + off_t bytes_left; + int cur_speed; + int hours, minutes, seconds; + int i, len; + int file_len; + + transferred = *counter - cur_pos; + cur_pos = *counter; + now = time(NULL); + bytes_left = end_pos - cur_pos; + + if (bytes_left > 0) + elapsed = now - last_update; + else { + elapsed = now - start; + /* Calculate true total speed when done */ + transferred = end_pos; + bytes_per_second = 0; + } + + /* calculate speed */ + if (elapsed != 0) + cur_speed = (transferred / elapsed); + else + cur_speed = transferred; + +#define AGE_FACTOR 0.9 + if (bytes_per_second != 0) { + bytes_per_second = (bytes_per_second * AGE_FACTOR) + + (cur_speed * (1.0 - AGE_FACTOR)); + } else + bytes_per_second = cur_speed; + + /* filename */ + buf[0] = '\0'; + file_len = win_size - 35; + if (file_len > 0) { + len = snprintf(buf, file_len + 1, "\r%s", file); + if (len < 0) + len = 0; + for (i = len; i < file_len; i++ ) + buf[i] = ' '; + buf[file_len] = '\0'; + } + + /* percent of transfer done */ + if (end_pos != 0) + percent = ((float)cur_pos / end_pos) * 100; + else + percent = 100; + snprintf(buf + strlen(buf), win_size - strlen(buf), + " %3d%% ", percent); + + /* amount transferred */ + format_size(buf + strlen(buf), win_size - strlen(buf), + cur_pos); + strlcat(buf, " ", win_size); + + /* bandwidth usage */ + format_rate(buf + strlen(buf), win_size - strlen(buf), + (off_t)bytes_per_second); + strlcat(buf, "/s ", win_size); + + /* ETA */ + if (!transferred) + stalled += elapsed; + else + stalled = 0; + + if (stalled >= STALL_TIME) + strlcat(buf, "- stalled -", win_size); + else if (bytes_per_second == 0 && bytes_left) + strlcat(buf, " --:-- ETA", win_size); + else { + if (bytes_left > 0) + seconds = bytes_left / bytes_per_second; + else + seconds = elapsed; + + hours = seconds / 3600; + seconds -= hours * 3600; + minutes = seconds / 60; + seconds -= minutes * 60; + + if (hours != 0) + snprintf(buf + strlen(buf), win_size - strlen(buf), + "%d:%02d:%02d", hours, minutes, seconds); + else + snprintf(buf + strlen(buf), win_size - strlen(buf), + " %02d:%02d", minutes, seconds); + + if (bytes_left > 0) + strlcat(buf, " ETA", win_size); + else + strlcat(buf, " ", win_size); + } + + atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1); + last_update = now; +} + +static void +update_progress_meter(int ignore) +{ + int save_errno; + + save_errno = errno; + + if (can_output()) + refresh_progress_meter(); + + signal(SIGALRM, update_progress_meter); + alarm(UPDATE_INTERVAL); + errno = save_errno; +} + +void +start_progress_meter(char *f, off_t filesize, off_t *ctr) +{ + struct winsize winsize; + + start = last_update = time(NULL); + file = f; + end_pos = filesize; + cur_pos = 0; + counter = ctr; + stalled = 0; + bytes_per_second = 0; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 && + winsize.ws_col != 0) { + if (winsize.ws_col > MAX_WINSIZE) + win_size = MAX_WINSIZE; + else + win_size = winsize.ws_col; + } else + win_size = DEFAULT_WINSIZE; + win_size += 1; /* trailing \0 */ + + if (can_output()) + refresh_progress_meter(); + + signal(SIGALRM, update_progress_meter); + alarm(UPDATE_INTERVAL); +} + +void +stop_progress_meter(void) +{ + alarm(0); + + if (!can_output()) + return; + + /* Ensure we complete the progress */ + if (cur_pos != end_pos) + refresh_progress_meter(); + + atomicio(vwrite, STDOUT_FILENO, "\n", 1); +} diff --git a/crypto/openssh-3.9p1/progressmeter.h b/crypto/openssh-3.9p1/progressmeter.h new file mode 100644 index 0000000000..bfb9a0b770 --- /dev/null +++ b/crypto/openssh-3.9p1/progressmeter.h @@ -0,0 +1,27 @@ +/* $OpenBSD: progressmeter.h,v 1.1 2003/01/10 08:19:07 fgsch Exp $ */ +/* + * Copyright (c) 2002 Nils Nordman. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +void start_progress_meter(char *, off_t, off_t *); +void stop_progress_meter(void); diff --git a/crypto/openssh-3.9p1/readconf.c b/crypto/openssh-3.9p1/readconf.c new file mode 100644 index 0000000000..a4fe1fe028 --- /dev/null +++ b/crypto/openssh-3.9p1/readconf.c @@ -0,0 +1,1047 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Functions for reading the configuration files. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: readconf.c,v 1.134 2004/07/11 17:48:47 deraadt Exp $"); + +#include "ssh.h" +#include "xmalloc.h" +#include "compat.h" +#include "cipher.h" +#include "pathnames.h" +#include "log.h" +#include "readconf.h" +#include "match.h" +#include "misc.h" +#include "kex.h" +#include "mac.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 + User foo + + 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 + PasswordAuthentication no + + Host puukko.hut.fi + User t35124p + ProxyCommand ssh-proxy %h %p + + Host *.fr + PublicKeyAuthentication no + + Host *.su + Cipher none + PasswordAuthentication no + + # Defaults for various options + Host * + ForwardAgent no + ForwardX11 no + PasswordAuthentication yes + RSAAuthentication yes + RhostsRSAAuthentication yes + StrictHostKeyChecking yes + TcpKeepAlive no + IdentityFile ~/.ssh/identity + Port 22 + EscapeChar ~ + +*/ + +/* Keyword tokens. */ + +typedef enum { + oBadOption, + oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts, + oPasswordAuthentication, oRSAAuthentication, + oChallengeResponseAuthentication, oXAuthLocation, + oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward, + oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand, + oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts, + oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression, + oCompressionLevel, oTCPKeepAlive, oNumberOfPasswordPrompts, + oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs, + oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication, + oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias, + oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, + oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, + oClearAllForwardings, oNoHostAuthenticationForLocalhost, + oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, + oAddressFamily, oGssAuthentication, oGssDelegateCreds, + oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, + oSendEnv, oControlPath, oControlMaster, + oDeprecated, oUnsupported +} OpCodes; + +/* Textual representations of the tokens. */ + +static struct { + const char *name; + OpCodes opcode; +} keywords[] = { + { "forwardagent", oForwardAgent }, + { "forwardx11", oForwardX11 }, + { "forwardx11trusted", oForwardX11Trusted }, + { "xauthlocation", oXAuthLocation }, + { "gatewayports", oGatewayPorts }, + { "useprivilegedport", oUsePrivilegedPort }, + { "rhostsauthentication", oDeprecated }, + { "passwordauthentication", oPasswordAuthentication }, + { "kbdinteractiveauthentication", oKbdInteractiveAuthentication }, + { "kbdinteractivedevices", oKbdInteractiveDevices }, + { "rsaauthentication", oRSAAuthentication }, + { "pubkeyauthentication", oPubkeyAuthentication }, + { "dsaauthentication", oPubkeyAuthentication }, /* alias */ + { "rhostsrsaauthentication", oRhostsRSAAuthentication }, + { "hostbasedauthentication", oHostbasedAuthentication }, + { "challengeresponseauthentication", oChallengeResponseAuthentication }, + { "skeyauthentication", oChallengeResponseAuthentication }, /* alias */ + { "tisauthentication", oChallengeResponseAuthentication }, /* alias */ + { "kerberosauthentication", oUnsupported }, + { "kerberostgtpassing", oUnsupported }, + { "afstokenpassing", oUnsupported }, +#if defined(GSSAPI) + { "gssapiauthentication", oGssAuthentication }, + { "gssapidelegatecredentials", oGssDelegateCreds }, +#else + { "gssapiauthentication", oUnsupported }, + { "gssapidelegatecredentials", oUnsupported }, +#endif + { "fallbacktorsh", oDeprecated }, + { "usersh", oDeprecated }, + { "identityfile", oIdentityFile }, + { "identityfile2", oIdentityFile }, /* alias */ + { "identitiesonly", oIdentitiesOnly }, + { "hostname", oHostName }, + { "hostkeyalias", oHostKeyAlias }, + { "proxycommand", oProxyCommand }, + { "port", oPort }, + { "cipher", oCipher }, + { "ciphers", oCiphers }, + { "macs", oMacs }, + { "protocol", oProtocol }, + { "remoteforward", oRemoteForward }, + { "localforward", oLocalForward }, + { "user", oUser }, + { "host", oHost }, + { "escapechar", oEscapeChar }, + { "globalknownhostsfile", oGlobalKnownHostsFile }, + { "userknownhostsfile", oUserKnownHostsFile }, /* obsolete */ + { "globalknownhostsfile2", oGlobalKnownHostsFile2 }, + { "userknownhostsfile2", oUserKnownHostsFile2 }, /* obsolete */ + { "connectionattempts", oConnectionAttempts }, + { "batchmode", oBatchMode }, + { "checkhostip", oCheckHostIP }, + { "stricthostkeychecking", oStrictHostKeyChecking }, + { "compression", oCompression }, + { "compressionlevel", oCompressionLevel }, + { "tcpkeepalive", oTCPKeepAlive }, + { "keepalive", oTCPKeepAlive }, /* obsolete */ + { "numberofpasswordprompts", oNumberOfPasswordPrompts }, + { "loglevel", oLogLevel }, + { "dynamicforward", oDynamicForward }, + { "preferredauthentications", oPreferredAuthentications }, + { "hostkeyalgorithms", oHostKeyAlgorithms }, + { "bindaddress", oBindAddress }, +#ifdef SMARTCARD + { "smartcarddevice", oSmartcardDevice }, +#else + { "smartcarddevice", oUnsupported }, +#endif + { "clearallforwardings", oClearAllForwardings }, + { "enablesshkeysign", oEnableSSHKeysign }, + { "verifyhostkeydns", oVerifyHostKeyDNS }, + { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, + { "rekeylimit", oRekeyLimit }, + { "connecttimeout", oConnectTimeout }, + { "addressfamily", oAddressFamily }, + { "serveraliveinterval", oServerAliveInterval }, + { "serveralivecountmax", oServerAliveCountMax }, + { "sendenv", oSendEnv }, + { "controlpath", oControlPath }, + { "controlmaster", oControlMaster }, + { NULL, oBadOption } +}; + +/* + * Adds a local TCP/IP port forward to options. Never returns if there is an + * error. + */ + +void +add_local_forward(Options *options, u_short port, const char *host, + u_short host_port) +{ + Forward *fwd; +#ifndef NO_IPPORT_RESERVED_CONCEPT + extern uid_t original_real_uid; + if (port < IPPORT_RESERVED && original_real_uid != 0) + fatal("Privileged ports can only be forwarded by root."); +#endif + 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, u_short port, const char *host, + u_short 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; +} + +static void +clear_forwardings(Options *options) +{ + int i; + + for (i = 0; i < options->num_local_forwards; i++) + xfree(options->local_forwards[i].host); + options->num_local_forwards = 0; + for (i = 0; i < options->num_remote_forwards; i++) + xfree(options->remote_forwards[i].host); + options->num_remote_forwards = 0; +} + +/* + * Returns the number of the token pointed to by cp or oBadOption. + */ + +static OpCodes +parse_token(const char *cp, const char *filename, int linenum) +{ + u_int i; + + for (i = 0; keywords[i].name; i++) + if (strcasecmp(cp, keywords[i].name) == 0) + return keywords[i].opcode; + + error("%s: line %d: Bad configuration option: %s", + filename, linenum, cp); + return oBadOption; +} + +/* + * Processes a single option line as used in the configuration files. This + * only sets those values that have not already been set. + */ +#define WHITESPACE " \t\r\n" + +int +process_config_line(Options *options, const char *host, + char *line, const char *filename, int linenum, + int *activep) +{ + char buf[256], *s, **charptr, *endofnumber, *keyword, *arg; + int opcode, *intptr, value; + size_t len; + u_short fwd_port, fwd_host_port; + char sfwd_host_port[6]; + + /* Strip trailing whitespace */ + for(len = strlen(line) - 1; len > 0; len--) { + if (strchr(WHITESPACE, line[len]) == NULL) + break; + line[len] = '\0'; + } + + s = line; + /* Get the keyword. (Each line is supposed to begin with a keyword). */ + keyword = strdelim(&s); + /* Ignore leading whitespace. */ + if (*keyword == '\0') + keyword = strdelim(&s); + if (keyword == NULL || !*keyword || *keyword == '\n' || *keyword == '#') + return 0; + + opcode = parse_token(keyword, filename, linenum); + + switch (opcode) { + case oBadOption: + /* don't panic, but count bad options */ + return -1; + /* NOTREACHED */ + case oConnectTimeout: + intptr = &options->connection_timeout; +parse_time: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%s line %d: missing time value.", + filename, linenum); + if ((value = convtime(arg)) == -1) + fatal("%s line %d: invalid time value.", + filename, linenum); + if (*intptr == -1) + *intptr = value; + break; + + case oForwardAgent: + intptr = &options->forward_agent; +parse_flag: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing yes/no argument.", filename, linenum); + value = 0; /* To avoid compiler warning... */ + if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) + value = 1; + else if (strcmp(arg, "no") == 0 || strcmp(arg, "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 oForwardX11Trusted: + intptr = &options->forward_x11_trusted; + goto parse_flag; + + case oGatewayPorts: + intptr = &options->gateway_ports; + goto parse_flag; + + case oUsePrivilegedPort: + intptr = &options->use_privileged_port; + goto parse_flag; + + case oPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; + + case oKbdInteractiveAuthentication: + intptr = &options->kbd_interactive_authentication; + goto parse_flag; + + case oKbdInteractiveDevices: + charptr = &options->kbd_interactive_devices; + goto parse_string; + + case oPubkeyAuthentication: + intptr = &options->pubkey_authentication; + goto parse_flag; + + case oRSAAuthentication: + intptr = &options->rsa_authentication; + goto parse_flag; + + case oRhostsRSAAuthentication: + intptr = &options->rhosts_rsa_authentication; + goto parse_flag; + + case oHostbasedAuthentication: + intptr = &options->hostbased_authentication; + goto parse_flag; + + case oChallengeResponseAuthentication: + intptr = &options->challenge_response_authentication; + goto parse_flag; + + case oGssAuthentication: + intptr = &options->gss_authentication; + goto parse_flag; + + case oGssDelegateCreds: + intptr = &options->gss_deleg_creds; + goto parse_flag; + + case oBatchMode: + intptr = &options->batch_mode; + goto parse_flag; + + case oCheckHostIP: + intptr = &options->check_host_ip; + goto parse_flag; + + case oVerifyHostKeyDNS: + intptr = &options->verify_host_key_dns; + goto parse_yesnoask; + + case oStrictHostKeyChecking: + intptr = &options->strict_host_key_checking; +parse_yesnoask: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing yes/no/ask argument.", + filename, linenum); + value = 0; /* To avoid compiler warning... */ + if (strcmp(arg, "yes") == 0 || strcmp(arg, "true") == 0) + value = 1; + else if (strcmp(arg, "no") == 0 || strcmp(arg, "false") == 0) + value = 0; + else if (strcmp(arg, "ask") == 0) + value = 2; + else + fatal("%.200s line %d: Bad yes/no/ask argument.", filename, linenum); + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oCompression: + intptr = &options->compression; + goto parse_flag; + + case oTCPKeepAlive: + intptr = &options->tcp_keep_alive; + goto parse_flag; + + case oNoHostAuthenticationForLocalhost: + intptr = &options->no_host_authentication_for_localhost; + goto parse_flag; + + case oNumberOfPasswordPrompts: + intptr = &options->number_of_password_prompts; + goto parse_int; + + case oCompressionLevel: + intptr = &options->compression_level; + goto parse_int; + + case oRekeyLimit: + intptr = &options->rekey_limit; + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (arg[0] < '0' || arg[0] > '9') + fatal("%.200s line %d: Bad number.", filename, linenum); + value = strtol(arg, &endofnumber, 10); + if (arg == endofnumber) + fatal("%.200s line %d: Bad number.", filename, linenum); + switch (toupper(*endofnumber)) { + case 'K': + value *= 1<<10; + break; + case 'M': + value *= 1<<20; + break; + case 'G': + value *= 1<<30; + break; + } + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oIdentityFile: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (*activep) { + intptr = &options->num_identity_files; + if (*intptr >= SSH_MAX_IDENTITY_FILES) + fatal("%.200s line %d: Too many identity files specified (max %d).", + filename, linenum, SSH_MAX_IDENTITY_FILES); + charptr = &options->identity_files[*intptr]; + *charptr = xstrdup(arg); + *intptr = *intptr + 1; + } + break; + + case oXAuthLocation: + charptr=&options->xauth_location; + goto parse_string; + + case oUser: + charptr = &options->user; +parse_string: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (*activep && *charptr == NULL) + *charptr = xstrdup(arg); + break; + + case oGlobalKnownHostsFile: + charptr = &options->system_hostfile; + goto parse_string; + + case oUserKnownHostsFile: + charptr = &options->user_hostfile; + goto parse_string; + + case oGlobalKnownHostsFile2: + charptr = &options->system_hostfile2; + goto parse_string; + + case oUserKnownHostsFile2: + charptr = &options->user_hostfile2; + goto parse_string; + + case oHostName: + charptr = &options->hostname; + goto parse_string; + + case oHostKeyAlias: + charptr = &options->host_key_alias; + goto parse_string; + + case oPreferredAuthentications: + charptr = &options->preferred_authentications; + goto parse_string; + + case oBindAddress: + charptr = &options->bind_address; + goto parse_string; + + case oSmartcardDevice: + charptr = &options->smartcard_device; + goto parse_string; + + case oProxyCommand: + if (s == NULL) + fatal("%.200s line %d: Missing argument.", filename, linenum); + charptr = &options->proxy_command; + len = strspn(s, WHITESPACE "="); + if (*activep && *charptr == NULL) + *charptr = xstrdup(s + len); + return 0; + + case oPort: + intptr = &options->port; +parse_int: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (arg[0] < '0' || arg[0] > '9') + fatal("%.200s line %d: Bad number.", filename, linenum); + + /* Octal, decimal, or hex format? */ + value = strtol(arg, &endofnumber, 0); + if (arg == endofnumber) + fatal("%.200s line %d: Bad number.", filename, linenum); + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oConnectionAttempts: + intptr = &options->connection_attempts; + goto parse_int; + + case oCipher: + intptr = &options->cipher; + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + value = cipher_number(arg); + if (value == -1) + fatal("%.200s line %d: Bad cipher '%s'.", + filename, linenum, arg ? arg : ""); + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oCiphers: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (!ciphers_valid(arg)) + fatal("%.200s line %d: Bad SSH2 cipher spec '%s'.", + filename, linenum, arg ? arg : ""); + if (*activep && options->ciphers == NULL) + options->ciphers = xstrdup(arg); + break; + + case oMacs: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (!mac_valid(arg)) + fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.", + filename, linenum, arg ? arg : ""); + if (*activep && options->macs == NULL) + options->macs = xstrdup(arg); + break; + + case oHostKeyAlgorithms: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (!key_names_valid2(arg)) + fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", + filename, linenum, arg ? arg : ""); + if (*activep && options->hostkeyalgorithms == NULL) + options->hostkeyalgorithms = xstrdup(arg); + break; + + case oProtocol: + intptr = &options->protocol; + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + value = proto_spec(arg); + if (value == SSH_PROTO_UNKNOWN) + fatal("%.200s line %d: Bad protocol spec '%s'.", + filename, linenum, arg ? arg : ""); + if (*activep && *intptr == SSH_PROTO_UNKNOWN) + *intptr = value; + break; + + case oLogLevel: + intptr = (int *) &options->log_level; + arg = strdelim(&s); + value = log_level_number(arg); + if (value == SYSLOG_LEVEL_NOT_SET) + fatal("%.200s line %d: unsupported log level '%s'", + filename, linenum, arg ? arg : ""); + if (*activep && (LogLevel) *intptr == SYSLOG_LEVEL_NOT_SET) + *intptr = (LogLevel) value; + break; + + case oLocalForward: + case oRemoteForward: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing port argument.", + filename, linenum); + if ((fwd_port = a2port(arg)) == 0) + fatal("%.200s line %d: Bad listen port.", + filename, linenum); + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing second argument.", + filename, linenum); + if (sscanf(arg, "%255[^:]:%5[0-9]", buf, sfwd_host_port) != 2 && + sscanf(arg, "%255[^/]/%5[0-9]", buf, sfwd_host_port) != 2) + fatal("%.200s line %d: Bad forwarding specification.", + filename, linenum); + if ((fwd_host_port = a2port(sfwd_host_port)) == 0) + fatal("%.200s line %d: Bad forwarding port.", + filename, linenum); + if (*activep) { + if (opcode == oLocalForward) + add_local_forward(options, fwd_port, buf, + fwd_host_port); + else if (opcode == oRemoteForward) + add_remote_forward(options, fwd_port, buf, + fwd_host_port); + } + break; + + case oDynamicForward: + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing port argument.", + filename, linenum); + fwd_port = a2port(arg); + if (fwd_port == 0) + fatal("%.200s line %d: Badly formatted port number.", + filename, linenum); + if (*activep) + add_local_forward(options, fwd_port, "socks", 0); + break; + + case oClearAllForwardings: + intptr = &options->clear_forwardings; + goto parse_flag; + + case oHost: + *activep = 0; + while ((arg = strdelim(&s)) != NULL && *arg != '\0') + if (match_pattern(host, arg)) { + debug("Applying options for %.100s", arg); + *activep = 1; + break; + } + /* Avoid garbage check below, as strdelim is done. */ + return 0; + + case oEscapeChar: + intptr = &options->escape_char; + arg = strdelim(&s); + if (!arg || *arg == '\0') + fatal("%.200s line %d: Missing argument.", filename, linenum); + if (arg[0] == '^' && arg[2] == 0 && + (u_char) arg[1] >= 64 && (u_char) arg[1] < 128) + value = (u_char) arg[1] & 31; + else if (strlen(arg) == 1) + value = (u_char) arg[0]; + else if (strcmp(arg, "none") == 0) + value = SSH_ESCAPECHAR_NONE; + else { + fatal("%.200s line %d: Bad escape character.", + filename, linenum); + /* NOTREACHED */ + value = 0; /* Avoid compiler warning. */ + } + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oAddressFamily: + arg = strdelim(&s); + intptr = &options->address_family; + if (strcasecmp(arg, "inet") == 0) + value = AF_INET; + else if (strcasecmp(arg, "inet6") == 0) + value = AF_INET6; + else if (strcasecmp(arg, "any") == 0) + value = AF_UNSPEC; + else + fatal("Unsupported AddressFamily \"%s\"", arg); + if (*activep && *intptr == -1) + *intptr = value; + break; + + case oEnableSSHKeysign: + intptr = &options->enable_ssh_keysign; + goto parse_flag; + + case oIdentitiesOnly: + intptr = &options->identities_only; + goto parse_flag; + + case oServerAliveInterval: + intptr = &options->server_alive_interval; + goto parse_time; + + case oServerAliveCountMax: + intptr = &options->server_alive_count_max; + goto parse_int; + + case oSendEnv: + while ((arg = strdelim(&s)) != NULL && *arg != '\0') { + if (strchr(arg, '=') != NULL) + fatal("%s line %d: Invalid environment name.", + filename, linenum); + if (options->num_send_env >= MAX_SEND_ENV) + fatal("%s line %d: too many send env.", + filename, linenum); + options->send_env[options->num_send_env++] = + xstrdup(arg); + } + break; + + case oControlPath: + charptr = &options->control_path; + goto parse_string; + + case oControlMaster: + intptr = &options->control_master; + goto parse_yesnoask; + + case oDeprecated: + debug("%s line %d: Deprecated option \"%s\"", + filename, linenum, keyword); + return 0; + + case oUnsupported: + error("%s line %d: Unsupported option \"%s\"", + filename, linenum, keyword); + return 0; + + default: + fatal("process_config_line: Unimplemented opcode %d", opcode); + } + + /* Check that there is no garbage at end of line. */ + if ((arg = strdelim(&s)) != NULL && *arg != '\0') { + fatal("%.200s line %d: garbage at end of line; \"%.200s\".", + filename, linenum, arg); + } + return 0; +} + + +/* + * 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 0. + */ + +int +read_config_file(const char *filename, const char *host, Options *options, + int checkperm) +{ + FILE *f; + char line[1024]; + int active, linenum; + int bad_options = 0; + + /* Open the file. */ + if ((f = fopen(filename, "r")) == NULL) + return 0; + + if (checkperm) { + struct stat sb; + + if (fstat(fileno(f), &sb) == -1) + fatal("fstat %s: %s", filename, strerror(errno)); + if (((sb.st_uid != 0 && sb.st_uid != getuid()) || + (sb.st_mode & 022) != 0)) + fatal("Bad owner or permissions on %s", filename); + } + + 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++; + if (process_config_line(options, host, line, filename, linenum, &active) != 0) + bad_options++; + } + fclose(f); + if (bad_options > 0) + fatal("%s: terminating, %d bad configuration options", + filename, bad_options); + return 1; +} + +/* + * 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->forward_x11_trusted = -1; + options->xauth_location = NULL; + options->gateway_ports = -1; + options->use_privileged_port = -1; + options->rsa_authentication = -1; + options->pubkey_authentication = -1; + options->challenge_response_authentication = -1; + options->gss_authentication = -1; + options->gss_deleg_creds = -1; + options->password_authentication = -1; + options->kbd_interactive_authentication = -1; + options->kbd_interactive_devices = NULL; + options->rhosts_rsa_authentication = -1; + options->hostbased_authentication = -1; + options->batch_mode = -1; + options->check_host_ip = -1; + options->strict_host_key_checking = -1; + options->compression = -1; + options->tcp_keep_alive = -1; + options->compression_level = -1; + options->port = -1; + options->address_family = -1; + options->connection_attempts = -1; + options->connection_timeout = -1; + options->number_of_password_prompts = -1; + options->cipher = -1; + options->ciphers = NULL; + options->macs = NULL; + options->hostkeyalgorithms = NULL; + options->protocol = SSH_PROTO_UNKNOWN; + options->num_identity_files = 0; + options->hostname = NULL; + options->host_key_alias = NULL; + options->proxy_command = NULL; + options->user = NULL; + options->escape_char = -1; + options->system_hostfile = NULL; + options->user_hostfile = NULL; + options->system_hostfile2 = NULL; + options->user_hostfile2 = NULL; + options->num_local_forwards = 0; + options->num_remote_forwards = 0; + options->clear_forwardings = -1; + options->log_level = SYSLOG_LEVEL_NOT_SET; + options->preferred_authentications = NULL; + options->bind_address = NULL; + options->smartcard_device = NULL; + options->enable_ssh_keysign = - 1; + options->no_host_authentication_for_localhost = - 1; + options->identities_only = - 1; + options->rekey_limit = - 1; + options->verify_host_key_dns = -1; + options->server_alive_interval = -1; + options->server_alive_count_max = -1; + options->num_send_env = 0; + options->control_path = NULL; + options->control_master = -1; +} + +/* + * 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) +{ + int len; + + if (options->forward_agent == -1) + options->forward_agent = 0; + if (options->forward_x11 == -1) + options->forward_x11 = 0; + if (options->forward_x11_trusted == -1) + options->forward_x11_trusted = 0; + if (options->xauth_location == NULL) + options->xauth_location = _PATH_XAUTH; + if (options->gateway_ports == -1) + options->gateway_ports = 0; + if (options->use_privileged_port == -1) + options->use_privileged_port = 0; + if (options->rsa_authentication == -1) + options->rsa_authentication = 1; + if (options->pubkey_authentication == -1) + options->pubkey_authentication = 1; + if (options->challenge_response_authentication == -1) + options->challenge_response_authentication = 1; + if (options->gss_authentication == -1) + options->gss_authentication = 0; + if (options->gss_deleg_creds == -1) + options->gss_deleg_creds = 0; + if (options->password_authentication == -1) + options->password_authentication = 1; + if (options->kbd_interactive_authentication == -1) + options->kbd_interactive_authentication = 1; + if (options->rhosts_rsa_authentication == -1) + options->rhosts_rsa_authentication = 0; + if (options->hostbased_authentication == -1) + options->hostbased_authentication = 0; + if (options->batch_mode == -1) + options->batch_mode = 0; + if (options->check_host_ip == -1) + options->check_host_ip = 1; + if (options->strict_host_key_checking == -1) + options->strict_host_key_checking = 2; /* 2 is default */ + if (options->compression == -1) + options->compression = 0; + if (options->tcp_keep_alive == -1) + options->tcp_keep_alive = 1; + if (options->compression_level == -1) + options->compression_level = 6; + if (options->port == -1) + options->port = 0; /* Filled in ssh_connect. */ + if (options->address_family == -1) + options->address_family = AF_UNSPEC; + if (options->connection_attempts == -1) + options->connection_attempts = 1; + if (options->number_of_password_prompts == -1) + options->number_of_password_prompts = 3; + /* Selected in ssh_login(). */ + if (options->cipher == -1) + options->cipher = SSH_CIPHER_NOT_SET; + /* options->ciphers, default set in myproposals.h */ + /* options->macs, default set in myproposals.h */ + /* options->hostkeyalgorithms, default set in myproposals.h */ + if (options->protocol == SSH_PROTO_UNKNOWN) + options->protocol = SSH_PROTO_1|SSH_PROTO_2; + if (options->num_identity_files == 0) { + if (options->protocol & SSH_PROTO_1) { + len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1; + options->identity_files[options->num_identity_files] = + xmalloc(len); + snprintf(options->identity_files[options->num_identity_files++], + len, "~/%.100s", _PATH_SSH_CLIENT_IDENTITY); + } + if (options->protocol & SSH_PROTO_2) { + len = 2 + strlen(_PATH_SSH_CLIENT_ID_RSA) + 1; + options->identity_files[options->num_identity_files] = + xmalloc(len); + snprintf(options->identity_files[options->num_identity_files++], + len, "~/%.100s", _PATH_SSH_CLIENT_ID_RSA); + + len = 2 + strlen(_PATH_SSH_CLIENT_ID_DSA) + 1; + options->identity_files[options->num_identity_files] = + xmalloc(len); + snprintf(options->identity_files[options->num_identity_files++], + len, "~/%.100s", _PATH_SSH_CLIENT_ID_DSA); + } + } + if (options->escape_char == -1) + options->escape_char = '~'; + if (options->system_hostfile == NULL) + options->system_hostfile = _PATH_SSH_SYSTEM_HOSTFILE; + if (options->user_hostfile == NULL) + options->user_hostfile = _PATH_SSH_USER_HOSTFILE; + if (options->system_hostfile2 == NULL) + options->system_hostfile2 = _PATH_SSH_SYSTEM_HOSTFILE2; + if (options->user_hostfile2 == NULL) + options->user_hostfile2 = _PATH_SSH_USER_HOSTFILE2; + if (options->log_level == SYSLOG_LEVEL_NOT_SET) + options->log_level = SYSLOG_LEVEL_INFO; + if (options->clear_forwardings == 1) + clear_forwardings(options); + if (options->no_host_authentication_for_localhost == - 1) + options->no_host_authentication_for_localhost = 0; + if (options->identities_only == -1) + options->identities_only = 0; + if (options->enable_ssh_keysign == -1) + options->enable_ssh_keysign = 0; + if (options->rekey_limit == -1) + options->rekey_limit = 0; + if (options->verify_host_key_dns == -1) + options->verify_host_key_dns = 0; + if (options->server_alive_interval == -1) + options->server_alive_interval = 0; + if (options->server_alive_count_max == -1) + options->server_alive_count_max = 3; + if (options->control_master == -1) + options->control_master = 0; + /* 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 */ + /* options->host_key_alias should not be set by default */ + /* options->preferred_authentications will be set in ssh */ +} diff --git a/crypto/openssh-3.9p1/readconf.h b/crypto/openssh-3.9p1/readconf.h new file mode 100644 index 0000000000..ded4225857 --- /dev/null +++ b/crypto/openssh-3.9p1/readconf.h @@ -0,0 +1,127 @@ +/* $OpenBSD: readconf.h,v 1.64 2004/07/11 17:48:47 deraadt Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Functions for reading the configuration file. + * + * 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". + */ + +#ifndef READCONF_H +#define READCONF_H + +#include "key.h" + +/* Data structure for representing a forwarding request. */ + +typedef struct { + u_short port; /* Port to forward. */ + char *host; /* Host to connect. */ + u_short host_port; /* Port to connect on host. */ +} Forward; +/* Data structure for representing option data. */ + +#define MAX_SEND_ENV 256 + +typedef struct { + int forward_agent; /* Forward authentication agent. */ + int forward_x11; /* Forward X11 display. */ + int forward_x11_trusted; /* Trust Forward X11 display. */ + char *xauth_location; /* Location for xauth program */ + int gateway_ports; /* Allow remote connects to forwarded ports. */ + int use_privileged_port; /* Don't use privileged port if false. */ + int rhosts_rsa_authentication; /* Try rhosts with RSA + * authentication. */ + int rsa_authentication; /* Try RSA authentication. */ + int pubkey_authentication; /* Try ssh2 pubkey authentication. */ + int hostbased_authentication; /* ssh2's rhosts_rsa */ + int challenge_response_authentication; + /* Try S/Key or TIS, authentication. */ + int gss_authentication; /* Try GSS authentication */ + int gss_deleg_creds; /* Delegate GSS credentials */ + int password_authentication; /* Try password + * authentication. */ + int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ + char *kbd_interactive_devices; /* Keyboard-interactive auth devices. */ + int batch_mode; /* Batch mode: do not ask for passwords. */ + int check_host_ip; /* Also keep track of keys for IP address */ + int strict_host_key_checking; /* Strict host key checking. */ + int compression; /* Compress packets in both directions. */ + int compression_level; /* Compression level 1 (fast) to 9 + * (best). */ + int tcp_keep_alive; /* Set SO_KEEPALIVE. */ + LogLevel log_level; /* Level for logging. */ + + int port; /* Port to connect. */ + int address_family; + int connection_attempts; /* Max attempts (seconds) before + * giving up */ + int connection_timeout; /* Max time (seconds) before + * aborting connection attempt */ + int number_of_password_prompts; /* Max number of password + * prompts. */ + int cipher; /* Cipher to use. */ + char *ciphers; /* SSH2 ciphers in order of preference. */ + char *macs; /* SSH2 macs in order of preference. */ + char *hostkeyalgorithms; /* SSH2 server key types in order of preference. */ + int protocol; /* Protocol in order of preference. */ + char *hostname; /* Real host to connect. */ + char *host_key_alias; /* hostname alias for .ssh/known_hosts */ + 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/ssh_known_hosts. */ + char *user_hostfile; /* Path for $HOME/.ssh/known_hosts. */ + char *system_hostfile2; + char *user_hostfile2; + char *preferred_authentications; + char *bind_address; /* local socket address for connection to sshd */ + char *smartcard_device; /* Smartcard reader device */ + int verify_host_key_dns; /* Verify host key using DNS */ + + int num_identity_files; /* Number of files for RSA/DSA identities. */ + char *identity_files[SSH_MAX_IDENTITY_FILES]; + Key *identity_keys[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]; + int clear_forwardings; + + int enable_ssh_keysign; + int rekey_limit; + int no_host_authentication_for_localhost; + int identities_only; + int server_alive_interval; + int server_alive_count_max; + + int num_send_env; + char *send_env[MAX_SEND_ENV]; + + char *control_path; + int control_master; +} Options; + + +void initialize_options(Options *); +void fill_default_options(Options *); +int read_config_file(const char *, const char *, Options *, int); + +int +process_config_line(Options *, const char *, char *, const char *, int, int *); + +void add_local_forward(Options *, u_short, const char *, u_short); +void add_remote_forward(Options *, u_short, const char *, u_short); + +#endif /* READCONF_H */ diff --git a/crypto/openssh-3.9p1/readpass.c b/crypto/openssh-3.9p1/readpass.c new file mode 100644 index 0000000000..eb4f6fdb6d --- /dev/null +++ b/crypto/openssh-3.9p1/readpass.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: readpass.c,v 1.30 2004/06/17 15:10:14 djm Exp $"); + +#include "xmalloc.h" +#include "misc.h" +#include "pathnames.h" +#include "log.h" +#include "ssh.h" + +static char * +ssh_askpass(char *askpass, const char *msg) +{ + pid_t pid; + size_t len; + char *pass; + int p[2], status, ret; + char buf[1024]; + + if (fflush(stdout) != 0) + error("ssh_askpass: fflush: %s", strerror(errno)); + if (askpass == NULL) + fatal("internal error: askpass undefined"); + if (pipe(p) < 0) { + error("ssh_askpass: pipe: %s", strerror(errno)); + return NULL; + } + if ((pid = fork()) < 0) { + error("ssh_askpass: fork: %s", strerror(errno)); + return NULL; + } + if (pid == 0) { + seteuid(getuid()); + setuid(getuid()); + close(p[0]); + if (dup2(p[1], STDOUT_FILENO) < 0) + fatal("ssh_askpass: dup2: %s", strerror(errno)); + execlp(askpass, askpass, msg, (char *) 0); + fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno)); + } + close(p[1]); + + len = ret = 0; + do { + ret = read(p[0], buf + len, sizeof(buf) - 1 - len); + if (ret == -1 && errno == EINTR) + continue; + if (ret <= 0) + break; + len += ret; + } while (sizeof(buf) - 1 - len > 0); + buf[len] = '\0'; + + close(p[0]); + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + break; + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + memset(buf, 0, sizeof(buf)); + return NULL; + } + + buf[strcspn(buf, "\r\n")] = '\0'; + pass = xstrdup(buf); + memset(buf, 0, sizeof(buf)); + return pass; +} + +/* + * Reads a passphrase from /dev/tty with echo turned off/on. Returns the + * passphrase (allocated with xmalloc). Exits if EOF is encountered. If + * RP_ALLOW_STDIN is set, the passphrase will be read from stdin if no + * tty is available + */ +char * +read_passphrase(const char *prompt, int flags) +{ + char *askpass = NULL, *ret, buf[1024]; + int rppflags, use_askpass = 0, ttyfd; + + rppflags = (flags & RP_ECHO) ? RPP_ECHO_ON : RPP_ECHO_OFF; + if (flags & RP_USE_ASKPASS) + use_askpass = 1; + else if (flags & RP_ALLOW_STDIN) { + if (!isatty(STDIN_FILENO)) + use_askpass = 1; + } else { + rppflags |= RPP_REQUIRE_TTY; + ttyfd = open(_PATH_TTY, O_RDWR); + if (ttyfd >= 0) + close(ttyfd); + else + use_askpass = 1; + } + + if ((flags & RP_USE_ASKPASS) && getenv("DISPLAY") == NULL) + return (flags & RP_ALLOW_EOF) ? NULL : xstrdup(""); + + if (use_askpass && getenv("DISPLAY")) { + if (getenv(SSH_ASKPASS_ENV)) + askpass = getenv(SSH_ASKPASS_ENV); + else + askpass = _PATH_SSH_ASKPASS_DEFAULT; + if ((ret = ssh_askpass(askpass, prompt)) == NULL) + if (!(flags & RP_ALLOW_EOF)) + return xstrdup(""); + return ret; + } + + if (readpassphrase(prompt, buf, sizeof buf, rppflags) == NULL) { + if (flags & RP_ALLOW_EOF) + return NULL; + return xstrdup(""); + } + + ret = xstrdup(buf); + memset(buf, 'x', sizeof buf); + return ret; +} diff --git a/crypto/openssh-3.9p1/regress/envpass.sh b/crypto/openssh-3.9p1/regress/envpass.sh new file mode 100644 index 0000000000..5a7e178d81 --- /dev/null +++ b/crypto/openssh-3.9p1/regress/envpass.sh @@ -0,0 +1,51 @@ +# $OpenBSD: envpass.sh,v 1.3 2004/06/22 22:42:02 dtucker Exp $ +# Placed in the Public Domain. + +tid="environment passing" + +# NB accepted env vars are in test-exec.sh (_XXX_TEST_* and _XXX_TEST) + +trace "pass env, don't accept" +verbose "test $tid: pass env, don't accept" +_TEST_ENV=blah ${SSH} -oSendEnv="*" -F $OBJ/ssh_proxy otherhost \ + sh << 'EOF' + test -z "$_TEST_ENV" +EOF +r=$? +if [ $r -ne 0 ]; then + fail "environment found" +fi + +trace "don't pass env, accept" +verbose "test $tid: don't pass env, accept" +${SSH} -F $OBJ/ssh_proxy otherhost \ + sh << 'EOF' + test -z "$_XXX_TEST_A" && test -z "$_XXX_TEST_B" +EOF +r=$? +if [ $r -ne 0 ]; then + fail "environment found" +fi + +trace "pass single env, accept single env" +verbose "test $tid: pass single env, accept single env" +_XXX_TEST=blah ${SSH} -oSendEnv="_XXX_TEST" -F $OBJ/ssh_proxy otherhost \ + sh << 'EOF' + test X"$_XXX_TEST" = X"blah" +EOF +r=$? +if [ $r -ne 0 ]; then + fail "environment not found" +fi + +trace "pass multiple env, accept multiple env" +verbose "test $tid: pass multiple env, accept multiple env" +_XXX_TEST_A=1 _XXX_TEST_B=2 ${SSH} -oSendEnv="_XXX_TEST_*" \ + -F $OBJ/ssh_proxy otherhost \ + sh << 'EOF' + test X"$_XXX_TEST_A" = X"1" -a X"$_XXX_TEST_B" = X"2" +EOF +r=$? +if [ $r -ne 0 ]; then + fail "environment not found" +fi diff --git a/crypto/openssh-3.9p1/regress/multiplex.sh b/crypto/openssh-3.9p1/regress/multiplex.sh new file mode 100644 index 0000000000..dbf2025be9 --- /dev/null +++ b/crypto/openssh-3.9p1/regress/multiplex.sh @@ -0,0 +1,74 @@ +# $OpenBSD: multiplex.sh,v 1.8 2004/06/22 03:12:13 markus Exp $ +# Placed in the Public Domain. + +CTL=$OBJ/ctl-sock + +tid="connection multiplexing" + +DATA=/bin/ls${EXEEXT} +COPY=$OBJ/ls.copy + +start_sshd + +trace "start master, fork to background" +${SSH} -2 -MS$CTL -F $OBJ/ssh_config -oSendEnv="_XXX_TEST" -f somehost sleep 120 + +verbose "test $tid: envpass" +trace "env passing over multiplexed connection" +_XXX_TEST=blah ${SSH} -oSendEnv="_XXX_TEST" -S$CTL otherhost sh << 'EOF' + test X"$_XXX_TEST" = X"blah" +EOF +if [ $? -ne 0 ]; then + fail "environment not found" +fi + +verbose "test $tid: transfer" +rm -f ${COPY} +trace "ssh transfer over multiplexed connection and check result" +${SSH} -S$CTL otherhost cat ${DATA} > ${COPY} +test -f ${COPY} || fail "ssh -Sctl: failed copy ${DATA}" +cmp ${DATA} ${COPY} || fail "ssh -Sctl: corrupted copy of ${DATA}" + +rm -f ${COPY} +trace "ssh transfer over multiplexed connection and check result" +${SSH} -S $CTL otherhost cat ${DATA} > ${COPY} +test -f ${COPY} || fail "ssh -S ctl: failed copy ${DATA}" +cmp ${DATA} ${COPY} || fail "ssh -S ctl: corrupted copy of ${DATA}" + +rm -f ${COPY} +trace "sftp transfer over multiplexed connection and check result" +echo "get ${DATA} ${COPY}" | \ + ${SFTP} -S ${SSH} -oControlPath=$CTL otherhost >/dev/null 2>&1 +test -f ${COPY} || fail "sftp: failed copy ${DATA}" +cmp ${DATA} ${COPY} || fail "sftp: corrupted copy of ${DATA}" + +rm -f ${COPY} +trace "scp transfer over multiplexed connection and check result" +${SCP} -S ${SSH} -oControlPath=$CTL otherhost:${DATA} ${COPY} >/dev/null 2>&1 +test -f ${COPY} || fail "scp: failed copy ${DATA}" +cmp ${DATA} ${COPY} || fail "scp: corrupted copy of ${DATA}" + +rm -f ${COPY} + +for s in 0 1 4 5 44; do + trace "exit status $s over multiplexed connection" + verbose "test $tid: status $s" + ${SSH} -S $CTL otherhost exit $s + r=$? + if [ $r -ne $s ]; then + fail "exit code mismatch for protocol $p: $r != $s" + fi + + # same with early close of stdout/err + trace "exit status $s with early close over multiplexed connection" + ${SSH} -S $CTL -n otherhost \ + exec sh -c \'"sleep 2; exec > /dev/null 2>&1; sleep 3; exit $s"\' + r=$? + if [ $r -ne $s ]; then + fail "exit code (with sleep) mismatch for protocol $p: $r != $s" + fi +done + +# kill master, remove control socket. ssh -MS will exit when sleep exits +$SUDO kill `cat $PIDFILE` +rm -f $CTL diff --git a/crypto/openssh-3.9p1/regress/reexec.sh b/crypto/openssh-3.9p1/regress/reexec.sh new file mode 100644 index 0000000000..39fffefbc3 --- /dev/null +++ b/crypto/openssh-3.9p1/regress/reexec.sh @@ -0,0 +1,87 @@ +# $OpenBSD: reexec.sh,v 1.3 2004/06/25 01:32:44 djm Exp $ +# Placed in the Public Domain. + +tid="reexec tests" + +DATA=/bin/ls +COPY=${OBJ}/copy +SSHD_ORIG=$SSHD +SSHD_COPY=$OBJ/sshd.copy + +# Start a sshd and then delete it +start_sshd_copy_zap () +{ + cp $SSHD_ORIG $SSHD_COPY + SSHD=$SSHD_COPY + start_sshd + rm -f $SSHD_COPY + SSHD=$SSHD_ORIG +} + +verbose "test config passing" +cp $OBJ/sshd_config $OBJ/sshd_config.orig + +start_sshd + +echo "InvalidXXX=no" >> $OBJ/sshd_config + +rm -f ${COPY} +for p in 1 2; do + verbose "$tid: proto $p" + ${SSH} -nqo "Protocol=$p" -F $OBJ/ssh_config somehost \ + cat ${DATA} > ${COPY} + if [ $? -ne 0 ]; then + fail "ssh cat $DATA failed" + fi + cmp ${DATA} ${COPY} || fail "corrupted copy" + rm -f ${COPY} +done + +$SUDO kill `cat $PIDFILE` +rm -f $PIDFILE + +cp $OBJ/sshd_config.orig $OBJ/sshd_config + +verbose "test reexec fallback" + +start_sshd_copy_zap + +rm -f ${COPY} +for p in 1 2; do + verbose "$tid: proto $p" + ${SSH} -nqo "Protocol=$p" -F $OBJ/ssh_config somehost \ + cat ${DATA} > ${COPY} + if [ $? -ne 0 ]; then + fail "ssh cat $DATA failed" + fi + cmp ${DATA} ${COPY} || fail "corrupted copy" + rm -f ${COPY} +done + +$SUDO kill `cat $PIDFILE` +rm -f $PIDFILE + +verbose "test reexec fallback without privsep" + +cp $OBJ/sshd_config.orig $OBJ/sshd_config +echo "UsePrivilegeSeparation=no" >> $OBJ/sshd_config + +start_sshd_copy_zap + +rm -f ${COPY} +for p in 1 2; do + verbose "$tid: proto $p" + ${SSH} -nqo "Protocol=$p" -F $OBJ/ssh_config somehost \ + cat ${DATA} > ${COPY} + if [ $? -ne 0 ]; then + fail "ssh cat $DATA failed" + fi + cmp ${DATA} ${COPY} || fail "corrupted copy" + rm -f ${COPY} +done + +$SUDO kill `cat $PIDFILE` +rm -f $PIDFILE + +cp $OBJ/sshd_config.orig $OBJ/sshd_config + diff --git a/crypto/openssh-3.9p1/regress/scp-ssh-wrapper.sh b/crypto/openssh-3.9p1/regress/scp-ssh-wrapper.sh new file mode 100644 index 0000000000..8e43147731 --- /dev/null +++ b/crypto/openssh-3.9p1/regress/scp-ssh-wrapper.sh @@ -0,0 +1,54 @@ +#!/bin/sh +# $OpenBSD: scp-ssh-wrapper.sh,v 1.1 2004/06/13 13:51:02 dtucker Exp $ +# Placed in the Public Domain. + +printname () { + NAME=$1 + save_IFS=$IFS + IFS=/ + set -- `echo "$NAME"` + IFS="$save_IFS" + while [ $# -ge 1 ] ; do + if [ "x$1" != "x" ]; then + echo "D0755 0 $1" + fi + shift; + done +} + +# discard first 5 args +shift; shift; shift; shift; shift + +BAD="../../../../../../../../../../../../../${DIR}/dotpathdir" + +case "$SCPTESTMODE" in +badserver_0) + echo "D0755 0 /${DIR}/rootpathdir" + echo "C755 2 rootpathfile" + echo "X" + ;; +badserver_1) + echo "D0755 0 $BAD" + echo "C755 2 file" + echo "X" + ;; +badserver_2) + echo "D0755 0 $BAD" + echo "C755 2 file" + echo "X" + ;; +badserver_3) + printname $BAD + echo "C755 2 file" + echo "X" + ;; +badserver_4) + printname $BAD + echo "D0755 0 .." + echo "C755 2 file" + echo "X" + ;; +*) + exec $1 + ;; +esac diff --git a/crypto/openssh-3.9p1/regress/scp.sh b/crypto/openssh-3.9p1/regress/scp.sh new file mode 100644 index 0000000000..703cc08931 --- /dev/null +++ b/crypto/openssh-3.9p1/regress/scp.sh @@ -0,0 +1,82 @@ +# $OpenBSD: scp.sh,v 1.2 2004/06/16 13:15:09 dtucker Exp $ +# Placed in the Public Domain. + +tid="scp" + +#set -x + +# Figure out if diff understands "-N" +if diff -N ${SRC}/scp.sh ${SRC}/scp.sh 2>/dev/null; then + DIFFOPT="-rN" +else + DIFFOPT="-r" +fi + +DATA=/bin/ls +COPY=${OBJ}/copy +COPY2=${OBJ}/copy2 +DIR=${COPY}.dd +DIR2=${COPY}.dd2 + +SRC=`dirname ${SCRIPT}` +cp ${SRC}/scp-ssh-wrapper.sh ${OBJ}/scp-ssh-wrapper.exe +chmod 755 ${OBJ}/scp-ssh-wrapper.exe +scpopts="-q -S ${OBJ}/scp-ssh-wrapper.exe" + +scpclean() { + rm -rf ${COPY} ${COPY2} ${DIR} ${DIR2} + mkdir ${DIR} ${DIR2} +} + +verbose "$tid: simple copy local file to remote file" +scpclean +$SCP $scpopts ${DATA} somehost:${COPY} || fail "copy failed" +cmp ${DATA} ${COPY} || fail "corrupted copy" + +verbose "$tid: simple copy remote file to local file" +scpclean +$SCP $scpopts somehost:${DATA} ${COPY} || fail "copy failed" +cmp ${DATA} ${COPY} || fail "corrupted copy" + +verbose "$tid: simple copy local file to remote dir" +scpclean +cp ${DATA} ${COPY} +$SCP $scpopts ${COPY} somehost:${DIR} || fail "copy failed" +cmp ${COPY} ${DIR}/copy || fail "corrupted copy" + +verbose "$tid: simple copy remote file to local dir" +scpclean +cp ${DATA} ${COPY} +$SCP $scpopts somehost:${COPY} ${DIR} || fail "copy failed" +cmp ${COPY} ${DIR}/copy || fail "corrupted copy" + +verbose "$tid: recursive local dir to remote dir" +scpclean +rm -rf ${DIR2} +cp ${DATA} ${DIR}/copy +$SCP $scpopts -r ${DIR} somehost:${DIR2} || fail "copy failed" +diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy" + +verbose "$tid: recursive remote dir to local dir" +scpclean +rm -rf ${DIR2} +cp ${DATA} ${DIR}/copy +$SCP $scpopts -r somehost:${DIR} ${DIR2} || fail "copy failed" +diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy" + +for i in 0 1 2 3 4; do + verbose "$tid: disallow bad server #$i" + SCPTESTMODE=badserver_$i + export DIR SCPTESTMODE + scpclean + $SCP $scpopts somehost:${DATA} ${DIR} >/dev/null 2>/dev/null + [ -d {$DIR}/rootpathdir ] && fail "allows dir relative to root dir" + [ -d ${DIR}/dotpathdir ] && fail "allows dir creation in non-recursive mode" + + scpclean + $SCP -r $scpopts somehost:${DATA} ${DIR2} >/dev/null 2>/dev/null + [ -d ${DIR}/dotpathdir ] && fail "allows dir creation outside of subdir" +done + +scpclean +rm -f ${OBJ}/scp-ssh-wrapper.exe diff --git a/crypto/openssh-3.9p1/rijndael.c b/crypto/openssh-3.9p1/rijndael.c new file mode 100644 index 0000000000..7432ea2e42 --- /dev/null +++ b/crypto/openssh-3.9p1/rijndael.c @@ -0,0 +1,1244 @@ +/* $OpenBSD: rijndael.c,v 1.16 2004/06/23 00:39:38 mouring Exp $ */ + +/** + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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. + */ +#include "includes.h" + +#include +#include + +#include "rijndael.h" + +#define FULL_UNROLL + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +static const u32 Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +static const u32 Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +static const u32 Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +static const u32 Te3[256] = { + + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; +static const u32 Te4[256] = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; +static const u32 Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +static const u32 Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; +static const u32 Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; +static const u32 Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; +static const u32 Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; +static const u32 rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) +#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } + +/** + * Expand the cipher key into the encryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { + int i = 0; + u32 temp; + + rk[0] = GETU32(cipherKey ); + rk[1] = GETU32(cipherKey + 4); + rk[2] = GETU32(cipherKey + 8); + rk[3] = GETU32(cipherKey + 12); + if (keyBits == 128) { + for (;;) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 10; + } + rk += 4; + } + } + rk[4] = GETU32(cipherKey + 16); + rk[5] = GETU32(cipherKey + 20); + if (keyBits == 192) { + for (;;) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + return 12; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(cipherKey + 24); + rk[7] = GETU32(cipherKey + 28); + if (keyBits == 256) { + for (;;) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + return 14; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + rk += 8; + } + } + return 0; +} + +/** + * Expand the cipher key into the decryption key schedule. + * + * @return the number of rounds for the given cipher key size. + */ +static int +rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits, + int have_encrypt) { + int Nr, i, j; + u32 temp; + + if (have_encrypt) { + Nr = have_encrypt; + } else { + /* expand the cipher key: */ + Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits); + } + /* invert the order of the round keys: */ + for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < Nr; i++) { + rk += 4; + rk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + return Nr; +} + +static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) { + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(pt ) ^ rk[0]; + s1 = GETU32(pt + 4) ^ rk[1]; + s2 = GETU32(pt + 8) ^ rk[2]; + s3 = GETU32(pt + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; + if (Nr > 10) { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; + if (Nr > 12) { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += Nr << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = Nr >> 1; + for (;;) { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(ct , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(ct + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(ct + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(ct + 12, s3); +} + +static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) { + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(ct ) ^ rk[0]; + s1 = GETU32(ct + 4) ^ rk[1]; + s2 = GETU32(ct + 8) ^ rk[2]; + s3 = GETU32(ct + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (Nr > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (Nr > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += Nr << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = Nr >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(pt , s0); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(pt + 4, s1); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(pt + 8, s2); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(pt + 12, s3); +} + +void +rijndael_set_key(rijndael_ctx *ctx, u_char *key, int bits, int do_encrypt) +{ + ctx->Nr = rijndaelKeySetupEnc(ctx->ek, key, bits); + if (do_encrypt) { + ctx->decrypt = 0; + memset(ctx->dk, 0, sizeof(ctx->dk)); + } else { + ctx->decrypt = 1; + memcpy(ctx->dk, ctx->ek, sizeof(ctx->dk)); + rijndaelKeySetupDec(ctx->dk, key, bits, ctx->Nr); + } +} + +void +rijndael_decrypt(rijndael_ctx *ctx, u_char *src, u_char *dst) +{ + rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst); +} + +void +rijndael_encrypt(rijndael_ctx *ctx, u_char *src, u_char *dst) +{ + rijndaelEncrypt(ctx->ek, ctx->Nr, src, dst); +} diff --git a/crypto/openssh-3.9p1/rijndael.h b/crypto/openssh-3.9p1/rijndael.h new file mode 100644 index 0000000000..c614bb1887 --- /dev/null +++ b/crypto/openssh-3.9p1/rijndael.h @@ -0,0 +1,51 @@ +/* $OpenBSD: rijndael.h,v 1.12 2001/12/19 07:18:56 deraadt Exp $ */ + +/** + * rijndael-alg-fst.h + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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. + */ +#ifndef __RIJNDAEL_H +#define __RIJNDAEL_H + +#define MAXKC (256/32) +#define MAXKB (256/8) +#define MAXNR 14 + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +/* The structure for key information */ +typedef struct { + int decrypt; + int Nr; /* key-length-dependent number of rounds */ + u32 ek[4*(MAXNR + 1)]; /* encrypt key schedule */ + u32 dk[4*(MAXNR + 1)]; /* decrypt key schedule */ +} rijndael_ctx; + +void rijndael_set_key(rijndael_ctx *, u_char *, int, int); +void rijndael_decrypt(rijndael_ctx *, u_char *, u_char *); +void rijndael_encrypt(rijndael_ctx *, u_char *, u_char *); + +#endif /* __RIJNDAEL_H */ diff --git a/crypto/openssh-3.9p1/rsa.c b/crypto/openssh-3.9p1/rsa.c new file mode 100644 index 0000000000..66561a4213 --- /dev/null +++ b/crypto/openssh-3.9p1/rsa.c @@ -0,0 +1,144 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + * + * + * Copyright (c) 1999 Niels Provos. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Description of the RSA algorithm can be found e.g. from the following + * sources: + * + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1994. + * + * Jennifer Seberry and Josed Pieprzyk: Cryptography: An Introduction to + * Computer Security. Prentice-Hall, 1989. + * + * Man Young Rhee: Cryptography and Secure Data Communications. McGraw-Hill, + * 1994. + * + * R. Rivest, A. Shamir, and L. M. Adleman: Cryptographic Communications + * System and Method. US Patent 4,405,829, 1983. + * + * Hans Riesel: Prime Numbers and Computer Methods for Factorization. + * Birkhauser, 1994. + * + * The RSA Frequently Asked Questions document by RSA Data Security, + * Inc., 1995. + * + * RSA in 3 lines of perl by Adam Back , 1995, as + * included below: + * + * [gone - had to be deleted - what a pity] + */ + +#include "includes.h" +RCSID("$OpenBSD: rsa.c,v 1.24 2001/12/27 18:22:16 markus Exp $"); + +#include "rsa.h" +#include "log.h" +#include "xmalloc.h" + +void +rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key) +{ + u_char *inbuf, *outbuf; + int len, ilen, olen; + + if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e)) + fatal("rsa_public_encrypt() exponent too small or not odd"); + + olen = BN_num_bytes(key->n); + outbuf = xmalloc(olen); + + ilen = BN_num_bytes(in); + inbuf = xmalloc(ilen); + BN_bn2bin(in, inbuf); + + if ((len = RSA_public_encrypt(ilen, inbuf, outbuf, key, + RSA_PKCS1_PADDING)) <= 0) + fatal("rsa_public_encrypt() failed"); + + BN_bin2bn(outbuf, len, out); + + memset(outbuf, 0, olen); + memset(inbuf, 0, ilen); + xfree(outbuf); + xfree(inbuf); +} + +int +rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key) +{ + u_char *inbuf, *outbuf; + int len, ilen, olen; + + olen = BN_num_bytes(key->n); + outbuf = xmalloc(olen); + + ilen = BN_num_bytes(in); + inbuf = xmalloc(ilen); + BN_bn2bin(in, inbuf); + + if ((len = RSA_private_decrypt(ilen, inbuf, outbuf, key, + RSA_PKCS1_PADDING)) <= 0) { + error("rsa_private_decrypt() failed"); + } else { + BN_bin2bn(outbuf, len, out); + } + memset(outbuf, 0, olen); + memset(inbuf, 0, ilen); + xfree(outbuf); + xfree(inbuf); + return len; +} + +/* calculate p-1 and q-1 */ +void +rsa_generate_additional_parameters(RSA *rsa) +{ + BIGNUM *aux; + BN_CTX *ctx; + + if ((aux = BN_new()) == NULL) + fatal("rsa_generate_additional_parameters: BN_new failed"); + if ((ctx = BN_CTX_new()) == NULL) + fatal("rsa_generate_additional_parameters: BN_CTX_new failed"); + + BN_sub(aux, rsa->q, BN_value_one()); + BN_mod(rsa->dmq1, rsa->d, aux, ctx); + + BN_sub(aux, rsa->p, BN_value_one()); + BN_mod(rsa->dmp1, rsa->d, aux, ctx); + + BN_clear_free(aux); + BN_CTX_free(ctx); +} + diff --git a/crypto/openssh-3.9p1/rsa.h b/crypto/openssh-3.9p1/rsa.h new file mode 100644 index 0000000000..957d865522 --- /dev/null +++ b/crypto/openssh-3.9p1/rsa.h @@ -0,0 +1,26 @@ +/* $OpenBSD: rsa.h,v 1.15 2002/03/04 17:27:39 stevesk Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * RSA key generation, encryption and decryption. + * + * 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". + */ + +#ifndef RSA_H +#define RSA_H + +#include +#include + +void rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *); +int rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *); +void rsa_generate_additional_parameters(RSA *); + +#endif /* RSA_H */ diff --git a/crypto/openssh-3.9p1/scard-opensc.c b/crypto/openssh-3.9p1/scard-opensc.c new file mode 100644 index 0000000000..dd2c28df25 --- /dev/null +++ b/crypto/openssh-3.9p1/scard-opensc.c @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2002 Juha Yrjölä. All rights reserved. + * Copyright (c) 2001 Markus Friedl. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +#if defined(SMARTCARD) && defined(USE_OPENSC) + +#include +#include + +#include +#include + +#include "key.h" +#include "log.h" +#include "xmalloc.h" +#include "misc.h" +#include "scard.h" + +#if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE) +#define USE_ENGINE +#define RSA_get_default_method RSA_get_default_openssl_method +#else +#endif + +#ifdef USE_ENGINE +#include +#define sc_get_rsa sc_get_engine +#else +#define sc_get_rsa sc_get_rsa_method +#endif + +static int sc_reader_id; +static sc_context_t *ctx = NULL; +static sc_card_t *card = NULL; +static sc_pkcs15_card_t *p15card = NULL; + +static char *sc_pin = NULL; + +struct sc_priv_data +{ + struct sc_pkcs15_id cert_id; + int ref_count; +}; + +void +sc_close(void) +{ + if (p15card) { + sc_pkcs15_unbind(p15card); + p15card = NULL; + } + if (card) { + sc_disconnect_card(card, 0); + card = NULL; + } + if (ctx) { + sc_release_context(ctx); + ctx = NULL; + } +} + +static int +sc_init(void) +{ + int r; + + r = sc_establish_context(&ctx, "openssh"); + if (r) + goto err; + if (sc_reader_id >= ctx->reader_count) { + r = SC_ERROR_NO_READERS_FOUND; + error("Illegal reader number %d (max %d)", sc_reader_id, + ctx->reader_count -1); + goto err; + } + r = sc_connect_card(ctx->reader[sc_reader_id], 0, &card); + if (r) + goto err; + r = sc_pkcs15_bind(card, &p15card); + if (r) + goto err; + return 0; +err: + sc_close(); + return r; +} + +/* private key operations */ + +static int +sc_prkey_op_init(RSA *rsa, struct sc_pkcs15_object **key_obj_out, + unsigned int usage) +{ + int r; + struct sc_priv_data *priv; + struct sc_pkcs15_object *key_obj; + struct sc_pkcs15_prkey_info *key; + struct sc_pkcs15_object *pin_obj; + struct sc_pkcs15_pin_info *pin; + + priv = (struct sc_priv_data *) RSA_get_app_data(rsa); + if (priv == NULL) + return -1; + if (p15card == NULL) { + sc_close(); + r = sc_init(); + if (r) { + error("SmartCard init failed: %s", sc_strerror(r)); + goto err; + } + } + r = sc_pkcs15_find_prkey_by_id_usage(p15card, &priv->cert_id, + usage, &key_obj); + if (r) { + error("Unable to find private key from SmartCard: %s", + sc_strerror(r)); + goto err; + } + key = key_obj->data; + r = sc_pkcs15_find_pin_by_auth_id(p15card, &key_obj->auth_id, + &pin_obj); + if (r == SC_ERROR_OBJECT_NOT_FOUND) { + /* no pin required */ + r = sc_lock(card); + if (r) { + error("Unable to lock smartcard: %s", sc_strerror(r)); + goto err; + } + *key_obj_out = key_obj; + return 0; + } else if (r) { + error("Unable to find PIN object from SmartCard: %s", + sc_strerror(r)); + goto err; + } + pin = pin_obj->data; + r = sc_lock(card); + if (r) { + error("Unable to lock smartcard: %s", sc_strerror(r)); + goto err; + } + if (sc_pin != NULL) { + r = sc_pkcs15_verify_pin(p15card, pin, sc_pin, + strlen(sc_pin)); + if (r) { + sc_unlock(card); + error("PIN code verification failed: %s", + sc_strerror(r)); + goto err; + } + } + *key_obj_out = key_obj; + return 0; +err: + sc_close(); + return -1; +} + +#define SC_USAGE_DECRYPT SC_PKCS15_PRKEY_USAGE_DECRYPT | \ + SC_PKCS15_PRKEY_USAGE_UNWRAP + +static int +sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, + int padding) +{ + struct sc_pkcs15_object *key_obj; + int r; + + if (padding != RSA_PKCS1_PADDING) + return -1; + r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_DECRYPT); + if (r) + return -1; + r = sc_pkcs15_decipher(p15card, key_obj, SC_ALGORITHM_RSA_PAD_PKCS1, + from, flen, to, flen); + sc_unlock(card); + if (r < 0) { + error("sc_pkcs15_decipher() failed: %s", sc_strerror(r)); + goto err; + } + return r; +err: + sc_close(); + return -1; +} + +#define SC_USAGE_SIGN SC_PKCS15_PRKEY_USAGE_SIGN | \ + SC_PKCS15_PRKEY_USAGE_SIGNRECOVER + +static int +sc_sign(int type, u_char *m, unsigned int m_len, + unsigned char *sigret, unsigned int *siglen, RSA *rsa) +{ + struct sc_pkcs15_object *key_obj; + int r; + unsigned long flags = 0; + + /* XXX: sc_prkey_op_init will search for a pkcs15 private + * key object with the sign or signrecover usage flag set. + * If the signing key has only the non-repudiation flag set + * the key will be rejected as using a non-repudiation key + * for authentication is not recommended. Note: This does not + * prevent the use of a non-repudiation key for authentication + * if the sign or signrecover flag is set as well. + */ + r = sc_prkey_op_init(rsa, &key_obj, SC_USAGE_SIGN); + if (r) + return -1; + /* FIXME: length of sigret correct? */ + /* FIXME: check 'type' and modify flags accordingly */ + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA1; + r = sc_pkcs15_compute_signature(p15card, key_obj, flags, + m, m_len, sigret, RSA_size(rsa)); + sc_unlock(card); + if (r < 0) { + error("sc_pkcs15_compute_signature() failed: %s", + sc_strerror(r)); + goto err; + } + *siglen = r; + return 1; +err: + sc_close(); + return 0; +} + +static int +sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, + int padding) +{ + error("Private key encryption not supported"); + return -1; +} + +/* called on free */ + +static int (*orig_finish)(RSA *rsa) = NULL; + +static int +sc_finish(RSA *rsa) +{ + struct sc_priv_data *priv; + + priv = RSA_get_app_data(rsa); + priv->ref_count--; + if (priv->ref_count == 0) { + free(priv); + sc_close(); + } + if (orig_finish) + orig_finish(rsa); + return 1; +} + +/* engine for overloading private key operations */ + +static RSA_METHOD * +sc_get_rsa_method(void) +{ + static RSA_METHOD smart_rsa; + const RSA_METHOD *def = RSA_get_default_method(); + + /* use the OpenSSL version */ + memcpy(&smart_rsa, def, sizeof(smart_rsa)); + + smart_rsa.name = "opensc"; + + /* overload */ + smart_rsa.rsa_priv_enc = sc_private_encrypt; + smart_rsa.rsa_priv_dec = sc_private_decrypt; + smart_rsa.rsa_sign = sc_sign; + + /* save original */ + orig_finish = def->finish; + smart_rsa.finish = sc_finish; + + return &smart_rsa; +} + +#ifdef USE_ENGINE +static ENGINE * +sc_get_engine(void) +{ + static ENGINE *smart_engine = NULL; + + if ((smart_engine = ENGINE_new()) == NULL) + fatal("ENGINE_new failed"); + + ENGINE_set_id(smart_engine, "opensc"); + ENGINE_set_name(smart_engine, "OpenSC"); + + ENGINE_set_RSA(smart_engine, sc_get_rsa_method()); + ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method()); + ENGINE_set_DH(smart_engine, DH_get_default_openssl_method()); + ENGINE_set_RAND(smart_engine, RAND_SSLeay()); + ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp); + + return smart_engine; +} +#endif + +static void +convert_rsa_to_rsa1(Key * in, Key * out) +{ + struct sc_priv_data *priv; + + out->rsa->flags = in->rsa->flags; + out->flags = in->flags; + RSA_set_method(out->rsa, RSA_get_method(in->rsa)); + BN_copy(out->rsa->n, in->rsa->n); + BN_copy(out->rsa->e, in->rsa->e); + priv = RSA_get_app_data(in->rsa); + priv->ref_count++; + RSA_set_app_data(out->rsa, priv); + return; +} + +static int +sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj) +{ + int r; + sc_pkcs15_cert_t *cert = NULL; + struct sc_priv_data *priv = NULL; + sc_pkcs15_cert_info_t *cinfo = cert_obj->data; + + X509 *x509 = NULL; + EVP_PKEY *pubkey = NULL; + u8 *p; + char *tmp; + + debug("sc_read_pubkey() with cert id %02X", cinfo->id.value[0]); + r = sc_pkcs15_read_certificate(p15card, cinfo, &cert); + if (r) { + logit("Certificate read failed: %s", sc_strerror(r)); + goto err; + } + x509 = X509_new(); + if (x509 == NULL) { + r = -1; + goto err; + } + p = cert->data; + if (!d2i_X509(&x509, &p, cert->data_len)) { + logit("Unable to parse X.509 certificate"); + r = -1; + goto err; + } + sc_pkcs15_free_certificate(cert); + cert = NULL; + pubkey = X509_get_pubkey(x509); + X509_free(x509); + x509 = NULL; + if (pubkey->type != EVP_PKEY_RSA) { + logit("Public key is of unknown type"); + r = -1; + goto err; + } + k->rsa = EVP_PKEY_get1_RSA(pubkey); + EVP_PKEY_free(pubkey); + + k->rsa->flags |= RSA_FLAG_SIGN_VER; + RSA_set_method(k->rsa, sc_get_rsa_method()); + priv = xmalloc(sizeof(struct sc_priv_data)); + priv->cert_id = cinfo->id; + priv->ref_count = 1; + RSA_set_app_data(k->rsa, priv); + + k->flags = KEY_FLAG_EXT; + tmp = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX); + debug("fingerprint %d %s", key_size(k), tmp); + xfree(tmp); + + return 0; +err: + if (cert) + sc_pkcs15_free_certificate(cert); + if (pubkey) + EVP_PKEY_free(pubkey); + if (x509) + X509_free(x509); + return r; +} + +Key ** +sc_get_keys(const char *id, const char *pin) +{ + Key *k, **keys; + int i, r, real_count = 0, key_count; + sc_pkcs15_id_t cert_id; + sc_pkcs15_object_t *certs[32]; + char *buf = xstrdup(id), *p; + + debug("sc_get_keys called: id = %s", id); + + if (sc_pin != NULL) + xfree(sc_pin); + sc_pin = (pin == NULL) ? NULL : xstrdup(pin); + + cert_id.len = 0; + if ((p = strchr(buf, ':')) != NULL) { + *p = 0; + p++; + sc_pkcs15_hex_string_to_id(p, &cert_id); + } + r = sscanf(buf, "%d", &sc_reader_id); + xfree(buf); + if (r != 1) + goto err; + if (p15card == NULL) { + sc_close(); + r = sc_init(); + if (r) { + error("Smartcard init failed: %s", sc_strerror(r)); + goto err; + } + } + if (cert_id.len) { + r = sc_pkcs15_find_cert_by_id(p15card, &cert_id, &certs[0]); + if (r < 0) + goto err; + key_count = 1; + } else { + r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509, + certs, 32); + if (r == 0) { + logit("No certificates found on smartcard"); + r = -1; + goto err; + } else if (r < 0) { + error("Certificate enumeration failed: %s", + sc_strerror(r)); + goto err; + } + key_count = r; + } + keys = xmalloc(sizeof(Key *) * (key_count*2+1)); + for (i = 0; i < key_count; i++) { + sc_pkcs15_object_t *tmp_obj = NULL; + cert_id = ((sc_pkcs15_cert_info_t *)(certs[i]->data))->id; + if (sc_pkcs15_find_prkey_by_id(p15card, &cert_id, &tmp_obj)) + /* skip the public key (certificate) if no + * corresponding private key is present */ + continue; + k = key_new(KEY_RSA); + if (k == NULL) + break; + r = sc_read_pubkey(k, certs[i]); + if (r) { + error("sc_read_pubkey failed: %s", sc_strerror(r)); + key_free(k); + continue; + } + keys[real_count] = k; + real_count++; + k = key_new(KEY_RSA1); + if (k == NULL) + break; + convert_rsa_to_rsa1(keys[real_count-1], k); + keys[real_count] = k; + real_count++; + } + keys[real_count] = NULL; + + return keys; +err: + sc_close(); + return NULL; +} + +int +sc_put_key(Key *prv, const char *id) +{ + error("key uploading not yet supported"); + return -1; +} + +char * +sc_get_key_label(Key *key) +{ + int r; + const struct sc_priv_data *priv; + struct sc_pkcs15_object *key_obj; + + priv = (const struct sc_priv_data *) RSA_get_app_data(key->rsa); + if (priv == NULL || p15card == NULL) { + logit("SmartCard key not loaded"); + /* internal error => return default label */ + return xstrdup("smartcard key"); + } + r = sc_pkcs15_find_prkey_by_id(p15card, &priv->cert_id, &key_obj); + if (r) { + logit("Unable to find private key from SmartCard: %s", + sc_strerror(r)); + return xstrdup("smartcard key"); + } + if (key_obj == NULL || key_obj->label == NULL) + /* the optional PKCS#15 label does not exists + * => return the default label */ + return xstrdup("smartcard key"); + return xstrdup(key_obj->label); +} + +#endif /* SMARTCARD */ diff --git a/crypto/openssh-3.9p1/scard.c b/crypto/openssh-3.9p1/scard.c new file mode 100644 index 0000000000..b3d25058ae --- /dev/null +++ b/crypto/openssh-3.9p1/scard.c @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +#if defined(SMARTCARD) && defined(USE_SECTOK) +RCSID("$OpenBSD: scard.c,v 1.29 2004/05/08 00:21:31 djm Exp $"); + +#include +#include + +#include "key.h" +#include "log.h" +#include "xmalloc.h" +#include "misc.h" +#include "scard.h" + +#if OPENSSL_VERSION_NUMBER < 0x00907000L +#define USE_ENGINE +#define RSA_get_default_method RSA_get_default_openssl_method +#else +#endif + +#ifdef USE_ENGINE +#include +#define sc_get_rsa sc_get_engine +#else +#define sc_get_rsa sc_get_rsa_method +#endif + +#define CLA_SSH 0x05 +#define INS_DECRYPT 0x10 +#define INS_GET_KEYLENGTH 0x20 +#define INS_GET_PUBKEY 0x30 +#define INS_GET_RESPONSE 0xc0 + +#define MAX_BUF_SIZE 256 + +u_char DEFAUT0[] = {0xad, 0x9f, 0x61, 0xfe, 0xfa, 0x20, 0xce, 0x63}; + +static int sc_fd = -1; +static char *sc_reader_id = NULL; +static char *sc_pin = NULL; +static int cla = 0x00; /* class */ + +static void sc_mk_digest(const char *pin, u_char *digest); +static int get_AUT0(u_char *aut0); +static int try_AUT0(void); + +/* interface to libsectok */ + +static int +sc_open(void) +{ + int sw; + + if (sc_fd >= 0) + return sc_fd; + + sc_fd = sectok_friendly_open(sc_reader_id, STONOWAIT, &sw); + if (sc_fd < 0) { + error("sectok_open failed: %s", sectok_get_sw(sw)); + return SCARD_ERROR_FAIL; + } + if (! sectok_cardpresent(sc_fd)) { + debug("smartcard in reader %s not present, skipping", + sc_reader_id); + sc_close(); + return SCARD_ERROR_NOCARD; + } + if (sectok_reset(sc_fd, 0, NULL, &sw) <= 0) { + error("sectok_reset failed: %s", sectok_get_sw(sw)); + sc_fd = -1; + return SCARD_ERROR_FAIL; + } + if ((cla = cyberflex_inq_class(sc_fd)) < 0) + cla = 0; + + debug("sc_open ok %d", sc_fd); + return sc_fd; +} + +static int +sc_enable_applet(void) +{ + static u_char aid[] = {0xfc, 0x53, 0x73, 0x68, 0x2e, 0x62, 0x69, 0x6e}; + int sw = 0; + + /* select applet id */ + sectok_apdu(sc_fd, cla, 0xa4, 0x04, 0, sizeof aid, aid, 0, NULL, &sw); + if (!sectok_swOK(sw)) { + error("sectok_apdu failed: %s", sectok_get_sw(sw)); + sc_close(); + return -1; + } + return 0; +} + +static int +sc_init(void) +{ + int status; + + status = sc_open(); + if (status == SCARD_ERROR_NOCARD) { + return SCARD_ERROR_NOCARD; + } + if (status < 0 ) { + error("sc_open failed"); + return status; + } + if (sc_enable_applet() < 0) { + error("sc_enable_applet failed"); + return SCARD_ERROR_APPLET; + } + return 0; +} + +static int +sc_read_pubkey(Key * k) +{ + u_char buf[2], *n; + char *p; + int len, sw, status = -1; + + len = sw = 0; + n = NULL; + + if (sc_fd < 0) { + if (sc_init() < 0) + goto err; + } + + /* get key size */ + sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL, + sizeof(buf), buf, &sw); + if (!sectok_swOK(sw)) { + error("could not obtain key length: %s", sectok_get_sw(sw)); + goto err; + } + len = (buf[0] << 8) | buf[1]; + len /= 8; + debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw)); + + n = xmalloc(len); + /* get n */ + sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw); + + if (sw == 0x6982) { + if (try_AUT0() < 0) + goto err; + sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw); + } + if (!sectok_swOK(sw)) { + error("could not obtain public key: %s", sectok_get_sw(sw)); + goto err; + } + + debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw)); + + if (BN_bin2bn(n, len, k->rsa->n) == NULL) { + error("c_read_pubkey: BN_bin2bn failed"); + goto err; + } + + /* currently the java applet just stores 'n' */ + if (!BN_set_word(k->rsa->e, 35)) { + error("c_read_pubkey: BN_set_word(e, 35) failed"); + goto err; + } + + status = 0; + p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX); + debug("fingerprint %u %s", key_size(k), p); + xfree(p); + +err: + if (n != NULL) + xfree(n); + sc_close(); + return status; +} + +/* private key operations */ + +static int +sc_private_decrypt(int flen, u_char *from, u_char *to, RSA *rsa, + int padding) +{ + u_char *padded = NULL; + int sw, len, olen, status = -1; + + debug("sc_private_decrypt called"); + + olen = len = sw = 0; + if (sc_fd < 0) { + status = sc_init(); + if (status < 0 ) + goto err; + } + if (padding != RSA_PKCS1_PADDING) + goto err; + + len = BN_num_bytes(rsa->n); + padded = xmalloc(len); + + sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw); + + if (sw == 0x6982) { + if (try_AUT0() < 0) + goto err; + sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, from, len, padded, &sw); + } + if (!sectok_swOK(sw)) { + error("sc_private_decrypt: INS_DECRYPT failed: %s", + sectok_get_sw(sw)); + goto err; + } + olen = RSA_padding_check_PKCS1_type_2(to, len, padded + 1, len - 1, + len); +err: + if (padded) + xfree(padded); + sc_close(); + return (olen >= 0 ? olen : status); +} + +static int +sc_private_encrypt(int flen, u_char *from, u_char *to, RSA *rsa, + int padding) +{ + u_char *padded = NULL; + int sw, len, status = -1; + + len = sw = 0; + if (sc_fd < 0) { + status = sc_init(); + if (status < 0 ) + goto err; + } + if (padding != RSA_PKCS1_PADDING) + goto err; + + debug("sc_private_encrypt called"); + len = BN_num_bytes(rsa->n); + padded = xmalloc(len); + + if (RSA_padding_add_PKCS1_type_1(padded, len, (u_char *)from, flen) <= 0) { + error("RSA_padding_add_PKCS1_type_1 failed"); + goto err; + } + sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw); + if (sw == 0x6982) { + if (try_AUT0() < 0) + goto err; + sectok_apdu(sc_fd, CLA_SSH, INS_DECRYPT, 0, 0, len, padded, len, to, &sw); + } + if (!sectok_swOK(sw)) { + error("sc_private_encrypt: INS_DECRYPT failed: %s", + sectok_get_sw(sw)); + goto err; + } +err: + if (padded) + xfree(padded); + sc_close(); + return (len >= 0 ? len : status); +} + +/* called on free */ + +static int (*orig_finish)(RSA *rsa) = NULL; + +static int +sc_finish(RSA *rsa) +{ + if (orig_finish) + orig_finish(rsa); + sc_close(); + return 1; +} + +/* engine for overloading private key operations */ + +static RSA_METHOD * +sc_get_rsa_method(void) +{ + static RSA_METHOD smart_rsa; + const RSA_METHOD *def = RSA_get_default_method(); + + /* use the OpenSSL version */ + memcpy(&smart_rsa, def, sizeof(smart_rsa)); + + smart_rsa.name = "sectok"; + + /* overload */ + smart_rsa.rsa_priv_enc = sc_private_encrypt; + smart_rsa.rsa_priv_dec = sc_private_decrypt; + + /* save original */ + orig_finish = def->finish; + smart_rsa.finish = sc_finish; + + return &smart_rsa; +} + +#ifdef USE_ENGINE +static ENGINE * +sc_get_engine(void) +{ + static ENGINE *smart_engine = NULL; + + if ((smart_engine = ENGINE_new()) == NULL) + fatal("ENGINE_new failed"); + + ENGINE_set_id(smart_engine, "sectok"); + ENGINE_set_name(smart_engine, "libsectok"); + + ENGINE_set_RSA(smart_engine, sc_get_rsa_method()); + ENGINE_set_DSA(smart_engine, DSA_get_default_openssl_method()); + ENGINE_set_DH(smart_engine, DH_get_default_openssl_method()); + ENGINE_set_RAND(smart_engine, RAND_SSLeay()); + ENGINE_set_BN_mod_exp(smart_engine, BN_mod_exp); + + return smart_engine; +} +#endif + +void +sc_close(void) +{ + if (sc_fd >= 0) { + sectok_close(sc_fd); + sc_fd = -1; + } +} + +Key ** +sc_get_keys(const char *id, const char *pin) +{ + Key *k, *n, **keys; + int status, nkeys = 2; + + if (sc_reader_id != NULL) + xfree(sc_reader_id); + sc_reader_id = xstrdup(id); + + if (sc_pin != NULL) + xfree(sc_pin); + sc_pin = (pin == NULL) ? NULL : xstrdup(pin); + + k = key_new(KEY_RSA); + if (k == NULL) { + return NULL; + } + status = sc_read_pubkey(k); + if (status == SCARD_ERROR_NOCARD) { + key_free(k); + return NULL; + } + if (status < 0 ) { + error("sc_read_pubkey failed"); + key_free(k); + return NULL; + } + keys = xmalloc((nkeys+1) * sizeof(Key *)); + + n = key_new(KEY_RSA1); + BN_copy(n->rsa->n, k->rsa->n); + BN_copy(n->rsa->e, k->rsa->e); + RSA_set_method(n->rsa, sc_get_rsa()); + n->flags |= KEY_FLAG_EXT; + keys[0] = n; + + n = key_new(KEY_RSA); + BN_copy(n->rsa->n, k->rsa->n); + BN_copy(n->rsa->e, k->rsa->e); + RSA_set_method(n->rsa, sc_get_rsa()); + n->flags |= KEY_FLAG_EXT; + keys[1] = n; + + keys[2] = NULL; + + key_free(k); + return keys; +} + +#define NUM_RSA_KEY_ELEMENTS 5+1 +#define COPY_RSA_KEY(x, i) \ + do { \ + len = BN_num_bytes(prv->rsa->x); \ + elements[i] = xmalloc(len); \ + debug("#bytes %d", len); \ + if (BN_bn2bin(prv->rsa->x, elements[i]) < 0) \ + goto done; \ + } while (0) + +static void +sc_mk_digest(const char *pin, u_char *digest) +{ + const EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, pin, strlen(pin)); + EVP_DigestFinal(&md, digest, NULL); +} + +static int +get_AUT0(u_char *aut0) +{ + char *pass; + + pass = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN); + if (pass == NULL) + return -1; + if (!strcmp(pass, "-")) { + memcpy(aut0, DEFAUT0, sizeof DEFAUT0); + return 0; + } + sc_mk_digest(pass, aut0); + memset(pass, 0, strlen(pass)); + xfree(pass); + return 0; +} + +static int +try_AUT0(void) +{ + u_char aut0[EVP_MAX_MD_SIZE]; + + /* permission denied; try PIN if provided */ + if (sc_pin && strlen(sc_pin) > 0) { + sc_mk_digest(sc_pin, aut0); + if (cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) { + error("smartcard passphrase incorrect"); + return (-1); + } + } else { + /* try default AUT0 key */ + if (cyberflex_verify_AUT0(sc_fd, cla, DEFAUT0, 8) < 0) { + /* default AUT0 key failed; prompt for passphrase */ + if (get_AUT0(aut0) < 0 || + cyberflex_verify_AUT0(sc_fd, cla, aut0, 8) < 0) { + error("smartcard passphrase incorrect"); + return (-1); + } + } + } + return (0); +} + +int +sc_put_key(Key *prv, const char *id) +{ + u_char *elements[NUM_RSA_KEY_ELEMENTS]; + u_char key_fid[2]; + u_char AUT0[EVP_MAX_MD_SIZE]; + int len, status = -1, i, fd = -1, ret; + int sw = 0, cla = 0x00; + + for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++) + elements[i] = NULL; + + COPY_RSA_KEY(q, 0); + COPY_RSA_KEY(p, 1); + COPY_RSA_KEY(iqmp, 2); + COPY_RSA_KEY(dmq1, 3); + COPY_RSA_KEY(dmp1, 4); + COPY_RSA_KEY(n, 5); + len = BN_num_bytes(prv->rsa->n); + fd = sectok_friendly_open(id, STONOWAIT, &sw); + if (fd < 0) { + error("sectok_open failed: %s", sectok_get_sw(sw)); + goto done; + } + if (! sectok_cardpresent(fd)) { + error("smartcard in reader %s not present", id); + goto done; + } + ret = sectok_reset(fd, 0, NULL, &sw); + if (ret <= 0) { + error("sectok_reset failed: %s", sectok_get_sw(sw)); + goto done; + } + if ((cla = cyberflex_inq_class(fd)) < 0) { + error("cyberflex_inq_class failed"); + goto done; + } + memcpy(AUT0, DEFAUT0, sizeof(DEFAUT0)); + if (cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) { + if (get_AUT0(AUT0) < 0 || + cyberflex_verify_AUT0(fd, cla, AUT0, sizeof(DEFAUT0)) < 0) { + memset(AUT0, 0, sizeof(DEFAUT0)); + error("smartcard passphrase incorrect"); + goto done; + } + } + memset(AUT0, 0, sizeof(DEFAUT0)); + key_fid[0] = 0x00; + key_fid[1] = 0x12; + if (cyberflex_load_rsa_priv(fd, cla, key_fid, 5, 8*len, elements, + &sw) < 0) { + error("cyberflex_load_rsa_priv failed: %s", sectok_get_sw(sw)); + goto done; + } + if (!sectok_swOK(sw)) + goto done; + logit("cyberflex_load_rsa_priv done"); + key_fid[0] = 0x73; + key_fid[1] = 0x68; + if (cyberflex_load_rsa_pub(fd, cla, key_fid, len, elements[5], + &sw) < 0) { + error("cyberflex_load_rsa_pub failed: %s", sectok_get_sw(sw)); + goto done; + } + if (!sectok_swOK(sw)) + goto done; + logit("cyberflex_load_rsa_pub done"); + status = 0; + +done: + memset(elements[0], '\0', BN_num_bytes(prv->rsa->q)); + memset(elements[1], '\0', BN_num_bytes(prv->rsa->p)); + memset(elements[2], '\0', BN_num_bytes(prv->rsa->iqmp)); + memset(elements[3], '\0', BN_num_bytes(prv->rsa->dmq1)); + memset(elements[4], '\0', BN_num_bytes(prv->rsa->dmp1)); + memset(elements[5], '\0', BN_num_bytes(prv->rsa->n)); + + for (i = 0; i < NUM_RSA_KEY_ELEMENTS; i++) + if (elements[i]) + xfree(elements[i]); + if (fd != -1) + sectok_close(fd); + return (status); +} + +char * +sc_get_key_label(Key *key) +{ + return xstrdup("smartcard key"); +} + +#endif /* SMARTCARD && USE_SECTOK */ diff --git a/crypto/openssh-3.9p1/scard.h b/crypto/openssh-3.9p1/scard.h new file mode 100644 index 0000000000..9ba20a361b --- /dev/null +++ b/crypto/openssh-3.9p1/scard.h @@ -0,0 +1,41 @@ +/* $OpenBSD: scard.h,v 1.12 2003/06/12 19:12:03 markus Exp $ */ + +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SCARD_H +#define SCARD_H + +#include "key.h" + +#define SCARD_ERROR_FAIL -1 +#define SCARD_ERROR_NOCARD -2 +#define SCARD_ERROR_APPLET -3 + +Key **sc_get_keys(const char *, const char *); +void sc_close(void); +int sc_put_key(Key *, const char *); +char *sc_get_key_label(Key *); + +#endif diff --git a/crypto/openssh-3.9p1/scp.1 b/crypto/openssh-3.9p1/scp.1 new file mode 100644 index 0000000000..f346b2ae96 --- /dev/null +++ b/crypto/openssh-3.9p1/scp.1 @@ -0,0 +1,218 @@ +.\" -*- nroff -*- +.\" +.\" scp.1 +.\" +.\" Author: Tatu Ylonen +.\" +.\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +.\" All rights reserved +.\" +.\" Created: Sun May 7 00:14:37 1995 ylo +.\" +.\" $OpenBSD: scp.1,v 1.36 2004/06/13 15:03:02 djm Exp $ +.\" +.Dd September 25, 1999 +.Dt SCP 1 +.Os +.Sh NAME +.Nm scp +.Nd secure copy (remote file copy program) +.Sh SYNOPSIS +.Nm scp +.Bk -words +.Op Fl 1246BCpqrv +.Op Fl c Ar cipher +.Op Fl F Ar ssh_config +.Op Fl i Ar identity_file +.Op Fl l Ar limit +.Op Fl o Ar ssh_option +.Op Fl P Ar port +.Op Fl S Ar program +.Sm off +.Oo +.Op Ar user No @ +.Ar host1 No : +.Oc Ns Ar file1 +.Sm on +.Op Ar ... +.Sm off +.Oo +.Op Ar user No @ +.Ar host2 No : +.Oc Ar file2 +.Sm on +.Ek +.Sh DESCRIPTION +.Nm +copies files between hosts on a network. +It uses +.Xr ssh 1 +for data transfer, and uses the same authentication and provides the +same security as +.Xr ssh 1 . +Unlike +.Xr rcp 1 , +.Nm +will ask for passwords or passphrases if they are needed for +authentication. +.Pp +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. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 1 +Forces +.Nm +to use protocol 1. +.It Fl 2 +Forces +.Nm +to use protocol 2. +.It Fl 4 +Forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +Forces +.Nm +to use IPv6 addresses only. +.It Fl B +Selects batch mode (prevents asking for passwords or passphrases). +.It Fl C +Compression enable. +Passes the +.Fl C +flag to +.Xr ssh 1 +to enable compression. +.It Fl c Ar cipher +Selects the cipher to use for encrypting the data transfer. +This option is directly passed to +.Xr ssh 1 . +.It Fl F Ar ssh_config +Specifies an alternative +per-user configuration file for +.Nm ssh . +This option is directly passed to +.Xr ssh 1 . +.It Fl i Ar identity_file +Selects the file from which the identity (private key) for RSA +authentication is read. +This option is directly passed to +.Xr ssh 1 . +.It Fl l Ar limit +Limits the used bandwidth, specified in Kbit/s. +.It Fl o Ar ssh_option +Can be used to pass options to +.Nm ssh +in the format used in +.Xr ssh_config 5 . +This is useful for specifying options +for which there is no separate +.Nm scp +command-line flag. +For full details of the options listed below, and their possible values, see +.Xr ssh_config 5 . +.Pp +.Bl -tag -width Ds -offset indent -compact +.It AddressFamily +.It BatchMode +.It BindAddress +.It ChallengeResponseAuthentication +.It CheckHostIP +.It Cipher +.It Ciphers +.It Compression +.It CompressionLevel +.It ConnectionAttempts +.It ConnectTimeout +.It ControlMaster +.It ControlPath +.It GlobalKnownHostsFile +.It GSSAPIAuthentication +.It GSSAPIDelegateCredentials +.It Host +.It HostbasedAuthentication +.It HostKeyAlgorithms +.It HostKeyAlias +.It HostName +.It IdentityFile +.It IdentitiesOnly +.It LogLevel +.It MACs +.It NoHostAuthenticationForLocalhost +.It NumberOfPasswordPrompts +.It PasswordAuthentication +.It Port +.It PreferredAuthentications +.It Protocol +.It ProxyCommand +.It PubkeyAuthentication +.It RhostsRSAAuthentication +.It RSAAuthentication +.It SendEnv +.It ServerAliveInterval +.It ServerAliveCountMax +.It SmartcardDevice +.It StrictHostKeyChecking +.It TCPKeepAlive +.It UsePrivilegedPort +.It User +.It UserKnownHostsFile +.It VerifyHostKeyDNS +.El +.It Fl P Ar port +Specifies the port to connect to on the remote host. +Note that this option is written with a capital +.Sq P , +because +.Fl p +is already reserved for preserving the times and modes of the file in +.Xr rcp 1 . +.It Fl p +Preserves modification times, access times, and modes from the +original file. +.It Fl q +Disables the progress meter. +.It Fl r +Recursively copy entire directories. +.It Fl S Ar program +Name of +.Ar program +to use for the encrypted connection. +The program must understand +.Xr ssh 1 +options. +.It Fl v +Verbose mode. +Causes +.Nm +and +.Xr ssh 1 +to print debugging messages about their progress. +This is helpful in +debugging connection, authentication, and configuration problems. +.El +.Sh DIAGNOSTICS +.Nm +exits with 0 on success or >0 if an error occurred. +.Sh SEE ALSO +.Xr rcp 1 , +.Xr sftp 1 , +.Xr ssh 1 , +.Xr ssh-add 1 , +.Xr ssh-agent 1 , +.Xr ssh-keygen 1 , +.Xr ssh_config 5 , +.Xr sshd 8 +.Sh HISTORY +.Nm +is based on the +.Xr rcp 1 +program in BSD source code from the Regents of the University of +California. +.Sh AUTHORS +.An Timo Rinne Aq tri@iki.fi +.An Tatu Ylonen Aq ylo@cs.hut.fi diff --git a/crypto/openssh-3.9p1/scp.c b/crypto/openssh-3.9p1/scp.c new file mode 100644 index 0000000000..ef9eaa1a41 --- /dev/null +++ b/crypto/openssh-3.9p1/scp.c @@ -0,0 +1,1140 @@ +/* + * 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 , Tatu Ylonen + * + * 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". + */ +/* + * Copyright (c) 1999 Theo de Raadt. All rights reserved. + * Copyright (c) 1999 Aaron Campbell. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Parts from: + * + * 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. 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. + * + */ + +#include "includes.h" +RCSID("$OpenBSD: scp.c,v 1.117 2004/08/11 21:44:32 avsm Exp $"); + +#include "xmalloc.h" +#include "atomicio.h" +#include "pathnames.h" +#include "log.h" +#include "misc.h" +#include "progressmeter.h" + +extern char *__progname; + +void bwlimit(int); + +/* Struct for addargs */ +arglist args; + +/* Bandwidth limit */ +off_t limit_rate = 0; + +/* Name of current file being transferred. */ +char *curfile; + +/* This is set to non-zero to enable verbose mode. */ +int verbose_mode = 0; + +/* This is set to zero if the progressmeter is not desired. */ +int showprogress = 1; + +/* This is the program to execute for the secured connection. ("ssh" or -S) */ +char *ssh_program = _PATH_SSH_PROGRAM; + +/* This is used to store the pid of ssh_program */ +pid_t do_cmd_pid = -1; + +static void +killchild(int signo) +{ + if (do_cmd_pid > 1) + kill(do_cmd_pid, signo); + + _exit(1); +} + +/* + * 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 argc) +{ + int pin[2], pout[2], reserved[2]; + + if (verbose_mode) + fprintf(stderr, + "Executing: program %s host %s, user %s, command %s\n", + ssh_program, 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]); + + /* Fork a child to execute the command on the remote host using ssh. */ + do_cmd_pid = fork(); + if (do_cmd_pid == 0) { + /* Child. */ + close(pin[1]); + close(pout[0]); + dup2(pin[0], 0); + dup2(pout[1], 1); + close(pin[0]); + close(pout[1]); + + args.list[0] = ssh_program; + if (remuser != NULL) + addargs(&args, "-l%s", remuser); + addargs(&args, "%s", host); + addargs(&args, "%s", cmd); + + execvp(ssh_program, args.list); + perror(ssh_program); + exit(1); + } else if (do_cmd_pid == -1) { + fatal("fork: %s", strerror(errno)); + } + /* Parent. Close the other side, and return the local side. */ + close(pin[0]); + *fdout = pin[1]; + close(pout[1]); + *fdin = pout[0]; + signal(SIGTERM, killchild); + signal(SIGINT, killchild); + signal(SIGHUP, killchild); + return 0; +} + +typedef struct { + int cnt; + char *buf; +} BUF; + +BUF *allocbuf(BUF *, int, int); +void lostconn(int); +void nospace(void); +int okname(char *); +void run_err(const char *,...); +void verifydir(char *); + +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(int argc, char **argv) +{ + int ch, fflag, tflag, status; + double speed; + char *targ, *endp; + extern char *optarg; + extern int optind; + + __progname = ssh_get_progname(argv[0]); + + args.list = NULL; + addargs(&args, "ssh"); /* overwritten with ssh_program */ + addargs(&args, "-x"); + addargs(&args, "-oForwardAgent no"); + addargs(&args, "-oClearAllForwardings yes"); + + fflag = tflag = 0; + while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1) + switch (ch) { + /* User-visible flags. */ + case '1': + case '2': + case '4': + case '6': + case 'C': + addargs(&args, "-%c", ch); + break; + case 'o': + case 'c': + case 'i': + case 'F': + addargs(&args, "-%c%s", ch, optarg); + break; + case 'P': + addargs(&args, "-p%s", optarg); + break; + case 'B': + addargs(&args, "-oBatchmode yes"); + break; + case 'l': + speed = strtod(optarg, &endp); + if (speed <= 0 || *endp != '\0') + usage(); + limit_rate = speed * 1024; + break; + case 'p': + pflag = 1; + break; + case 'r': + iamrecursive = 1; + break; + case 'S': + ssh_program = xstrdup(optarg); + break; + case 'v': + addargs(&args, "-v"); + verbose_mode = 1; + break; + case 'q': + addargs(&args, "-q"); + showprogress = 0; + break; + + /* Server options. */ + case 'd': + targetshouldbedirectory = 1; + break; + case 'f': /* "from" */ + iamremote = 1; + fflag = 1; + break; + case 't': /* "to" */ + iamremote = 1; + tflag = 1; +#ifdef HAVE_CYGWIN + setmode(0, O_BINARY); +#endif + break; + default: + usage(); + } + argc -= optind; + argv += optind; + + if ((pwd = getpwuid(userid = getuid())) == NULL) + fatal("unknown user %u", (u_int) userid); + + if (!isatty(STDERR_FILENO)) + showprogress = 0; + + 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; + do_cmd_pid = -1; + /* Command to be executed on remote system using "ssh". */ + (void) snprintf(cmd, sizeof cmd, "scp%s%s%s%s", + verbose_mode ? " -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]); + } + /* + * Finally check the exit status of the ssh process, if one was forked + * and no error has occured yet + */ + if (do_cmd_pid != -1 && errs == 0) { + if (remin != -1) + (void) close(remin); + if (remout != -1) + (void) close(remout); + if (waitpid(do_cmd_pid, &status, 0) == -1) + errs = 1; + else { + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + errs = 1; + } + } + exit(errs != 0); +} + +void +toremote(char *targ, int argc, char **argv) +{ + int i, len; + char *bp, *host, *src, *suser, *thost, *tuser; + + *targ++ = 0; + if (*targ == 0) + targ = "."; + + if ((thost = strrchr(argv[argc - 1], '@'))) { + /* user@host */ + *thost++ = 0; + tuser = argv[argc - 1]; + if (*tuser == '\0') + tuser = NULL; + } else { + thost = argv[argc - 1]; + tuser = NULL; + } + + for (i = 0; i < argc - 1; i++) { + src = colon(argv[i]); + if (src) { /* remote to remote */ + static char *ssh_options = + "-x -o'ClearAllForwardings yes'"; + *src++ = 0; + if (*src == 0) + src = "."; + host = strrchr(argv[i], '@'); + len = strlen(ssh_program) + strlen(argv[i]) + + strlen(src) + (tuser ? strlen(tuser) : 0) + + strlen(thost) + strlen(targ) + + strlen(ssh_options) + CMDNEEDS + 20; + bp = xmalloc(len); + if (host) { + *host++ = 0; + host = cleanhostname(host); + suser = argv[i]; + if (*suser == '\0') + suser = pwd->pw_name; + else if (!okname(suser)) { + xfree(bp); + continue; + } + if (tuser && !okname(tuser)) { + xfree(bp); + continue; + } + snprintf(bp, len, + "%s%s %s -n " + "-l %s %s %s %s '%s%s%s:%s'", + ssh_program, verbose_mode ? " -v" : "", + ssh_options, suser, host, cmd, src, + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); + } else { + host = cleanhostname(argv[i]); + snprintf(bp, len, + "exec %s%s %s -n %s " + "%s %s '%s%s%s:%s'", + ssh_program, verbose_mode ? " -v" : "", + ssh_options, host, cmd, src, + tuser ? tuser : "", tuser ? "@" : "", + thost, targ); + } + if (verbose_mode) + fprintf(stderr, "Executing: %s\n", bp); + if (system(bp) != 0) + errs = 1; + (void) xfree(bp); + } else { /* local to remote */ + if (remin == -1) { + len = strlen(targ) + CMDNEEDS + 20; + bp = xmalloc(len); + (void) snprintf(bp, len, "%s -t %s", cmd, targ); + host = cleanhostname(thost); + if (do_cmd(host, tuser, bp, &remin, + &remout, argc) < 0) + exit(1); + if (response() < 0) + exit(1); + (void) xfree(bp); + } + source(1, argv + i); + } + } +} + +void +tolocal(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) snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, + iamrecursive ? " -r" : "", pflag ? " -p" : "", + argv[i], argv[argc - 1]); + if (verbose_mode) + fprintf(stderr, "Executing: %s\n", bp); + if (system(bp)) + ++errs; + (void) xfree(bp); + continue; + } + *src++ = 0; + if (*src == 0) + src = "."; + if ((host = strrchr(argv[i], '@')) == NULL) { + host = argv[i]; + suser = NULL; + } else { + *host++ = 0; + suser = argv[i]; + if (*suser == '\0') + suser = pwd->pw_name; + } + host = cleanhostname(host); + len = strlen(src) + CMDNEEDS + 20; + bp = xmalloc(len); + (void) snprintf(bp, len, "%s -f %s", cmd, src); + if (do_cmd(host, suser, bp, &remin, &remout, argc) < 0) { + (void) xfree(bp); + ++errs; + continue; + } + xfree(bp); + sink(1, argv + argc - 1); + (void) close(remin); + remin = remout = -1; + } +} + +void +source(int argc, char **argv) +{ + struct stat stb; + static BUF buffer; + BUF *bp; + off_t i, amt, result, statbytes; + int fd, haderr, indx; + char *last, *name, buf[2048]; + int len; + + for (indx = 0; indx < argc; ++indx) { + name = argv[indx]; + statbytes = 0; + len = strlen(name); + while (len > 1 && name[len-1] == '/') + name[--len] = '\0'; + if (strchr(name, '\n') != NULL) { + run_err("%s: skipping, filename contains a newline", + name); + goto next; + } + 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; + curfile = last; + if (pflag) { + /* + * Make it compatible with possible future + * versions expecting microseconds. + */ + (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n", + (u_long) stb.st_mtime, + (u_long) stb.st_atime); + (void) atomicio(vwrite, remout, buf, strlen(buf)); + if (response() < 0) + goto next; + } +#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) + snprintf(buf, sizeof buf, "C%04o %lld %s\n", + (u_int) (stb.st_mode & FILEMODEMASK), + (int64_t)stb.st_size, last); + if (verbose_mode) { + fprintf(stderr, "Sending file modes: %s", buf); + } + (void) atomicio(vwrite, remout, buf, strlen(buf)); + if (response() < 0) + goto next; + if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { +next: (void) close(fd); + continue; + } + if (showprogress) + start_progress_meter(curfile, stb.st_size, &statbytes); + /* 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 = atomicio(read, fd, bp->buf, amt); + if (result != amt) + haderr = result >= 0 ? EIO : errno; + } + if (haderr) + (void) atomicio(vwrite, remout, bp->buf, amt); + else { + result = atomicio(vwrite, remout, bp->buf, amt); + if (result != amt) + haderr = result >= 0 ? EIO : errno; + statbytes += result; + } + if (limit_rate) + bwlimit(amt); + } + if (showprogress) + stop_progress_meter(); + + if (close(fd) < 0 && !haderr) + haderr = errno; + if (!haderr) + (void) atomicio(vwrite, remout, "", 1); + else + run_err("%s: %s", name, strerror(haderr)); + (void) response(); + } +} + +void +rsource(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) snprintf(path, sizeof(path), "T%lu 0 %lu 0\n", + (u_long) statp->st_mtime, + (u_long) statp->st_atime); + (void) atomicio(vwrite, remout, path, strlen(path)); + if (response() < 0) { + closedir(dirp); + return; + } + } + (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", + (u_int) (statp->st_mode & FILEMODEMASK), 0, last); + if (verbose_mode) + fprintf(stderr, "Entering directory: %s", path); + (void) atomicio(vwrite, remout, path, strlen(path)); + if (response() < 0) { + closedir(dirp); + return; + } + while ((dp = readdir(dirp)) != NULL) { + 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) snprintf(path, sizeof path, "%s/%s", name, dp->d_name); + vect[0] = path; + source(1, vect); + } + (void) closedir(dirp); + (void) atomicio(vwrite, remout, "E\n", 2); + (void) response(); +} + +void +bwlimit(int amount) +{ + static struct timeval bwstart, bwend; + static int lamt, thresh = 16384; + u_int64_t waitlen; + struct timespec ts, rm; + + if (!timerisset(&bwstart)) { + gettimeofday(&bwstart, NULL); + return; + } + + lamt += amount; + if (lamt < thresh) + return; + + gettimeofday(&bwend, NULL); + timersub(&bwend, &bwstart, &bwend); + if (!timerisset(&bwend)) + return; + + lamt *= 8; + waitlen = (double)1000000L * lamt / limit_rate; + + bwstart.tv_sec = waitlen / 1000000L; + bwstart.tv_usec = waitlen % 1000000L; + + if (timercmp(&bwstart, &bwend, >)) { + timersub(&bwstart, &bwend, &bwend); + + /* Adjust the wait time */ + if (bwend.tv_sec) { + thresh /= 2; + if (thresh < 2048) + thresh = 2048; + } else if (bwend.tv_usec < 100) { + thresh *= 2; + if (thresh > 32768) + thresh = 32768; + } + + TIMEVAL_TO_TIMESPEC(&bwend, &ts); + while (nanosleep(&ts, &rm) == -1) { + if (errno != EINTR) + break; + ts = rm; + } + } + + lamt = 0; + gettimeofday(&bwstart, NULL); +} + +void +sink(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; + off_t size, statbytes; + int setimes, targisdir, wrerrno = 0; + char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; + struct timeval tv[2]; + +#define atime tv[0] +#define mtime tv[1] +#define SCREWUP(str) do { why = str; goto screwup; } while (0) + + 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) atomicio(vwrite, remout, "", 1); + if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) + targisdir = 1; + for (first = 1;; first = 0) { + cp = buf; + if (atomicio(read, remin, cp, 1) <= 0) + return; + if (*cp++ == '\n') + SCREWUP("unexpected "); + do { + if (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) + SCREWUP("lost connection"); + *cp++ = ch; + } while (cp < &buf[sizeof(buf) - 1] && ch != '\n'); + *cp = 0; + if (verbose_mode) + fprintf(stderr, "Sink: %s", buf); + + if (buf[0] == '\01' || buf[0] == '\02') { + if (iamremote == 0) + (void) atomicio(vwrite, STDERR_FILENO, + buf + 1, strlen(buf + 1)); + if (buf[0] == '\02') + exit(1); + ++errs; + continue; + } + if (buf[0] == 'E') { + (void) atomicio(vwrite, remout, "", 1); + return; + } + if (ch == '\n') + *--cp = 0; + + cp = buf; + if (*cp == 'T') { + setimes++; + cp++; + mtime.tv_sec = strtol(cp, &cp, 10); + if (!cp || *cp++ != ' ') + SCREWUP("mtime.sec not delimited"); + mtime.tv_usec = strtol(cp, &cp, 10); + if (!cp || *cp++ != ' ') + SCREWUP("mtime.usec not delimited"); + atime.tv_sec = strtol(cp, &cp, 10); + if (!cp || *cp++ != ' ') + SCREWUP("atime.sec not delimited"); + atime.tv_usec = strtol(cp, &cp, 10); + if (!cp || *cp++ != '\0') + SCREWUP("atime.usec not delimited"); + (void) atomicio(vwrite, 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; isdigit(*cp);) + size = size * 10 + (*cp++ - '0'); + if (*cp++ != ' ') + SCREWUP("size not delimited"); + if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) { + run_err("error: unexpected filename: %s", cp); + exit(1); + } + if (targisdir) { + static char *namebuf; + static int cursize; + size_t need; + + need = strlen(targ) + strlen(cp) + 250; + if (need > cursize) { + if (namebuf) + xfree(namebuf); + namebuf = xmalloc(need); + cursize = need; + } + (void) snprintf(namebuf, need, "%s%s%s", targ, + strcmp(targ, "/") ? "/" : "", cp); + np = namebuf; + } else + np = targ; + curfile = cp; + exists = stat(np, &stb) == 0; + if (buf[0] == 'D') { + int mod_flag = pflag; + if (!iamrecursive) + SCREWUP("received directory without -r"); + 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] = xstrdup(np); + sink(1, vect); + if (setimes) { + setimes = 0; + if (utimes(vect[0], tv) < 0) + run_err("%s: set times: %s", + vect[0], strerror(errno)); + } + if (mod_flag) + (void) chmod(vect[0], mode); + if (vect[0]) + xfree(vect[0]); + continue; + } + omode = mode; + mode |= S_IWRITE; + if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { +bad: run_err("%s: %s", np, strerror(errno)); + continue; + } + (void) atomicio(vwrite, remout, "", 1); + if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { + (void) close(ofd); + continue; + } + cp = bp->buf; + wrerr = NO; + + statbytes = 0; + if (showprogress) + start_progress_meter(curfile, size, &statbytes); + for (count = i = 0; i < size; i += 4096) { + amt = 4096; + if (i + amt > size) + amt = size - i; + count += amt; + do { + j = atomicio(read, remin, cp, amt); + if (j <= 0) { + run_err("%s", j ? strerror(errno) : + "dropped connection"); + exit(1); + } + amt -= j; + cp += j; + statbytes += j; + } while (amt > 0); + + if (limit_rate) + bwlimit(4096); + + if (count == bp->cnt) { + /* Keep reading so we stay sync'd up. */ + if (wrerr == NO) { + j = atomicio(vwrite, ofd, bp->buf, count); + if (j != count) { + wrerr = YES; + wrerrno = j >= 0 ? EIO : errno; + } + } + count = 0; + cp = bp->buf; + } + } + if (showprogress) + stop_progress_meter(); + if (count != 0 && wrerr == NO && + (j = atomicio(vwrite, ofd, bp->buf, count)) != count) { + wrerr = YES; + wrerrno = j >= 0 ? EIO : errno; + } + if (wrerr == NO && ftruncate(ofd, size) != 0) { + run_err("%s: truncate: %s", np, strerror(errno)); + wrerr = DISPLAYED; + } + 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)); + wrerr = DISPLAYED; + } + } 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)); + wrerr = DISPLAYED; + } + } + if (close(ofd) == -1) { + wrerr = YES; + wrerrno = errno; + } + (void) response(); + if (setimes && wrerr == NO) { + setimes = 0; + if (utimes(np, tv) < 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) atomicio(vwrite, remout, "", 1); + break; + case DISPLAYED: + break; + } + } +screwup: + run_err("protocol error: %s", why); + exit(1); +} + +int +response(void) +{ + char ch, *cp, resp, rbuf[2048]; + + if (atomicio(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 (atomicio(read, remin, &ch, sizeof(ch)) != sizeof(ch)) + lostconn(0); + *cp++ = ch; + } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n'); + + if (!iamremote) + (void) atomicio(vwrite, STDERR_FILENO, rbuf, cp - rbuf); + ++errs; + if (resp == 1) + return (-1); + exit(1); + } + /* NOTREACHED */ +} + +void +usage(void) +{ + (void) fprintf(stderr, + "usage: scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n" + " [-l limit] [-o ssh_option] [-P port] [-S program]\n" + " [[user@]host1:]file1 [...] [[user@]host2:]file2\n"); + exit(1); +} + +void +run_err(const char *fmt,...) +{ + static FILE *fp; + va_list ap; + + ++errs; + if (fp == NULL && !(fp = fdopen(remout, "w"))) + return; + (void) fprintf(fp, "%c", 0x01); + (void) fprintf(fp, "scp: "); + va_start(ap, fmt); + (void) vfprintf(fp, fmt, ap); + va_end(ap); + (void) fprintf(fp, "\n"); + (void) fflush(fp); + + if (!iamremote) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + } +} + +void +verifydir(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(char *cp0) +{ + int c; + char *cp; + + cp = cp0; + do { + c = (int)*cp; + if (c & 0200) + goto bad; + if (!isalpha(c) && !isdigit(c)) { + switch (c) { + case '\'': + case '"': + case '`': + case ' ': + case '#': + goto bad; + default: + break; + } + } + } while (*++cp); + return (1); + +bad: fprintf(stderr, "%s: invalid user name\n", cp0); + return (0); +} + +BUF * +allocbuf(BUF *bp, int fd, int blksize) +{ + size_t size; +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + struct stat stb; + + if (fstat(fd, &stb) < 0) { + run_err("fstat: %s", strerror(errno)); + return (0); + } + size = roundup(stb.st_blksize, blksize); + if (size == 0) + size = blksize; +#else /* HAVE_STRUCT_STAT_ST_BLKSIZE */ + size = blksize; +#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ + if (bp->cnt >= size) + return (bp); + if (bp->buf == NULL) + bp->buf = xmalloc(size); + else + bp->buf = xrealloc(bp->buf, size); + memset(bp->buf, 0, size); + bp->cnt = size; + return (bp); +} + +void +lostconn(int signo) +{ + if (!iamremote) + write(STDERR_FILENO, "lost connection\n", 16); + if (signo) + _exit(1); + else + exit(1); +} diff --git a/crypto/openssh-3.9p1/servconf.c b/crypto/openssh-3.9p1/servconf.c new file mode 100644 index 0000000000..fae3c658e1 --- /dev/null +++ b/crypto/openssh-3.9p1/servconf.c @@ -0,0 +1,992 @@ +/* + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: servconf.c,v 1.137 2004/08/13 11:09:24 dtucker Exp $"); + +#include "ssh.h" +#include "log.h" +#include "servconf.h" +#include "xmalloc.h" +#include "compat.h" +#include "pathnames.h" +#include "misc.h" +#include "cipher.h" +#include "kex.h" +#include "mac.h" + +static void add_listen_addr(ServerOptions *, char *, u_short); +static void add_one_listen_addr(ServerOptions *, char *, u_short); + +/* AF_UNSPEC or AF_INET or AF_INET6 */ +extern int IPv4or6; +/* Use of privilege separation or not */ +extern int use_privsep; + +/* Initializes the server options to their default values. */ + +void +initialize_server_options(ServerOptions *options) +{ + memset(options, 0, sizeof(*options)); + + /* Portable-specific options */ + options->use_pam = -1; + + /* Standard Options */ + options->num_ports = 0; + options->ports_from_cmdline = 0; + options->listen_addrs = NULL; + options->num_host_key_files = 0; + options->pid_file = NULL; + options->server_key_bits = -1; + options->login_grace_time = -1; + options->key_regeneration_time = -1; + options->permit_root_login = PERMIT_NOT_SET; + options->ignore_rhosts = -1; + options->ignore_user_known_hosts = -1; + options->print_motd = -1; + options->print_lastlog = -1; + options->x11_forwarding = -1; + options->x11_display_offset = -1; + options->x11_use_localhost = -1; + options->xauth_location = NULL; + options->strict_modes = -1; + options->tcp_keep_alive = -1; + options->log_facility = SYSLOG_FACILITY_NOT_SET; + options->log_level = SYSLOG_LEVEL_NOT_SET; + options->rhosts_rsa_authentication = -1; + options->hostbased_authentication = -1; + options->hostbased_uses_name_from_packet_only = -1; + options->rsa_authentication = -1; + options->pubkey_authentication = -1; + options->kerberos_authentication = -1; + options->kerberos_or_local_passwd = -1; + options->kerberos_ticket_cleanup = -1; + options->kerberos_get_afs_token = -1; + options->gss_authentication=-1; + options->gss_cleanup_creds = -1; + options->password_authentication = -1; + options->kbd_interactive_authentication = -1; + options->challenge_response_authentication = -1; + options->permit_empty_passwd = -1; + options->permit_user_env = -1; + options->use_login = -1; + options->compression = -1; + options->allow_tcp_forwarding = -1; + options->num_allow_users = 0; + options->num_deny_users = 0; + options->num_allow_groups = 0; + options->num_deny_groups = 0; + options->ciphers = NULL; + options->macs = NULL; + options->protocol = SSH_PROTO_UNKNOWN; + options->gateway_ports = -1; + options->num_subsystems = 0; + options->max_startups_begin = -1; + options->max_startups_rate = -1; + options->max_startups = -1; + options->max_authtries = -1; + options->banner = NULL; + options->use_dns = -1; + options->client_alive_interval = -1; + options->client_alive_count_max = -1; + options->authorized_keys_file = NULL; + options->authorized_keys_file2 = NULL; + options->num_accept_env = 0; + + /* Needs to be accessable in many places */ + use_privsep = -1; +} + +void +fill_default_server_options(ServerOptions *options) +{ + /* Portable-specific options */ + if (options->use_pam == -1) + options->use_pam = 0; + + /* Standard Options */ + if (options->protocol == SSH_PROTO_UNKNOWN) + options->protocol = SSH_PROTO_1|SSH_PROTO_2; + if (options->num_host_key_files == 0) { + /* fill default hostkeys for protocols */ + if (options->protocol & SSH_PROTO_1) + options->host_key_files[options->num_host_key_files++] = + _PATH_HOST_KEY_FILE; + if (options->protocol & SSH_PROTO_2) { + options->host_key_files[options->num_host_key_files++] = + _PATH_HOST_RSA_KEY_FILE; + options->host_key_files[options->num_host_key_files++] = + _PATH_HOST_DSA_KEY_FILE; + } + } + if (options->num_ports == 0) + options->ports[options->num_ports++] = SSH_DEFAULT_PORT; + if (options->listen_addrs == NULL) + add_listen_addr(options, NULL, 0); + if (options->pid_file == NULL) + options->pid_file = _PATH_SSH_DAEMON_PID_FILE; + if (options->server_key_bits == -1) + options->server_key_bits = 768; + if (options->login_grace_time == -1) + options->login_grace_time = 120; + if (options->key_regeneration_time == -1) + options->key_regeneration_time = 3600; + if (options->permit_root_login == PERMIT_NOT_SET) + options->permit_root_login = PERMIT_YES; + if (options->ignore_rhosts == -1) + options->ignore_rhosts = 1; + if (options->ignore_user_known_hosts == -1) + options->ignore_user_known_hosts = 0; + if (options->print_motd == -1) + options->print_motd = 1; + if (options->print_lastlog == -1) + options->print_lastlog = 1; + if (options->x11_forwarding == -1) + options->x11_forwarding = 0; + if (options->x11_display_offset == -1) + options->x11_display_offset = 10; + if (options->x11_use_localhost == -1) + options->x11_use_localhost = 1; + if (options->xauth_location == NULL) + options->xauth_location = _PATH_XAUTH; + if (options->strict_modes == -1) + options->strict_modes = 1; + if (options->tcp_keep_alive == -1) + options->tcp_keep_alive = 1; + if (options->log_facility == SYSLOG_FACILITY_NOT_SET) + options->log_facility = SYSLOG_FACILITY_AUTH; + if (options->log_level == SYSLOG_LEVEL_NOT_SET) + options->log_level = SYSLOG_LEVEL_INFO; + if (options->rhosts_rsa_authentication == -1) + options->rhosts_rsa_authentication = 0; + if (options->hostbased_authentication == -1) + options->hostbased_authentication = 0; + if (options->hostbased_uses_name_from_packet_only == -1) + options->hostbased_uses_name_from_packet_only = 0; + if (options->rsa_authentication == -1) + options->rsa_authentication = 1; + if (options->pubkey_authentication == -1) + options->pubkey_authentication = 1; + if (options->kerberos_authentication == -1) + options->kerberos_authentication = 0; + if (options->kerberos_or_local_passwd == -1) + options->kerberos_or_local_passwd = 1; + if (options->kerberos_ticket_cleanup == -1) + options->kerberos_ticket_cleanup = 1; + if (options->kerberos_get_afs_token == -1) + options->kerberos_get_afs_token = 0; + if (options->gss_authentication == -1) + options->gss_authentication = 0; + if (options->gss_cleanup_creds == -1) + options->gss_cleanup_creds = 1; + if (options->password_authentication == -1) + options->password_authentication = 1; + if (options->kbd_interactive_authentication == -1) + options->kbd_interactive_authentication = 0; + if (options->challenge_response_authentication == -1) + options->challenge_response_authentication = 1; + if (options->permit_empty_passwd == -1) + options->permit_empty_passwd = 0; + if (options->permit_user_env == -1) + options->permit_user_env = 0; + if (options->use_login == -1) + options->use_login = 0; + if (options->compression == -1) + options->compression = 1; + if (options->allow_tcp_forwarding == -1) + options->allow_tcp_forwarding = 1; + if (options->gateway_ports == -1) + options->gateway_ports = 0; + if (options->max_startups == -1) + options->max_startups = 10; + if (options->max_startups_rate == -1) + options->max_startups_rate = 100; /* 100% */ + if (options->max_startups_begin == -1) + options->max_startups_begin = options->max_startups; + if (options->max_authtries == -1) + options->max_authtries = DEFAULT_AUTH_FAIL_MAX; + if (options->use_dns == -1) + options->use_dns = 1; + if (options->client_alive_interval == -1) + options->client_alive_interval = 0; + if (options->client_alive_count_max == -1) + options->client_alive_count_max = 3; + if (options->authorized_keys_file2 == NULL) { + /* authorized_keys_file2 falls back to authorized_keys_file */ + if (options->authorized_keys_file != NULL) + options->authorized_keys_file2 = options->authorized_keys_file; + else + options->authorized_keys_file2 = _PATH_SSH_USER_PERMITTED_KEYS2; + } + if (options->authorized_keys_file == NULL) + options->authorized_keys_file = _PATH_SSH_USER_PERMITTED_KEYS; + + /* Turn privilege separation on by default */ + if (use_privsep == -1) + use_privsep = 1; + +#ifndef HAVE_MMAP + if (use_privsep && options->compression == 1) { + error("This platform does not support both privilege " + "separation and compression"); + error("Compression disabled"); + options->compression = 0; + } +#endif + +} + +/* Keyword tokens. */ +typedef enum { + sBadOption, /* == unknown option */ + /* Portable-specific options */ + sUsePAM, + /* Standard Options */ + sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime, + sPermitRootLogin, sLogFacility, sLogLevel, + sRhostsRSAAuthentication, sRSAAuthentication, + sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, + sKerberosGetAFSToken, + sKerberosTgtPassing, sChallengeResponseAuthentication, + sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, + sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, + sStrictModes, sEmptyPasswd, sTCPKeepAlive, + sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression, + sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, + sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, + sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, + sMaxStartups, sMaxAuthTries, + sBanner, sUseDNS, sHostbasedAuthentication, + sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, + sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, + sGssAuthentication, sGssCleanupCreds, sAcceptEnv, + sUsePrivilegeSeparation, + sDeprecated, sUnsupported +} ServerOpCodes; + +/* Textual representation of the tokens. */ +static struct { + const char *name; + ServerOpCodes opcode; +} keywords[] = { + /* Portable-specific options */ +#ifdef USE_PAM + { "usepam", sUsePAM }, +#else + { "usepam", sUnsupported }, +#endif + { "pamauthenticationviakbdint", sDeprecated }, + /* Standard Options */ + { "port", sPort }, + { "hostkey", sHostKeyFile }, + { "hostdsakey", sHostKeyFile }, /* alias */ + { "pidfile", sPidFile }, + { "serverkeybits", sServerKeyBits }, + { "logingracetime", sLoginGraceTime }, + { "keyregenerationinterval", sKeyRegenerationTime }, + { "permitrootlogin", sPermitRootLogin }, + { "syslogfacility", sLogFacility }, + { "loglevel", sLogLevel }, + { "rhostsauthentication", sDeprecated }, + { "rhostsrsaauthentication", sRhostsRSAAuthentication }, + { "hostbasedauthentication", sHostbasedAuthentication }, + { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly }, + { "rsaauthentication", sRSAAuthentication }, + { "pubkeyauthentication", sPubkeyAuthentication }, + { "dsaauthentication", sPubkeyAuthentication }, /* alias */ +#ifdef KRB5 + { "kerberosauthentication", sKerberosAuthentication }, + { "kerberosorlocalpasswd", sKerberosOrLocalPasswd }, + { "kerberosticketcleanup", sKerberosTicketCleanup }, +#ifdef USE_AFS + { "kerberosgetafstoken", sKerberosGetAFSToken }, +#else + { "kerberosgetafstoken", sUnsupported }, +#endif +#else + { "kerberosauthentication", sUnsupported }, + { "kerberosorlocalpasswd", sUnsupported }, + { "kerberosticketcleanup", sUnsupported }, + { "kerberosgetafstoken", sUnsupported }, +#endif + { "kerberostgtpassing", sUnsupported }, + { "afstokenpassing", sUnsupported }, +#ifdef GSSAPI + { "gssapiauthentication", sGssAuthentication }, + { "gssapicleanupcredentials", sGssCleanupCreds }, +#else + { "gssapiauthentication", sUnsupported }, + { "gssapicleanupcredentials", sUnsupported }, +#endif + { "passwordauthentication", sPasswordAuthentication }, + { "kbdinteractiveauthentication", sKbdInteractiveAuthentication }, + { "challengeresponseauthentication", sChallengeResponseAuthentication }, + { "skeyauthentication", sChallengeResponseAuthentication }, /* alias */ + { "checkmail", sDeprecated }, + { "listenaddress", sListenAddress }, + { "printmotd", sPrintMotd }, + { "printlastlog", sPrintLastLog }, + { "ignorerhosts", sIgnoreRhosts }, + { "ignoreuserknownhosts", sIgnoreUserKnownHosts }, + { "x11forwarding", sX11Forwarding }, + { "x11displayoffset", sX11DisplayOffset }, + { "x11uselocalhost", sX11UseLocalhost }, + { "xauthlocation", sXAuthLocation }, + { "strictmodes", sStrictModes }, + { "permitemptypasswords", sEmptyPasswd }, + { "permituserenvironment", sPermitUserEnvironment }, + { "uselogin", sUseLogin }, + { "compression", sCompression }, + { "tcpkeepalive", sTCPKeepAlive }, + { "keepalive", sTCPKeepAlive }, /* obsolete alias */ + { "allowtcpforwarding", sAllowTcpForwarding }, + { "allowusers", sAllowUsers }, + { "denyusers", sDenyUsers }, + { "allowgroups", sAllowGroups }, + { "denygroups", sDenyGroups }, + { "ciphers", sCiphers }, + { "macs", sMacs }, + { "protocol", sProtocol }, + { "gatewayports", sGatewayPorts }, + { "subsystem", sSubsystem }, + { "maxstartups", sMaxStartups }, + { "maxauthtries", sMaxAuthTries }, + { "banner", sBanner }, + { "usedns", sUseDNS }, + { "verifyreversemapping", sDeprecated }, + { "reversemappingcheck", sDeprecated }, + { "clientaliveinterval", sClientAliveInterval }, + { "clientalivecountmax", sClientAliveCountMax }, + { "authorizedkeysfile", sAuthorizedKeysFile }, + { "authorizedkeysfile2", sAuthorizedKeysFile2 }, + { "useprivilegeseparation", sUsePrivilegeSeparation}, + { "acceptenv", sAcceptEnv }, + { NULL, sBadOption } +}; + +/* + * Returns the number of the token pointed to by cp or sBadOption. + */ + +static ServerOpCodes +parse_token(const char *cp, const char *filename, + int linenum) +{ + u_int i; + + for (i = 0; keywords[i].name; i++) + if (strcasecmp(cp, keywords[i].name) == 0) + return keywords[i].opcode; + + error("%s: line %d: Bad configuration option: %s", + filename, linenum, cp); + return sBadOption; +} + +static void +add_listen_addr(ServerOptions *options, char *addr, u_short port) +{ + int i; + + if (options->num_ports == 0) + options->ports[options->num_ports++] = SSH_DEFAULT_PORT; + if (port == 0) + for (i = 0; i < options->num_ports; i++) + add_one_listen_addr(options, addr, options->ports[i]); + else + add_one_listen_addr(options, addr, port); +} + +static void +add_one_listen_addr(ServerOptions *options, char *addr, u_short port) +{ + struct addrinfo hints, *ai, *aitop; + char strport[NI_MAXSERV]; + int gaierr; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = IPv4or6; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = (addr == NULL) ? AI_PASSIVE : 0; + snprintf(strport, sizeof strport, "%u", port); + if ((gaierr = getaddrinfo(addr, strport, &hints, &aitop)) != 0) + fatal("bad addr or host: %s (%s)", + addr ? addr : "", + gai_strerror(gaierr)); + for (ai = aitop; ai->ai_next; ai = ai->ai_next) + ; + ai->ai_next = options->listen_addrs; + options->listen_addrs = aitop; +} + +int +process_server_config_line(ServerOptions *options, char *line, + const char *filename, int linenum) +{ + char *cp, **charptr, *arg, *p; + int *intptr, value, i, n; + ServerOpCodes opcode; + + cp = line; + arg = strdelim(&cp); + /* Ignore leading whitespace */ + if (*arg == '\0') + arg = strdelim(&cp); + if (!arg || !*arg || *arg == '#') + return 0; + intptr = NULL; + charptr = NULL; + opcode = parse_token(arg, filename, linenum); + switch (opcode) { + /* Portable-specific options */ + case sUsePAM: + intptr = &options->use_pam; + goto parse_flag; + + /* Standard Options */ + case sBadOption: + return -1; + case sPort: + /* ignore ports from configfile if cmdline specifies ports */ + if (options->ports_from_cmdline) + return 0; + if (options->listen_addrs != NULL) + fatal("%s line %d: ports must be specified before " + "ListenAddress.", filename, linenum); + if (options->num_ports >= MAX_PORTS) + fatal("%s line %d: too many ports.", + filename, linenum); + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: missing port number.", + filename, linenum); + options->ports[options->num_ports++] = a2port(arg); + if (options->ports[options->num_ports-1] == 0) + fatal("%s line %d: Badly formatted port number.", + filename, linenum); + break; + + case sServerKeyBits: + intptr = &options->server_key_bits; +parse_int: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: missing integer value.", + filename, linenum); + value = atoi(arg); + if (*intptr == -1) + *intptr = value; + break; + + case sLoginGraceTime: + intptr = &options->login_grace_time; +parse_time: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: missing time value.", + filename, linenum); + if ((value = convtime(arg)) == -1) + fatal("%s line %d: invalid time value.", + filename, linenum); + if (*intptr == -1) + *intptr = value; + break; + + case sKeyRegenerationTime: + intptr = &options->key_regeneration_time; + goto parse_time; + + case sListenAddress: + arg = strdelim(&cp); + if (!arg || *arg == '\0' || strncmp(arg, "[]", 2) == 0) + fatal("%s line %d: missing inet addr.", + filename, linenum); + if (*arg == '[') { + if ((p = strchr(arg, ']')) == NULL) + fatal("%s line %d: bad ipv6 inet addr usage.", + filename, linenum); + arg++; + memmove(p, p+1, strlen(p+1)+1); + } else if (((p = strchr(arg, ':')) == NULL) || + (strchr(p+1, ':') != NULL)) { + add_listen_addr(options, arg, 0); + break; + } + if (*p == ':') { + u_short port; + + p++; + if (*p == '\0') + fatal("%s line %d: bad inet addr:port usage.", + filename, linenum); + else { + *(p-1) = '\0'; + if ((port = a2port(p)) == 0) + fatal("%s line %d: bad port number.", + filename, linenum); + add_listen_addr(options, arg, port); + } + } else if (*p == '\0') + add_listen_addr(options, arg, 0); + else + fatal("%s line %d: bad inet addr usage.", + filename, linenum); + break; + + case sHostKeyFile: + intptr = &options->num_host_key_files; + if (*intptr >= MAX_HOSTKEYS) + fatal("%s line %d: too many host keys specified (max %d).", + filename, linenum, MAX_HOSTKEYS); + charptr = &options->host_key_files[*intptr]; +parse_filename: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: missing file name.", + filename, linenum); + if (*charptr == NULL) { + *charptr = tilde_expand_filename(arg, getuid()); + /* increase optional counter */ + if (intptr != NULL) + *intptr = *intptr + 1; + } + break; + + case sPidFile: + charptr = &options->pid_file; + goto parse_filename; + + case sPermitRootLogin: + intptr = &options->permit_root_login; + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: missing yes/" + "without-password/forced-commands-only/no " + "argument.", filename, linenum); + value = 0; /* silence compiler */ + if (strcmp(arg, "without-password") == 0) + value = PERMIT_NO_PASSWD; + else if (strcmp(arg, "forced-commands-only") == 0) + value = PERMIT_FORCED_ONLY; + else if (strcmp(arg, "yes") == 0) + value = PERMIT_YES; + else if (strcmp(arg, "no") == 0) + value = PERMIT_NO; + else + fatal("%s line %d: Bad yes/" + "without-password/forced-commands-only/no " + "argument: %s", filename, linenum, arg); + if (*intptr == -1) + *intptr = value; + break; + + case sIgnoreRhosts: + intptr = &options->ignore_rhosts; +parse_flag: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: missing yes/no argument.", + filename, linenum); + value = 0; /* silence compiler */ + if (strcmp(arg, "yes") == 0) + value = 1; + else if (strcmp(arg, "no") == 0) + value = 0; + else + fatal("%s line %d: Bad yes/no argument: %s", + filename, linenum, arg); + if (*intptr == -1) + *intptr = value; + break; + + case sIgnoreUserKnownHosts: + intptr = &options->ignore_user_known_hosts; + goto parse_flag; + + case sRhostsRSAAuthentication: + intptr = &options->rhosts_rsa_authentication; + goto parse_flag; + + case sHostbasedAuthentication: + intptr = &options->hostbased_authentication; + goto parse_flag; + + case sHostbasedUsesNameFromPacketOnly: + intptr = &options->hostbased_uses_name_from_packet_only; + goto parse_flag; + + case sRSAAuthentication: + intptr = &options->rsa_authentication; + goto parse_flag; + + case sPubkeyAuthentication: + intptr = &options->pubkey_authentication; + goto parse_flag; + + case sKerberosAuthentication: + intptr = &options->kerberos_authentication; + goto parse_flag; + + case sKerberosOrLocalPasswd: + intptr = &options->kerberos_or_local_passwd; + goto parse_flag; + + case sKerberosTicketCleanup: + intptr = &options->kerberos_ticket_cleanup; + goto parse_flag; + + case sKerberosGetAFSToken: + intptr = &options->kerberos_get_afs_token; + goto parse_flag; + + case sGssAuthentication: + intptr = &options->gss_authentication; + goto parse_flag; + + case sGssCleanupCreds: + intptr = &options->gss_cleanup_creds; + goto parse_flag; + + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; + + case sKbdInteractiveAuthentication: + intptr = &options->kbd_interactive_authentication; + goto parse_flag; + + case sChallengeResponseAuthentication: + intptr = &options->challenge_response_authentication; + goto parse_flag; + + case sPrintMotd: + intptr = &options->print_motd; + goto parse_flag; + + case sPrintLastLog: + intptr = &options->print_lastlog; + goto parse_flag; + + case sX11Forwarding: + intptr = &options->x11_forwarding; + goto parse_flag; + + case sX11DisplayOffset: + intptr = &options->x11_display_offset; + goto parse_int; + + case sX11UseLocalhost: + intptr = &options->x11_use_localhost; + goto parse_flag; + + case sXAuthLocation: + charptr = &options->xauth_location; + goto parse_filename; + + case sStrictModes: + intptr = &options->strict_modes; + goto parse_flag; + + case sTCPKeepAlive: + intptr = &options->tcp_keep_alive; + goto parse_flag; + + case sEmptyPasswd: + intptr = &options->permit_empty_passwd; + goto parse_flag; + + case sPermitUserEnvironment: + intptr = &options->permit_user_env; + goto parse_flag; + + case sUseLogin: + intptr = &options->use_login; + goto parse_flag; + + case sCompression: + intptr = &options->compression; + goto parse_flag; + + case sGatewayPorts: + intptr = &options->gateway_ports; + goto parse_flag; + + case sUseDNS: + intptr = &options->use_dns; + goto parse_flag; + + case sLogFacility: + intptr = (int *) &options->log_facility; + arg = strdelim(&cp); + value = log_facility_number(arg); + if (value == SYSLOG_FACILITY_NOT_SET) + fatal("%.200s line %d: unsupported log facility '%s'", + filename, linenum, arg ? arg : ""); + if (*intptr == -1) + *intptr = (SyslogFacility) value; + break; + + case sLogLevel: + intptr = (int *) &options->log_level; + arg = strdelim(&cp); + value = log_level_number(arg); + if (value == SYSLOG_LEVEL_NOT_SET) + fatal("%.200s line %d: unsupported log level '%s'", + filename, linenum, arg ? arg : ""); + if (*intptr == -1) + *intptr = (LogLevel) value; + break; + + case sAllowTcpForwarding: + intptr = &options->allow_tcp_forwarding; + goto parse_flag; + + case sUsePrivilegeSeparation: + intptr = &use_privsep; + goto parse_flag; + + case sAllowUsers: + while ((arg = strdelim(&cp)) && *arg != '\0') { + if (options->num_allow_users >= MAX_ALLOW_USERS) + fatal("%s line %d: too many allow users.", + filename, linenum); + options->allow_users[options->num_allow_users++] = + xstrdup(arg); + } + break; + + case sDenyUsers: + while ((arg = strdelim(&cp)) && *arg != '\0') { + if (options->num_deny_users >= MAX_DENY_USERS) + fatal( "%s line %d: too many deny users.", + filename, linenum); + options->deny_users[options->num_deny_users++] = + xstrdup(arg); + } + break; + + case sAllowGroups: + while ((arg = strdelim(&cp)) && *arg != '\0') { + if (options->num_allow_groups >= MAX_ALLOW_GROUPS) + fatal("%s line %d: too many allow groups.", + filename, linenum); + options->allow_groups[options->num_allow_groups++] = + xstrdup(arg); + } + break; + + case sDenyGroups: + while ((arg = strdelim(&cp)) && *arg != '\0') { + if (options->num_deny_groups >= MAX_DENY_GROUPS) + fatal("%s line %d: too many deny groups.", + filename, linenum); + options->deny_groups[options->num_deny_groups++] = xstrdup(arg); + } + break; + + case sCiphers: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", filename, linenum); + if (!ciphers_valid(arg)) + fatal("%s line %d: Bad SSH2 cipher spec '%s'.", + filename, linenum, arg ? arg : ""); + if (options->ciphers == NULL) + options->ciphers = xstrdup(arg); + break; + + case sMacs: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", filename, linenum); + if (!mac_valid(arg)) + fatal("%s line %d: Bad SSH2 mac spec '%s'.", + filename, linenum, arg ? arg : ""); + if (options->macs == NULL) + options->macs = xstrdup(arg); + break; + + case sProtocol: + intptr = &options->protocol; + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", filename, linenum); + value = proto_spec(arg); + if (value == SSH_PROTO_UNKNOWN) + fatal("%s line %d: Bad protocol spec '%s'.", + filename, linenum, arg ? arg : ""); + if (*intptr == SSH_PROTO_UNKNOWN) + *intptr = value; + break; + + case sSubsystem: + if (options->num_subsystems >= MAX_SUBSYSTEMS) { + fatal("%s line %d: too many subsystems defined.", + filename, linenum); + } + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing subsystem name.", + filename, linenum); + for (i = 0; i < options->num_subsystems; i++) + if (strcmp(arg, options->subsystem_name[i]) == 0) + fatal("%s line %d: Subsystem '%s' already defined.", + filename, linenum, arg); + options->subsystem_name[options->num_subsystems] = xstrdup(arg); + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing subsystem command.", + filename, linenum); + options->subsystem_command[options->num_subsystems] = xstrdup(arg); + options->num_subsystems++; + break; + + case sMaxStartups: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing MaxStartups spec.", + filename, linenum); + if ((n = sscanf(arg, "%d:%d:%d", + &options->max_startups_begin, + &options->max_startups_rate, + &options->max_startups)) == 3) { + if (options->max_startups_begin > + options->max_startups || + options->max_startups_rate > 100 || + options->max_startups_rate < 1) + fatal("%s line %d: Illegal MaxStartups spec.", + filename, linenum); + } else if (n != 1) + fatal("%s line %d: Illegal MaxStartups spec.", + filename, linenum); + else + options->max_startups = options->max_startups_begin; + break; + + case sMaxAuthTries: + intptr = &options->max_authtries; + goto parse_int; + + case sBanner: + charptr = &options->banner; + goto parse_filename; + /* + * These options can contain %X options expanded at + * connect time, so that you can specify paths like: + * + * AuthorizedKeysFile /etc/ssh_keys/%u + */ + case sAuthorizedKeysFile: + case sAuthorizedKeysFile2: + charptr = (opcode == sAuthorizedKeysFile ) ? + &options->authorized_keys_file : + &options->authorized_keys_file2; + goto parse_filename; + + case sClientAliveInterval: + intptr = &options->client_alive_interval; + goto parse_time; + + case sClientAliveCountMax: + intptr = &options->client_alive_count_max; + goto parse_int; + + case sAcceptEnv: + while ((arg = strdelim(&cp)) && *arg != '\0') { + if (strchr(arg, '=') != NULL) + fatal("%s line %d: Invalid environment name.", + filename, linenum); + if (options->num_accept_env >= MAX_ACCEPT_ENV) + fatal("%s line %d: too many allow env.", + filename, linenum); + options->accept_env[options->num_accept_env++] = + xstrdup(arg); + } + break; + + case sDeprecated: + logit("%s line %d: Deprecated option %s", + filename, linenum, arg); + while (arg) + arg = strdelim(&cp); + break; + + case sUnsupported: + logit("%s line %d: Unsupported option %s", + filename, linenum, arg); + while (arg) + arg = strdelim(&cp); + break; + + default: + fatal("%s line %d: Missing handler for opcode %s (%d)", + filename, linenum, arg, opcode); + } + if ((arg = strdelim(&cp)) != NULL && *arg != '\0') + fatal("%s line %d: garbage at end of line; \"%.200s\".", + filename, linenum, arg); + return 0; +} + +/* Reads the server configuration file. */ + +void +load_server_config(const char *filename, Buffer *conf) +{ + char line[1024], *cp; + FILE *f; + + debug2("%s: filename %s", __func__, filename); + if ((f = fopen(filename, "r")) == NULL) { + perror(filename); + exit(1); + } + buffer_clear(conf); + while (fgets(line, sizeof(line), f)) { + /* + * Trim out comments and strip whitespace + * NB - preserve newlines, they are needed to reproduce + * line numbers later for error messages + */ + if ((cp = strchr(line, '#')) != NULL) + memcpy(cp, "\n", 2); + cp = line + strspn(line, " \t\r"); + + buffer_append(conf, cp, strlen(cp)); + } + buffer_append(conf, "\0", 1); + fclose(f); + debug2("%s: done config len = %d", __func__, buffer_len(conf)); +} + +void +parse_server_config(ServerOptions *options, const char *filename, Buffer *conf) +{ + int linenum, bad_options = 0; + char *cp, *obuf, *cbuf; + + debug2("%s: config %s len %d", __func__, filename, buffer_len(conf)); + + obuf = cbuf = xstrdup(buffer_ptr(conf)); + linenum = 1; + while((cp = strsep(&cbuf, "\n")) != NULL) { + if (process_server_config_line(options, cp, filename, + linenum++) != 0) + bad_options++; + } + xfree(obuf); + if (bad_options > 0) + fatal("%s: terminating, %d bad configuration options", + filename, bad_options); +} diff --git a/crypto/openssh-3.9p1/servconf.h b/crypto/openssh-3.9p1/servconf.h new file mode 100644 index 0000000000..ebd0568147 --- /dev/null +++ b/crypto/openssh-3.9p1/servconf.h @@ -0,0 +1,144 @@ +/* $OpenBSD: servconf.h,v 1.70 2004/06/24 19:30:54 djm Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Definitions for server configuration data and for the functions reading it. + * + * 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". + */ + +#ifndef SERVCONF_H +#define SERVCONF_H + +#include "buffer.h" + +#define MAX_PORTS 256 /* Max # ports. */ + +#define MAX_ALLOW_USERS 256 /* Max # users on allow list. */ +#define MAX_DENY_USERS 256 /* Max # users on deny list. */ +#define MAX_ALLOW_GROUPS 256 /* Max # groups on allow list. */ +#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ +#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ +#define MAX_HOSTKEYS 256 /* Max # hostkeys. */ +#define MAX_ACCEPT_ENV 256 /* Max # of env vars. */ + +/* permit_root_login */ +#define PERMIT_NOT_SET -1 +#define PERMIT_NO 0 +#define PERMIT_FORCED_ONLY 1 +#define PERMIT_NO_PASSWD 2 +#define PERMIT_YES 3 + +#define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ + +typedef struct { + u_int num_ports; + u_int ports_from_cmdline; + u_short ports[MAX_PORTS]; /* Port number to listen on. */ + char *listen_addr; /* Address on which the server listens. */ + struct addrinfo *listen_addrs; /* Addresses on which the server listens. */ + char *host_key_files[MAX_HOSTKEYS]; /* Files containing host keys. */ + int num_host_key_files; /* Number of files for host keys. */ + char *pid_file; /* Where to put our pid */ + 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; /* PERMIT_*, see above */ + int ignore_rhosts; /* Ignore .rhosts and .shosts. */ + int ignore_user_known_hosts; /* Ignore ~/.ssh/known_hosts + * for RhostsRsaAuth */ + int print_motd; /* If true, print /etc/motd. */ + int print_lastlog; /* If true, print lastlog */ + int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */ + int x11_display_offset; /* What DISPLAY number to start + * searching at */ + int x11_use_localhost; /* If true, use localhost for fake X11 server. */ + char *xauth_location; /* Location of xauth program */ + int strict_modes; /* If true, require string home dir modes. */ + int tcp_keep_alive; /* If true, set SO_KEEPALIVE. */ + char *ciphers; /* Supported SSH2 ciphers. */ + char *macs; /* Supported SSH2 macs. */ + int protocol; /* Supported protocol versions. */ + int gateway_ports; /* If true, allow remote connects to forwarded ports. */ + SyslogFacility log_facility; /* Facility for system logging. */ + LogLevel log_level; /* Level for system logging. */ + int rhosts_rsa_authentication; /* If true, permit rhosts RSA + * authentication. */ + int hostbased_authentication; /* If true, permit ssh2 hostbased auth */ + int hostbased_uses_name_from_packet_only; /* experimental */ + int rsa_authentication; /* If true, permit RSA authentication. */ + int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */ + int kerberos_authentication; /* If true, permit Kerberos + * authentication. */ + int kerberos_or_local_passwd; /* If true, permit kerberos + * and any other password + * authentication mechanism, + * such as SecurID or + * /etc/passwd */ + int kerberos_ticket_cleanup; /* If true, destroy ticket + * file on logout. */ + int kerberos_get_afs_token; /* If true, try to get AFS token if + * authenticated with Kerberos. */ + int gss_authentication; /* If true, permit GSSAPI authentication */ + int gss_cleanup_creds; /* If true, destroy cred cache on logout */ + int password_authentication; /* If true, permit password + * authentication. */ + int kbd_interactive_authentication; /* If true, permit */ + int challenge_response_authentication; + int permit_empty_passwd; /* If false, do not permit empty + * passwords. */ + int permit_user_env; /* If true, read ~/.ssh/environment */ + int use_login; /* If true, login(1) is used */ + int compression; /* If true, compression is allowed */ + int allow_tcp_forwarding; + u_int num_allow_users; + char *allow_users[MAX_ALLOW_USERS]; + u_int num_deny_users; + char *deny_users[MAX_DENY_USERS]; + u_int num_allow_groups; + char *allow_groups[MAX_ALLOW_GROUPS]; + u_int num_deny_groups; + char *deny_groups[MAX_DENY_GROUPS]; + + u_int num_subsystems; + char *subsystem_name[MAX_SUBSYSTEMS]; + char *subsystem_command[MAX_SUBSYSTEMS]; + + u_int num_accept_env; + char *accept_env[MAX_ACCEPT_ENV]; + + int max_startups_begin; + int max_startups_rate; + int max_startups; + int max_authtries; + char *banner; /* SSH-2 banner message */ + int use_dns; + int client_alive_interval; /* + * poke the client this often to + * see if it's still there + */ + int client_alive_count_max; /* + * If the client is unresponsive + * for this many intervals above, + * disconnect the session + */ + + char *authorized_keys_file; /* File containing public keys */ + char *authorized_keys_file2; + int use_pam; /* Enable auth via PAM */ +} ServerOptions; + +void initialize_server_options(ServerOptions *); +void fill_default_server_options(ServerOptions *); +int process_server_config_line(ServerOptions *, char *, const char *, int); +void load_server_config(const char *, Buffer *); +void parse_server_config(ServerOptions *, const char *, Buffer *); + +#endif /* SERVCONF_H */ diff --git a/crypto/openssh-3.9p1/serverloop.c b/crypto/openssh-3.9p1/serverloop.c new file mode 100644 index 0000000000..eee1e79598 --- /dev/null +++ b/crypto/openssh-3.9p1/serverloop.c @@ -0,0 +1,1097 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Server main loop for handling the interactive session. + * + * 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". + * + * SSH2 support by Markus Friedl. + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: serverloop.c,v 1.117 2004/08/11 21:43:05 avsm Exp $"); + +#include "xmalloc.h" +#include "packet.h" +#include "buffer.h" +#include "log.h" +#include "servconf.h" +#include "canohost.h" +#include "sshpty.h" +#include "channels.h" +#include "compat.h" +#include "ssh1.h" +#include "ssh2.h" +#include "auth.h" +#include "session.h" +#include "dispatch.h" +#include "auth-options.h" +#include "serverloop.h" +#include "misc.h" +#include "kex.h" + +extern ServerOptions options; + +/* XXX */ +extern Kex *xxx_kex; +extern Authctxt *the_authctxt; + +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 fdin_is_tty = 0; /* fdin points to a tty. */ +static int connection_in; /* Connection to client (input). */ +static int connection_out; /* Connection to client (output). */ +static int connection_closed = 0; /* Connection to client closed. */ +static u_int buffer_high; /* "Soft" max buffer size. */ +static int client_alive_timeouts = 0; + +/* + * 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 volatile sig_atomic_t child_terminated = 0; /* The child has terminated. */ + +/* prototypes */ +static void server_init_dispatch(void); + +/* + * we write to this pipe if a SIGCHLD is caught in order to avoid + * the race between select() and child_terminated + */ +static int notify_pipe[2]; +static void +notify_setup(void) +{ + if (pipe(notify_pipe) < 0) { + error("pipe(notify_pipe) failed %s", strerror(errno)); + } else if ((fcntl(notify_pipe[0], F_SETFD, 1) == -1) || + (fcntl(notify_pipe[1], F_SETFD, 1) == -1)) { + error("fcntl(notify_pipe, F_SETFD) failed %s", strerror(errno)); + close(notify_pipe[0]); + close(notify_pipe[1]); + } else { + set_nonblock(notify_pipe[0]); + set_nonblock(notify_pipe[1]); + return; + } + notify_pipe[0] = -1; /* read end */ + notify_pipe[1] = -1; /* write end */ +} +static void +notify_parent(void) +{ + if (notify_pipe[1] != -1) + write(notify_pipe[1], "", 1); +} +static void +notify_prepare(fd_set *readset) +{ + if (notify_pipe[0] != -1) + FD_SET(notify_pipe[0], readset); +} +static void +notify_done(fd_set *readset) +{ + char c; + + if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) + while (read(notify_pipe[0], &c, 1) != -1) + debug2("notify_done: reading"); +} + +static void +sigchld_handler(int sig) +{ + int save_errno = errno; + debug("Received SIGCHLD."); + child_terminated = 1; +#ifndef _UNICOS + mysignal(SIGCHLD, sigchld_handler); +#endif + notify_parent(); + errno = save_errno; +} + +/* + * Make packets from buffered stderr data, and buffer it for sending + * to the client. + */ +static void +make_packets_from_stderr_data(void) +{ + u_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 { + /* Keep the packets at reasonable size. */ + if (len > packet_get_maxsize()) + len = packet_get_maxsize(); + } + 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. + */ +static void +make_packets_from_stdout_data(void) +{ + u_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 { + /* Keep the packets at reasonable size. */ + if (len > packet_get_maxsize()) + len = packet_get_maxsize(); + } + packet_start(SSH_SMSG_STDOUT_DATA); + packet_put_string(buffer_ptr(&stdout_buffer), len); + packet_send(); + buffer_consume(&stdout_buffer, len); + stdout_bytes += len; + } +} + +static void +client_alive_check(void) +{ + int channel_id; + + /* timeout, check to see how many we have had */ + if (++client_alive_timeouts > options.client_alive_count_max) + packet_disconnect("Timeout, your session not responding."); + + /* + * send a bogus global/channel request with "wantreply", + * we should get back a failure + */ + if ((channel_id = channel_find_open()) == -1) { + packet_start(SSH2_MSG_GLOBAL_REQUEST); + packet_put_cstring("keepalive@openssh.com"); + packet_put_char(1); /* boolean: want reply */ + } else { + channel_request_start(channel_id, "keepalive@openssh.com", 1); + } + packet_send(); +} + +/* + * 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). + */ +static void +wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, + u_int *nallocp, u_int max_time_milliseconds) +{ + struct timeval tv, *tvp; + int ret; + int client_alive_scheduled = 0; + + /* + * if using client_alive, set the max timeout accordingly, + * and indicate that this particular timeout was for client + * alive by setting the client_alive_scheduled flag. + * + * this could be randomized somewhat to make traffic + * analysis more difficult, but we're not doing it yet. + */ + if (compat20 && + max_time_milliseconds == 0 && options.client_alive_interval) { + client_alive_scheduled = 1; + max_time_milliseconds = options.client_alive_interval * 1000; + } + + /* Allocate and update select() masks for channel descriptors. */ + channel_prepare_select(readsetp, writesetp, maxfdp, nallocp, 0); + + if (compat20) { +#if 0 + /* wrong: bad condition XXX */ + if (channel_not_very_much_buffered_data()) +#endif + FD_SET(connection_in, *readsetp); + } else { + /* + * Read packets from the client unless we have too much + * buffered stdin or channel data. + */ + if (buffer_len(&stdin_buffer) < buffer_high && + channel_not_very_much_buffered_data()) + FD_SET(connection_in, *readsetp); + /* + * 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, *readsetp); + if (!fderr_eof) + FD_SET(fderr, *readsetp); + } + /* + * 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, *writesetp); + } + notify_prepare(*readsetp); + + /* + * If we have buffered packet data going to the client, mark that + * descriptor. + */ + if (packet_have_data_to_write()) + FD_SET(connection_out, *writesetp); + + /* + * If child has terminated and there is enough buffer space to read + * from it, then read as much as is available and exit. + */ + if (child_terminated && packet_not_very_much_data_to_write()) + if (max_time_milliseconds == 0 || client_alive_scheduled) + 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((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); + + if (ret == -1) { + memset(*readsetp, 0, *nallocp); + memset(*writesetp, 0, *nallocp); + if (errno != EINTR) + error("select: %.100s", strerror(errno)); + } else if (ret == 0 && client_alive_scheduled) + client_alive_check(); + + notify_done(*readsetp); +} + +/* + * Processes input from the client and the program. Input data is stored + * in buffers and processed later. + */ +static 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) { + verbose("Connection closed by %.100s", + get_remote_ipaddr()); + connection_closed = 1; + if (compat20) + return; + cleanup_exit(255); + } else if (len < 0) { + if (errno != EINTR && errno != EAGAIN) { + verbose("Read error from remote host " + "%.100s: %.100s", + get_remote_ipaddr(), strerror(errno)); + cleanup_exit(255); + } + } else { + /* Buffer any received data. */ + packet_process_incoming(buf, len); + } + } + if (compat20) + return; + + /* 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 && (errno == EINTR || errno == EAGAIN)) { + /* do nothing */ + } else 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 && (errno == EINTR || errno == EAGAIN)) { + /* do nothing */ + } else if (len <= 0) { + fderr_eof = 1; + } else { + buffer_append(&stderr_buffer, buf, len); + } + } +} + +/* + * Sends data from internal buffers to client program stdin. + */ +static void +process_output(fd_set * writeset) +{ + struct termios tio; + u_char *data; + u_int dlen; + int len; + + /* Write buffered data to program stdin. */ + if (!compat20 && fdin != -1 && FD_ISSET(fdin, writeset)) { + data = buffer_ptr(&stdin_buffer); + dlen = buffer_len(&stdin_buffer); + len = write(fdin, data, dlen); + if (len < 0 && (errno == EINTR || errno == EAGAIN)) { + /* do nothing */ + } else if (len <= 0) { + if (fdin != fdout) + close(fdin); + else + shutdown(fdin, SHUT_WR); /* We will no longer send. */ + fdin = -1; + } else { + /* Successful write. */ + if (fdin_is_tty && dlen >= 1 && data[0] != '\r' && + tcgetattr(fdin, &tio) == 0 && + !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) { + /* + * Simulate echo to reduce the impact of + * traffic analysis + */ + packet_send_ignore(len); + packet_send(); + } + /* 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. + */ +static void +drain_output(void) +{ + /* 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(); +} + +static void +process_buffered_input_packets(void) +{ + dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? xxx_kex : NULL); +} + +/* + * 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(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) +{ + fd_set *readset = NULL, *writeset = NULL; + int max_fd = 0; + u_int nalloc = 0; + int wait_status; /* Status returned by wait(). */ + pid_t wait_pid; /* pid returned by wait(). */ + int waiting_termination = 0; /* Have displayed waiting close message. */ + u_int max_time_milliseconds; + u_int previous_stdout_buffer_bytes; + u_int stdout_buffer_bytes; + int type; + + debug("Entering interactive session."); + + /* Initialize the SIGCHLD kludge. */ + child_terminated = 0; + mysignal(SIGCHLD, sigchld_handler); + + /* Initialize our global variables. */ + fdin = fdin_arg; + fdout = fdout_arg; + fderr = fderr_arg; + + /* nonblocking IO */ + set_nonblock(fdin); + set_nonblock(fdout); + /* we don't have stderr for interactive terminal sessions, see below */ + if (fderr != -1) + set_nonblock(fderr); + + if (!(datafellows & SSH_BUG_IGNOREMSG) && isatty(fdin)) + fdin_is_tty = 1; + + connection_in = packet_get_connection_in(); + connection_out = packet_get_connection_out(); + + notify_setup(); + + previous_stdout_buffer_bytes = 0; + + /* Set approximate I/O buffer size. */ + if (packet_is_interactive()) + buffer_high = 4096; + else + buffer_high = 64 * 1024; + +#if 0 + /* Initialize max_fd to the maximum of the known file descriptors. */ + max_fd = MAX(connection_in, connection_out); + max_fd = MAX(max_fd, fdin); + max_fd = MAX(max_fd, fdout); + if (fderr != -1) + max_fd = MAX(max_fd, fderr); +#endif + + /* 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; + + server_init_dispatch(); + + /* Main loop of the server for the interactive session mode. */ + for (;;) { + + /* 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) { + if (fdin != fdout) + close(fdin); + else + shutdown(fdin, SHUT_WR); /* 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) { + /* try again after a while */ + max_time_milliseconds = 10; + } else { + /* Send it now. */ + make_packets_from_stdout_data(); + } + 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()) + break; + 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); + } + } + max_fd = MAX(connection_in, connection_out); + max_fd = MAX(max_fd, fdin); + max_fd = MAX(max_fd, fdout); + max_fd = MAX(max_fd, fderr); + max_fd = MAX(max_fd, notify_pipe[0]); + + /* Sleep in select() until we can do something. */ + wait_until_can_do_something(&readset, &writeset, &max_fd, + &nalloc, 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); + } + if (readset) + xfree(readset); + if (writeset) + xfree(writeset); + + /* 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) + close(fdout); + fdout = -1; + fdout_eof = 1; + if (fderr != -1) + close(fderr); + fderr = -1; + fderr_eof = 1; + if (fdin != -1) + close(fdin); + fdin = -1; + + channel_free_all(); + + /* We no longer want our SIGCHLD handler to be called. */ + mysignal(SIGCHLD, SIG_DFL); + + while ((wait_pid = waitpid(-1, &wait_status, 0)) < 0) + if (errno != EINTR) + packet_disconnect("wait: %.100s", strerror(errno)); + if (wait_pid != pid) + error("Strange, wait returned pid %ld, expected %ld", + (long)wait_pid, (long)pid); + + /* 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 { + type = packet_read(); + } + 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 */ +} + +static void +collect_children(void) +{ + pid_t pid; + sigset_t oset, nset; + int status; + + /* block SIGCHLD while we check for dead children */ + sigemptyset(&nset); + sigaddset(&nset, SIGCHLD); + sigprocmask(SIG_BLOCK, &nset, &oset); + if (child_terminated) { + while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || + (pid < 0 && errno == EINTR)) + if (pid > 0) + session_close_by_pid(pid, status); + child_terminated = 0; + } + sigprocmask(SIG_SETMASK, &oset, NULL); +} + +void +server_loop2(Authctxt *authctxt) +{ + fd_set *readset = NULL, *writeset = NULL; + int rekeying = 0, max_fd, nalloc = 0; + + debug("Entering interactive session for SSH2."); + + mysignal(SIGCHLD, sigchld_handler); + child_terminated = 0; + connection_in = packet_get_connection_in(); + connection_out = packet_get_connection_out(); + + notify_setup(); + + max_fd = MAX(connection_in, connection_out); + max_fd = MAX(max_fd, notify_pipe[0]); + + server_init_dispatch(); + + for (;;) { + process_buffered_input_packets(); + + rekeying = (xxx_kex != NULL && !xxx_kex->done); + + if (!rekeying && packet_not_very_much_data_to_write()) + channel_output_poll(); + wait_until_can_do_something(&readset, &writeset, &max_fd, + &nalloc, 0); + + collect_children(); + if (!rekeying) { + channel_after_select(readset, writeset); + if (packet_need_rekeying()) { + debug("need rekeying"); + xxx_kex->done = 0; + kex_send_kexinit(xxx_kex); + } + } + process_input(readset); + if (connection_closed) + break; + process_output(writeset); + } + collect_children(); + + if (readset) + xfree(readset); + if (writeset) + xfree(writeset); + + /* free all channels, no more reads and writes */ + channel_free_all(); + + /* free remaining sessions, e.g. remove wtmp entries */ + session_destroy_all(NULL); +} + +static void +server_input_keep_alive(int type, u_int32_t seq, void *ctxt) +{ + debug("Got %d/%u for keepalive", type, seq); + /* + * reset timeout, since we got a sane answer from the client. + * even if this was generated by something other than + * the bogus CHANNEL_REQUEST we send for keepalives. + */ + client_alive_timeouts = 0; +} + +static void +server_input_stdin_data(int type, u_int32_t seq, void *ctxt) +{ + char *data; + u_int data_len; + + /* Stdin data from the client. Append it to the buffer. */ + /* Ignore any data if the client has closed stdin. */ + if (fdin == -1) + return; + data = packet_get_string(&data_len); + packet_check_eom(); + buffer_append(&stdin_buffer, data, data_len); + memset(data, 0, data_len); + xfree(data); +} + +static void +server_input_eof(int type, u_int32_t seq, void *ctxt) +{ + /* + * 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_check_eom(); + stdin_eof = 1; +} + +static void +server_input_window_size(int type, u_int32_t seq, void *ctxt) +{ + int row = packet_get_int(); + int col = packet_get_int(); + int xpixel = packet_get_int(); + int ypixel = packet_get_int(); + + debug("Window change received."); + packet_check_eom(); + if (fdin != -1) + pty_change_window_size(fdin, row, col, xpixel, ypixel); +} + +static Channel * +server_request_direct_tcpip(void) +{ + Channel *c; + int sock; + char *target, *originator; + int target_port, originator_port; + + target = packet_get_string(NULL); + target_port = packet_get_int(); + originator = packet_get_string(NULL); + originator_port = packet_get_int(); + packet_check_eom(); + + debug("server_request_direct_tcpip: originator %s port %d, target %s port %d", + originator, originator_port, target, target_port); + + /* XXX check permission */ + sock = channel_connect_to(target, target_port); + xfree(target); + xfree(originator); + if (sock < 0) + return NULL; + c = channel_new("direct-tcpip", SSH_CHANNEL_CONNECTING, + sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, + CHAN_TCP_PACKET_DEFAULT, 0, "direct-tcpip", 1); + return c; +} + +static Channel * +server_request_session(void) +{ + Channel *c; + + debug("input_session_request"); + packet_check_eom(); + /* + * A server session has no fd to read or write until a + * CHANNEL_REQUEST for a shell is made, so we set the type to + * SSH_CHANNEL_LARVAL. Additionally, a callback for handling all + * CHANNEL_REQUEST messages is registered. + */ + c = channel_new("session", SSH_CHANNEL_LARVAL, + -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, + 0, "server-session", 1); + if (session_open(the_authctxt, c->self) != 1) { + debug("session open failed, free channel %d", c->self); + channel_free(c); + return NULL; + } + channel_register_cleanup(c->self, session_close_by_channel); + return c; +} + +static void +server_input_channel_open(int type, u_int32_t seq, void *ctxt) +{ + Channel *c = NULL; + char *ctype; + int rchan; + u_int rmaxpack, rwindow, len; + + ctype = packet_get_string(&len); + rchan = packet_get_int(); + rwindow = packet_get_int(); + rmaxpack = packet_get_int(); + + debug("server_input_channel_open: ctype %s rchan %d win %d max %d", + ctype, rchan, rwindow, rmaxpack); + + if (strcmp(ctype, "session") == 0) { + c = server_request_session(); + } else if (strcmp(ctype, "direct-tcpip") == 0) { + c = server_request_direct_tcpip(); + } + if (c != NULL) { + debug("server_input_channel_open: confirm %s", ctype); + c->remote_id = rchan; + c->remote_window = rwindow; + c->remote_maxpacket = rmaxpack; + if (c->type != SSH_CHANNEL_CONNECTING) { + packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION); + packet_put_int(c->remote_id); + packet_put_int(c->self); + packet_put_int(c->local_window); + packet_put_int(c->local_maxpacket); + packet_send(); + } + } else { + debug("server_input_channel_open: failure %s", ctype); + packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE); + packet_put_int(rchan); + packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED); + if (!(datafellows & SSH_BUG_OPENFAILURE)) { + packet_put_cstring("open failed"); + packet_put_cstring(""); + } + packet_send(); + } + xfree(ctype); +} + +static void +server_input_global_request(int type, u_int32_t seq, void *ctxt) +{ + char *rtype; + int want_reply; + int success = 0; + + rtype = packet_get_string(NULL); + want_reply = packet_get_char(); + debug("server_input_global_request: rtype %s want_reply %d", rtype, want_reply); + + /* -R style forwarding */ + if (strcmp(rtype, "tcpip-forward") == 0) { + struct passwd *pw; + char *listen_address; + u_short listen_port; + + pw = the_authctxt->pw; + if (pw == NULL || !the_authctxt->valid) + fatal("server_input_global_request: no/invalid user"); + listen_address = packet_get_string(NULL); + listen_port = (u_short)packet_get_int(); + debug("server_input_global_request: tcpip-forward listen %s port %d", + listen_address, listen_port); + + /* check permissions */ + if (!options.allow_tcp_forwarding || + no_port_forwarding_flag +#ifndef NO_IPPORT_RESERVED_CONCEPT + || (listen_port < IPPORT_RESERVED && pw->pw_uid != 0) +#endif + ) { + success = 0; + packet_send_debug("Server has disabled port forwarding."); + } else { + /* Start listening on the port */ + success = channel_setup_remote_fwd_listener( + listen_address, listen_port, options.gateway_ports); + } + xfree(listen_address); + } else if (strcmp(rtype, "cancel-tcpip-forward") == 0) { + char *cancel_address; + u_short cancel_port; + + cancel_address = packet_get_string(NULL); + cancel_port = (u_short)packet_get_int(); + debug("%s: cancel-tcpip-forward addr %s port %d", __func__, + cancel_address, cancel_port); + + success = channel_cancel_rport_listener(cancel_address, + cancel_port); + } + if (want_reply) { + packet_start(success ? + SSH2_MSG_REQUEST_SUCCESS : SSH2_MSG_REQUEST_FAILURE); + packet_send(); + packet_write_wait(); + } + xfree(rtype); +} +static void +server_input_channel_req(int type, u_int32_t seq, void *ctxt) +{ + Channel *c; + int id, reply, success = 0; + char *rtype; + + id = packet_get_int(); + rtype = packet_get_string(NULL); + reply = packet_get_char(); + + debug("server_input_channel_req: channel %d request %s reply %d", + id, rtype, reply); + + if ((c = channel_lookup(id)) == NULL) + packet_disconnect("server_input_channel_req: " + "unknown channel %d", id); + if (c->type == SSH_CHANNEL_LARVAL || c->type == SSH_CHANNEL_OPEN) + success = session_input_channel_req(c, rtype); + if (reply) { + packet_start(success ? + SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); + packet_put_int(c->remote_id); + packet_send(); + } + xfree(rtype); +} + +static void +server_init_dispatch_20(void) +{ + debug("server_init_dispatch_20"); + dispatch_init(&dispatch_protocol_error); + dispatch_set(SSH2_MSG_CHANNEL_CLOSE, &channel_input_oclose); + dispatch_set(SSH2_MSG_CHANNEL_DATA, &channel_input_data); + dispatch_set(SSH2_MSG_CHANNEL_EOF, &channel_input_ieof); + dispatch_set(SSH2_MSG_CHANNEL_EXTENDED_DATA, &channel_input_extended_data); + dispatch_set(SSH2_MSG_CHANNEL_OPEN, &server_input_channel_open); + dispatch_set(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); + dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); + dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &server_input_channel_req); + dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust); + dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &server_input_global_request); + /* client_alive */ + dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &server_input_keep_alive); + dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &server_input_keep_alive); + dispatch_set(SSH2_MSG_REQUEST_FAILURE, &server_input_keep_alive); + /* rekeying */ + dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); +} +static void +server_init_dispatch_13(void) +{ + debug("server_init_dispatch_13"); + dispatch_init(NULL); + dispatch_set(SSH_CMSG_EOF, &server_input_eof); + dispatch_set(SSH_CMSG_STDIN_DATA, &server_input_stdin_data); + dispatch_set(SSH_CMSG_WINDOW_SIZE, &server_input_window_size); + dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close); + dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation); + dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data); + dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation); + dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure); + dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open); +} +static void +server_init_dispatch_15(void) +{ + server_init_dispatch_13(); + debug("server_init_dispatch_15"); + dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof); + dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_oclose); +} +static void +server_init_dispatch(void) +{ + if (compat20) + server_init_dispatch_20(); + else if (compat13) + server_init_dispatch_13(); + else + server_init_dispatch_15(); +} diff --git a/crypto/openssh-3.9p1/serverloop.h b/crypto/openssh-3.9p1/serverloop.h new file mode 100644 index 0000000000..f419198d1c --- /dev/null +++ b/crypto/openssh-3.9p1/serverloop.h @@ -0,0 +1,27 @@ +/* $OpenBSD: serverloop.h,v 1.5 2001/06/27 02:12:53 markus Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ +/* + * 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). + */ +#ifndef SERVERLOOP_H +#define SERVERLOOP_H + +void server_loop(pid_t, int, int, int); +void server_loop2(Authctxt *); + +#endif diff --git a/crypto/openssh-3.9p1/session.c b/crypto/openssh-3.9p1/session.c new file mode 100644 index 0000000000..ee4008acff --- /dev/null +++ b/crypto/openssh-3.9p1/session.c @@ -0,0 +1,2306 @@ +/* + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + * + * SSH2 support by Markus Friedl. + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: session.c,v 1.180 2004/07/28 09:40:29 markus Exp $"); + +#include "ssh.h" +#include "ssh1.h" +#include "ssh2.h" +#include "xmalloc.h" +#include "sshpty.h" +#include "packet.h" +#include "buffer.h" +#include "match.h" +#include "uidswap.h" +#include "compat.h" +#include "channels.h" +#include "bufaux.h" +#include "auth.h" +#include "auth-options.h" +#include "pathnames.h" +#include "log.h" +#include "servconf.h" +#include "sshlogin.h" +#include "serverloop.h" +#include "canohost.h" +#include "session.h" +#include "monitor_wrap.h" + +#if defined(KRB5) && defined(USE_AFS) +#include +#endif + +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + +/* func */ + +Session *session_new(void); +void session_set_fds(Session *, int, int, int); +void session_pty_cleanup(Session *); +void session_proctitle(Session *); +int session_setup_x11fwd(Session *); +void do_exec_pty(Session *, const char *); +void do_exec_no_pty(Session *, const char *); +void do_exec(Session *, const char *); +void do_login(Session *, const char *); +#ifdef LOGIN_NEEDS_UTMPX +static void do_pre_login(Session *s); +#endif +void do_child(Session *, const char *); +void do_motd(void); +int check_quietlogin(Session *, const char *); + +static void do_authenticated1(Authctxt *); +static void do_authenticated2(Authctxt *); + +static int session_pty_req(Session *); + +/* import */ +extern ServerOptions options; +extern char *__progname; +extern int log_stderr; +extern int debug_flag; +extern u_int utmp_len; +extern int startup_pipe; +extern void destroy_sensitive_data(void); +extern Buffer loginmsg; + +/* original command from peer. */ +const char *original_command = NULL; + +/* data */ +#define MAX_SESSIONS 10 +Session sessions[MAX_SESSIONS]; + +#ifdef HAVE_LOGIN_CAP +login_cap_t *lc; +#endif + +static int is_child = 0; + +/* Name and directory of socket for authentication agent forwarding. */ +static char *auth_sock_name = NULL; +static char *auth_sock_dir = NULL; + +/* removes the agent forwarding socket */ + +static void +auth_sock_cleanup_proc(struct passwd *pw) +{ + if (auth_sock_name != NULL) { + temporarily_use_uid(pw); + unlink(auth_sock_name); + rmdir(auth_sock_dir); + auth_sock_name = NULL; + restore_uid(); + } +} + +static int +auth_input_request_forwarding(struct passwd * pw) +{ + Channel *nc; + int sock; + struct sockaddr_un sunaddr; + + if (auth_sock_name != NULL) { + error("authentication forwarding requested twice."); + return 0; + } + + /* Temporarily drop privileged uid for mkdir/bind. */ + temporarily_use_uid(pw); + + /* Allocate a buffer for the socket name, and format the name. */ + auth_sock_name = xmalloc(MAXPATHLEN); + auth_sock_dir = xmalloc(MAXPATHLEN); + strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN); + + /* Create private directory for socket */ + if (mkdtemp(auth_sock_dir) == NULL) { + packet_send_debug("Agent forwarding disabled: " + "mkdtemp() failed: %.100s", strerror(errno)); + restore_uid(); + xfree(auth_sock_name); + xfree(auth_sock_dir); + auth_sock_name = NULL; + auth_sock_dir = NULL; + return 0; + } + snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", + auth_sock_dir, (long) 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; + strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); + + if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) + packet_disconnect("bind: %.100s", strerror(errno)); + + /* Restore the privileged uid. */ + restore_uid(); + + /* Start listening on the socket. */ + if (listen(sock, SSH_LISTEN_BACKLOG) < 0) + packet_disconnect("listen: %.100s", strerror(errno)); + + /* Allocate a channel for the authentication agent socket. */ + nc = channel_new("auth socket", + SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, + CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, + 0, "auth socket", 1); + strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); + return 1; +} + +static void +display_loginmsg(void) +{ + if (buffer_len(&loginmsg) > 0) { + buffer_append(&loginmsg, "\0", 1); + printf("%s", (char *)buffer_ptr(&loginmsg)); + buffer_clear(&loginmsg); + } +} + +void +do_authenticated(Authctxt *authctxt) +{ + setproctitle("%s", authctxt->pw->pw_name); + + /* + * Cancel the alarm we set to limit the time taken for + * authentication. + */ + alarm(0); + if (startup_pipe != -1) { + close(startup_pipe); + startup_pipe = -1; + } + /* setup the channel layer */ + if (!no_port_forwarding_flag && options.allow_tcp_forwarding) + channel_permit_all_opens(); + + if (compat20) + do_authenticated2(authctxt); + else + do_authenticated1(authctxt); + + do_cleanup(authctxt); +} + +/* + * 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. + */ +static void +do_authenticated1(Authctxt *authctxt) +{ + Session *s; + char *command; + int success, type, screen_flag; + int enable_compression_after_reply = 0; + u_int proto_len, data_len, dlen, compression_level = 0; + + s = session_new(); + s->authctxt = authctxt; + s->pw = authctxt->pw; + + /* + * We stay in this loop until the client requests to execute a shell + * or a command. + */ + for (;;) { + success = 0; + + /* Get a packet from the client. */ + type = packet_read(); + + /* Process the packet. */ + switch (type) { + case SSH_CMSG_REQUEST_COMPRESSION: + compression_level = packet_get_int(); + packet_check_eom(); + if (compression_level < 1 || compression_level > 9) { + packet_send_debug("Received invalid compression level %d.", + compression_level); + break; + } + if (!options.compression) { + debug2("compression disabled"); + break; + } + /* Enable compression after we have responded with SUCCESS. */ + enable_compression_after_reply = 1; + success = 1; + break; + + case SSH_CMSG_REQUEST_PTY: + success = session_pty_req(s); + break; + + case SSH_CMSG_X11_REQUEST_FORWARDING: + s->auth_proto = packet_get_string(&proto_len); + s->auth_data = packet_get_string(&data_len); + + screen_flag = packet_get_protocol_flags() & + SSH_PROTOFLAG_SCREEN_NUMBER; + debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag); + + if (packet_remaining() == 4) { + if (!screen_flag) + debug2("Buggy client: " + "X11 screen flag missing"); + s->screen = packet_get_int(); + } else { + s->screen = 0; + } + packet_check_eom(); + success = session_setup_x11fwd(s); + if (!success) { + xfree(s->auth_proto); + xfree(s->auth_data); + s->auth_proto = NULL; + s->auth_data = NULL; + } + break; + + case SSH_CMSG_AGENT_REQUEST_FORWARDING: + if (no_agent_forwarding_flag || compat13) { + debug("Authentication agent forwarding not permitted for this authentication."); + break; + } + debug("Received authentication agent forwarding request."); + success = auth_input_request_forwarding(s->pw); + break; + + case SSH_CMSG_PORT_FORWARD_REQUEST: + if (no_port_forwarding_flag) { + debug("Port forwarding not permitted for this authentication."); + break; + } + if (!options.allow_tcp_forwarding) { + debug("Port forwarding not permitted."); + break; + } + debug("Received TCP/IP port forwarding request."); + channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports); + success = 1; + break; + + case SSH_CMSG_MAX_PACKET_SIZE: + if (packet_set_maxsize(packet_get_int()) > 0) + success = 1; + break; + + case SSH_CMSG_EXEC_SHELL: + case SSH_CMSG_EXEC_CMD: + if (type == SSH_CMSG_EXEC_CMD) { + command = packet_get_string(&dlen); + debug("Exec command '%.500s'", command); + do_exec(s, command); + xfree(command); + } else { + do_exec(s, NULL); + } + packet_check_eom(); + session_close(s); + return; + + default: + /* + * Any unknown messages in this phase are ignored, + * and a failure message is returned. + */ + logit("Unknown packet type received after authentication: %d", type); + } + packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE); + packet_send(); + packet_write_wait(); + + /* Enable compression now that we have replied if appropriate. */ + if (enable_compression_after_reply) { + enable_compression_after_reply = 0; + packet_start_compression(compression_level); + } + } +} + +/* + * 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(Session *s, const char *command) +{ + pid_t 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 */ + if (s == NULL) + fatal("do_exec_no_pty: no session"); + + session_proctitle(s); + +#if defined(USE_PAM) + if (options.use_pam && !use_privsep) + do_pam_setcred(1); +#endif /* USE_PAM */ + + /* Fork the child. */ + if ((pid = fork()) == 0) { + is_child = 1; + + /* Child. Reinitialize the log since the pid has changed. */ + log_init(__progname, options.log_level, options.log_facility, log_stderr); + + /* + * Create a new session and process group since the 4.4BSD + * setlogin() affects the entire process group. + */ + if (setsid() < 0) + error("setsid failed: %.100s", strerror(errno)); + +#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 */ + +#ifdef _UNICOS + cray_init_job(s->pw); /* set up cray jid and tmpdir */ +#endif + + /* Do processing for the child (exec command etc). */ + do_child(s, command); + /* NOTREACHED */ + } +#ifdef _UNICOS + signal(WJSIGNAL, cray_job_termination_handler); +#endif /* _UNICOS */ +#ifdef HAVE_CYGWIN + if (is_winnt) + cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); +#endif + if (pid < 0) + packet_disconnect("fork failed: %.100s", strerror(errno)); + s->pid = pid; + /* Set interactive/non-interactive mode. */ + packet_set_interactive(s->display != NULL); +#ifdef USE_PIPES + /* We are the parent. Close the child sides of the pipes. */ + close(pin[0]); + close(pout[1]); + close(perr[1]); + + if (compat20) { + if (s->is_subsystem) { + close(perr[0]); + perr[0] = -1; + } + session_set_fds(s, pin[1], pout[0], perr[0]); + } else { + /* Enter the interactive session. */ + server_loop(pid, pin[1], pout[0], perr[0]); + /* server_loop has closed pin[1], pout[0], and perr[0]. */ + } +#else /* USE_PIPES */ + /* We are the parent. Close the child sides of the socket pairs. */ + close(inout[0]); + close(err[0]); + + /* + * Clear loginmsg, since it's the child's responsibility to display + * it to the user, otherwise multiple sessions may accumulate + * multiple copies of the login messages. + */ + buffer_clear(&loginmsg); + + /* + * Enter the interactive session. Note: server_loop must be able to + * handle the case that fdin and fdout are the same. + */ + if (compat20) { + session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]); + } else { + server_loop(pid, inout[1], inout[1], err[1]); + /* server_loop has closed inout[1] and err[1]. */ + } +#endif /* USE_PIPES */ +} + +/* + * 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(Session *s, const char *command) +{ + int fdout, ptyfd, ttyfd, ptymaster; + pid_t pid; + + if (s == NULL) + fatal("do_exec_pty: no session"); + ptyfd = s->ptyfd; + ttyfd = s->ttyfd; + +#if defined(USE_PAM) + if (options.use_pam) { + do_pam_set_tty(s->tty); + if (!use_privsep) + do_pam_setcred(1); + } +#endif + + /* Fork the child. */ + if ((pid = fork()) == 0) { + is_child = 1; + + /* Child. Reinitialize the log because the pid has changed. */ + log_init(__progname, options.log_level, options.log_facility, log_stderr); + /* Close the master side of the pseudo tty. */ + close(ptyfd); + + /* Make the pseudo tty our controlling tty. */ + pty_make_controlling_tty(&ttyfd, s->tty); + + /* Redirect stdin/stdout/stderr from the pseudo tty. */ + if (dup2(ttyfd, 0) < 0) + error("dup2 stdin: %s", strerror(errno)); + if (dup2(ttyfd, 1) < 0) + error("dup2 stdout: %s", strerror(errno)); + if (dup2(ttyfd, 2) < 0) + error("dup2 stderr: %s", strerror(errno)); + + /* Close the extra descriptor for the pseudo tty. */ + close(ttyfd); + + /* record login, etc. similar to login(1) */ +#ifndef HAVE_OSF_SIA + if (!(options.use_login && command == NULL)) { +#ifdef _UNICOS + cray_init_job(s->pw); /* set up cray jid and tmpdir */ +#endif /* _UNICOS */ + do_login(s, command); + } +# ifdef LOGIN_NEEDS_UTMPX + else + do_pre_login(s); +# endif +#endif + + /* Do common processing for the child, such as execing the command. */ + do_child(s, command); + /* NOTREACHED */ + } +#ifdef _UNICOS + signal(WJSIGNAL, cray_job_termination_handler); +#endif /* _UNICOS */ +#ifdef HAVE_CYGWIN + if (is_winnt) + cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); +#endif + if (pid < 0) + packet_disconnect("fork failed: %.100s", strerror(errno)); + s->pid = pid; + + /* 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 #1 failed: %.100s", strerror(errno)); + + /* we keep a reference to the pty master */ + ptymaster = dup(ptyfd); + if (ptymaster < 0) + packet_disconnect("dup #2 failed: %.100s", strerror(errno)); + s->ptymaster = ptymaster; + + /* Enter interactive session. */ + packet_set_interactive(1); + if (compat20) { + session_set_fds(s, ptyfd, fdout, -1); + } else { + server_loop(pid, ptyfd, fdout, -1); + /* server_loop _has_ closed ptyfd and fdout. */ + } +} + +#ifdef LOGIN_NEEDS_UTMPX +static void +do_pre_login(Session *s) +{ + socklen_t fromlen; + struct sockaddr_storage from; + pid_t pid = getpid(); + + /* + * Get IP address of client. If the connection is not a socket, let + * the address be 0.0.0.0. + */ + memset(&from, 0, sizeof(from)); + fromlen = sizeof(from); + if (packet_connection_is_on_socket()) { + if (getpeername(packet_get_connection_in(), + (struct sockaddr *) & from, &fromlen) < 0) { + debug("getpeername: %.100s", strerror(errno)); + cleanup_exit(255); + } + } + + record_utmp_only(pid, s->tty, s->pw->pw_name, + get_remote_name_or_ip(utmp_len, options.use_dns), + (struct sockaddr *)&from, fromlen); +} +#endif + +/* + * This is called to fork and execute a command. If another command is + * to be forced, execute that instead. + */ +void +do_exec(Session *s, const char *command) +{ + if (forced_command) { + original_command = command; + command = forced_command; + debug("Forced command '%.900s'", command); + } + +#ifdef GSSAPI + if (options.gss_authentication) { + temporarily_use_uid(s->pw); + ssh_gssapi_storecreds(); + restore_uid(); + } +#endif + + if (s->ttyfd != -1) + do_exec_pty(s, command); + else + do_exec_no_pty(s, command); + + original_command = NULL; + + /* + * Clear loginmsg: it's the child's responsibility to display + * it to the user, otherwise multiple sessions may accumulate + * multiple copies of the login messages. + */ + buffer_clear(&loginmsg); +} + +/* administrative, login(1)-like work */ +void +do_login(Session *s, const char *command) +{ + socklen_t fromlen; + struct sockaddr_storage from; + struct passwd * pw = s->pw; + pid_t pid = getpid(); + + /* + * Get IP address of client. If the connection is not a socket, let + * the address be 0.0.0.0. + */ + memset(&from, 0, sizeof(from)); + fromlen = sizeof(from); + if (packet_connection_is_on_socket()) { + if (getpeername(packet_get_connection_in(), + (struct sockaddr *) & from, &fromlen) < 0) { + debug("getpeername: %.100s", strerror(errno)); + cleanup_exit(255); + } + } + + /* Record that there was a login on that tty from the remote host. */ + if (!use_privsep) + record_login(pid, s->tty, pw->pw_name, pw->pw_uid, + get_remote_name_or_ip(utmp_len, + options.use_dns), + (struct sockaddr *)&from, fromlen); + +#ifdef USE_PAM + /* + * If password change is needed, do it now. + * This needs to occur before the ~/.hushlogin check. + */ + if (options.use_pam && !use_privsep && s->authctxt->force_pwchange) { + display_loginmsg(); + do_pam_chauthtok(); + s->authctxt->force_pwchange = 0; + /* XXX - signal [net] parent to enable forwardings */ + } +#endif + + if (check_quietlogin(s, command)) + return; + + display_loginmsg(); + + do_motd(); +} + +/* + * Display the message of the day. + */ +void +do_motd(void) +{ + FILE *f; + char buf[256]; + + if (options.print_motd) { +#ifdef HAVE_LOGIN_CAP + f = fopen(login_getcapstr(lc, "welcome", "/etc/motd", + "/etc/motd"), "r"); +#else + f = fopen("/etc/motd", "r"); +#endif + if (f) { + while (fgets(buf, sizeof(buf), f)) + fputs(buf, stdout); + fclose(f); + } + } +} + + +/* + * Check for quiet login, either .hushlogin or command given. + */ +int +check_quietlogin(Session *s, const char *command) +{ + char buf[256]; + struct passwd *pw = s->pw; + struct stat st; + + /* Return 1 if .hushlogin exists or a command given. */ + if (command != NULL) + return 1; + snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir); +#ifdef HAVE_LOGIN_CAP + if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0) + return 1; +#else + if (stat(buf, &st) >= 0) + return 1; +#endif + return 0; +} + +/* + * 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, u_int *envsizep, const char *name, + const char *value) +{ + char **env; + u_int envsize; + u_int i, namelen; + + /* + * If we're passed an uninitialized list, allocate a single null + * entry before continuing. + */ + if (*envp == NULL && *envsizep == 0) { + *envp = xmalloc(sizeof(char *)); + *envp[0] = NULL; + *envsizep = 1; + } + + /* + * 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]) { + /* Reuse the slot. */ + xfree(env[i]); + } else { + /* New variable. Expand if necessary. */ + envsize = *envsizep; + if (i >= envsize - 1) { + if (envsize >= 1000) + fatal("child_set_env: too many env vars"); + envsize += 50; + env = (*envp) = xrealloc(env, envsize * sizeof(char *)); + *envsizep = envsize; + } + /* 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); + snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%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. + */ +static void +read_environment_file(char ***env, u_int *envsize, + const char *filename) +{ + FILE *f; + char buf[4096]; + char *cp, *value; + u_int lineno = 0; + + f = fopen(filename, "r"); + if (!f) + return; + + while (fgets(buf, sizeof(buf), f)) { + if (++lineno > 1000) + fatal("Too many lines in environment file %s", filename); + for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) + ; + if (!*cp || *cp == '#' || *cp == '\n') + continue; + if (strchr(cp, '\n')) + *strchr(cp, '\n') = '\0'; + value = strchr(cp, '='); + if (value == NULL) { + fprintf(stderr, "Bad line %u in %.100s\n", lineno, + filename); + continue; + } + /* + * Replace the equals sign by nul, and advance value to + * the value string. + */ + *value = '\0'; + value++; + child_set_env(env, envsize, cp, value); + } + fclose(f); +} + +#ifdef HAVE_ETC_DEFAULT_LOGIN +/* + * Return named variable from specified environment, or NULL if not present. + */ +static char * +child_get_env(char **env, const char *name) +{ + int i; + size_t len; + + len = strlen(name); + for (i=0; env[i] != NULL; i++) + if (strncmp(name, env[i], len) == 0 && env[i][len] == '=') + return(env[i] + len + 1); + return NULL; +} + +/* + * Read /etc/default/login. + * We pick up the PATH (or SUPATH for root) and UMASK. + */ +static void +read_etc_default_login(char ***env, u_int *envsize, uid_t uid) +{ + char **tmpenv = NULL, *var; + u_int i, tmpenvsize = 0; + u_long mask; + + /* + * We don't want to copy the whole file to the child's environment, + * so we use a temporary environment and copy the variables we're + * interested in. + */ + read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login"); + + if (tmpenv == NULL) + return; + + if (uid == 0) + var = child_get_env(tmpenv, "SUPATH"); + else + var = child_get_env(tmpenv, "PATH"); + if (var != NULL) + child_set_env(env, envsize, "PATH", var); + + if ((var = child_get_env(tmpenv, "UMASK")) != NULL) + if (sscanf(var, "%5lo", &mask) == 1) + umask((mode_t)mask); + + for (i = 0; tmpenv[i] != NULL; i++) + xfree(tmpenv[i]); + xfree(tmpenv); +} +#endif /* HAVE_ETC_DEFAULT_LOGIN */ + +void copy_environment(char **source, char ***env, u_int *envsize) +{ + char *var_name, *var_val; + int i; + + if (source == NULL) + return; + + for(i = 0; source[i] != NULL; i++) { + var_name = xstrdup(source[i]); + if ((var_val = strstr(var_name, "=")) == NULL) { + xfree(var_name); + continue; + } + *var_val++ = '\0'; + + debug3("Copy environment: %s=%s", var_name, var_val); + child_set_env(env, envsize, var_name, var_val); + + xfree(var_name); + } +} + +static char ** +do_setup_env(Session *s, const char *shell) +{ + char buf[256]; + u_int i, envsize; + char **env, *laddr, *path = NULL; + struct passwd *pw = s->pw; + + /* Initialize the environment. */ + envsize = 100; + env = xmalloc(envsize * sizeof(char *)); + env[0] = NULL; + +#ifdef HAVE_CYGWIN + /* + * The Windows environment contains some setting which are + * important for a running system. They must not be dropped. + */ + copy_environment(environ, &env, &envsize); +#endif + +#ifdef GSSAPI + /* Allow any GSSAPI methods that we've used to alter + * the childs environment as they see fit + */ + ssh_gssapi_do_child(&env, &envsize); +#endif + + if (!options.use_login) { + /* Set basic environment. */ + for (i = 0; i < s->num_env; i++) + child_set_env(&env, &envsize, s->env[i].name, + s->env[i].val); + + child_set_env(&env, &envsize, "USER", pw->pw_name); + child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); +#ifdef _AIX + child_set_env(&env, &envsize, "LOGIN", pw->pw_name); +#endif + child_set_env(&env, &envsize, "HOME", pw->pw_dir); +#ifdef HAVE_LOGIN_CAP + if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0) + child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); + else + child_set_env(&env, &envsize, "PATH", getenv("PATH")); +#else /* HAVE_LOGIN_CAP */ +# ifndef HAVE_CYGWIN + /* + * There's no standard path on Windows. The path contains + * important components pointing to the system directories, + * needed for loading shared libraries. So the path better + * remains intact here. + */ +# ifdef HAVE_ETC_DEFAULT_LOGIN + read_etc_default_login(&env, &envsize, pw->pw_uid); + path = child_get_env(env, "PATH"); +# endif /* HAVE_ETC_DEFAULT_LOGIN */ + if (path == NULL || *path == '\0') { + child_set_env(&env, &envsize, "PATH", + s->pw->pw_uid == 0 ? + SUPERUSER_PATH : _PATH_STDPATH); + } +# endif /* HAVE_CYGWIN */ +#endif /* HAVE_LOGIN_CAP */ + + snprintf(buf, sizeof buf, "%.200s/%.50s", + _PATH_MAILDIR, pw->pw_name); + child_set_env(&env, &envsize, "MAIL", buf); + + /* Normal systems set SHELL by default. */ + child_set_env(&env, &envsize, "SHELL", shell); + } + if (getenv("TZ")) + child_set_env(&env, &envsize, "TZ", getenv("TZ")); + + /* Set custom environment options from RSA authentication. */ + if (!options.use_login) { + while (custom_environment) { + struct envstring *ce = custom_environment; + char *str = ce->s; + + for (i = 0; str[i] != '=' && str[i]; i++) + ; + if (str[i] == '=') { + str[i] = 0; + child_set_env(&env, &envsize, str, str + i + 1); + } + custom_environment = ce->next; + xfree(ce->s); + xfree(ce); + } + } + + /* SSH_CLIENT deprecated */ + snprintf(buf, sizeof buf, "%.50s %d %d", + get_remote_ipaddr(), get_remote_port(), get_local_port()); + child_set_env(&env, &envsize, "SSH_CLIENT", buf); + + laddr = get_local_ipaddr(packet_get_connection_in()); + snprintf(buf, sizeof buf, "%.50s %d %.50s %d", + get_remote_ipaddr(), get_remote_port(), laddr, get_local_port()); + xfree(laddr); + child_set_env(&env, &envsize, "SSH_CONNECTION", buf); + + if (s->ttyfd != -1) + child_set_env(&env, &envsize, "SSH_TTY", s->tty); + if (s->term) + child_set_env(&env, &envsize, "TERM", s->term); + if (s->display) + child_set_env(&env, &envsize, "DISPLAY", s->display); + if (original_command) + child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND", + original_command); + +#ifdef _UNICOS + if (cray_tmpdir[0] != '\0') + child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir); +#endif /* _UNICOS */ + +#ifdef _AIX + { + char *cp; + + if ((cp = getenv("AUTHSTATE")) != NULL) + child_set_env(&env, &envsize, "AUTHSTATE", cp); + if ((cp = getenv("KRB5CCNAME")) != NULL) + child_set_env(&env, &envsize, "KRB5CCNAME", cp); + read_environment_file(&env, &envsize, "/etc/environment"); + } +#endif +#ifdef KRB5 + if (s->authctxt->krb5_ccname) + child_set_env(&env, &envsize, "KRB5CCNAME", + s->authctxt->krb5_ccname); +#endif +#ifdef USE_PAM + /* + * Pull in any environment variables that may have + * been set by PAM. + */ + if (options.use_pam) { + char **p; + + p = fetch_pam_child_environment(); + copy_environment(p, &env, &envsize); + free_pam_environment(p); + + p = fetch_pam_environment(); + copy_environment(p, &env, &envsize); + free_pam_environment(p); + } +#endif /* USE_PAM */ + + if (auth_sock_name != NULL) + child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, + auth_sock_name); + + /* read $HOME/.ssh/environment. */ + if (options.permit_user_env && !options.use_login) { + snprintf(buf, sizeof buf, "%.200s/.ssh/environment", + strcmp(pw->pw_dir, "/") ? pw->pw_dir : ""); + read_environment_file(&env, &envsize, buf); + } + if (debug_flag) { + /* dump the environment */ + fprintf(stderr, "Environment:\n"); + for (i = 0; env[i]; i++) + fprintf(stderr, " %.200s\n", env[i]); + } + return env; +} + +/* + * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found + * first in this order). + */ +static void +do_rc_files(Session *s, const char *shell) +{ + FILE *f = NULL; + char cmd[1024]; + int do_xauth; + struct stat st; + + do_xauth = + s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; + + /* ignore _PATH_SSH_USER_RC for subsystems */ + if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) { + snprintf(cmd, sizeof cmd, "%s -c '%s %s'", + shell, _PATH_BSHELL, _PATH_SSH_USER_RC); + if (debug_flag) + fprintf(stderr, "Running %s\n", cmd); + f = popen(cmd, "w"); + if (f) { + if (do_xauth) + fprintf(f, "%s %s\n", s->auth_proto, + s->auth_data); + pclose(f); + } else + fprintf(stderr, "Could not run %s\n", + _PATH_SSH_USER_RC); + } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { + if (debug_flag) + fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, + _PATH_SSH_SYSTEM_RC); + f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); + if (f) { + if (do_xauth) + fprintf(f, "%s %s\n", s->auth_proto, + s->auth_data); + pclose(f); + } else + fprintf(stderr, "Could not run %s\n", + _PATH_SSH_SYSTEM_RC); + } else if (do_xauth && options.xauth_location != NULL) { + /* Add authority data to .Xauthority if appropriate. */ + if (debug_flag) { + fprintf(stderr, + "Running %.500s remove %.100s\n", + options.xauth_location, s->auth_display); + fprintf(stderr, + "%.500s add %.100s %.100s %.100s\n", + options.xauth_location, s->auth_display, + s->auth_proto, s->auth_data); + } + snprintf(cmd, sizeof cmd, "%s -q -", + options.xauth_location); + f = popen(cmd, "w"); + if (f) { + fprintf(f, "remove %s\n", + s->auth_display); + fprintf(f, "add %s %s %s\n", + s->auth_display, s->auth_proto, + s->auth_data); + pclose(f); + } else { + fprintf(stderr, "Could not run %s\n", + cmd); + } + } +} + +static void +do_nologin(struct passwd *pw) +{ + FILE *f = NULL; + char buf[1024]; + +#ifdef HAVE_LOGIN_CAP + if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) + f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, + _PATH_NOLOGIN), "r"); +#else + if (pw->pw_uid) + f = fopen(_PATH_NOLOGIN, "r"); +#endif + if (f) { + /* /etc/nologin exists. Print its contents and exit. */ + logit("User %.100s not allowed because %s exists", + pw->pw_name, _PATH_NOLOGIN); + while (fgets(buf, sizeof(buf), f)) + fputs(buf, stderr); + fclose(f); + fflush(NULL); + exit(254); + } +} + +/* Set login name, uid, gid, and groups. */ +void +do_setusercontext(struct passwd *pw) +{ +#ifndef HAVE_CYGWIN + if (getuid() == 0 || geteuid() == 0) +#endif /* HAVE_CYGWIN */ + { + +#ifdef HAVE_SETPCRED + if (setpcred(pw->pw_name, (char **)NULL) == -1) + fatal("Failed to set process credentials"); +#endif /* HAVE_SETPCRED */ +#ifdef HAVE_LOGIN_CAP +# ifdef __bsdi__ + setpgid(0, 0); +# endif +# ifdef USE_PAM + if (options.use_pam) { + do_pam_session(); + do_pam_setcred(0); + } +# endif /* USE_PAM */ + if (setusercontext(lc, pw, pw->pw_uid, + (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { + perror("unable to set user context"); + exit(1); + } +#else +# if defined(HAVE_GETLUID) && defined(HAVE_SETLUID) + /* Sets login uid for accounting */ + if (getluid() == -1 && setluid(pw->pw_uid) == -1) + error("setluid: %s", strerror(errno)); +# endif /* defined(HAVE_GETLUID) && defined(HAVE_SETLUID) */ + + if (setlogin(pw->pw_name) < 0) + error("setlogin failed: %s", strerror(errno)); + if (setgid(pw->pw_gid) < 0) { + perror("setgid"); + exit(1); + } + /* Initialize the group list. */ + if (initgroups(pw->pw_name, pw->pw_gid) < 0) { + perror("initgroups"); + exit(1); + } + endgrent(); +# ifdef USE_PAM + /* + * PAM credentials may take the form of supplementary groups. + * These will have been wiped by the above initgroups() call. + * Reestablish them here. + */ + if (options.use_pam) { + do_pam_session(); + do_pam_setcred(0); + } +# endif /* USE_PAM */ +# if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) + irix_setusercontext(pw); +# endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ +# ifdef _AIX + aix_usrinfo(pw); +# endif /* _AIX */ + /* Permanently switch to the desired uid. */ + permanently_set_uid(pw); +#endif + } + +#ifdef HAVE_CYGWIN + if (is_winnt) +#endif + if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) + fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); +} + +static void +do_pwchange(Session *s) +{ + fflush(NULL); + fprintf(stderr, "WARNING: Your password has expired.\n"); + if (s->ttyfd != -1) { + fprintf(stderr, + "You must change your password now and login again!\n"); + execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL); + perror("passwd"); + } else { + fprintf(stderr, + "Password change required but no TTY available.\n"); + } + exit(1); +} + +static void +launch_login(struct passwd *pw, const char *hostname) +{ + /* Launch login(1). */ + + execl(LOGIN_PROGRAM, "login", "-h", hostname, +#ifdef xxxLOGIN_NEEDS_TERM + (s->term ? s->term : "unknown"), +#endif /* LOGIN_NEEDS_TERM */ +#ifdef LOGIN_NO_ENDOPT + "-p", "-f", pw->pw_name, (char *)NULL); +#else + "-p", "-f", "--", pw->pw_name, (char *)NULL); +#endif + + /* Login couldn't be executed, die. */ + + perror("login"); + exit(1); +} + +static void +child_close_fds(void) +{ + int i; + + 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. + */ + /* XXX better use close-on-exec? -markus */ + 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(); + + /* + * 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++) + close(i); +} + +/* + * 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(Session *s, const char *command) +{ + extern char **environ; + char **env; + char *argv[10]; + const char *shell, *shell0, *hostname = NULL; + struct passwd *pw = s->pw; + + /* remove hostkey from the child's memory */ + destroy_sensitive_data(); + + /* Force a password change */ + if (s->authctxt->force_pwchange) { + do_setusercontext(pw); + child_close_fds(); + do_pwchange(s); + exit(1); + } + + /* login(1) is only called if we execute the login shell */ + if (options.use_login && command != NULL) + options.use_login = 0; + +#ifdef _UNICOS + cray_setup(pw->pw_uid, pw->pw_name, command); +#endif /* _UNICOS */ + + /* + * Login(1) does this as well, and it needs uid 0 for the "-h" + * switch, so we let login(1) to this for us. + */ + if (!options.use_login) { +#ifdef HAVE_OSF_SIA + session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty); + if (!check_quietlogin(s, command)) + do_motd(); +#else /* HAVE_OSF_SIA */ + do_nologin(pw); + do_setusercontext(pw); + /* + * PAM session modules in do_setusercontext may have + * generated messages, so if this in an interactive + * login then display them too. + */ + if (command == NULL) + display_loginmsg(); +#endif /* HAVE_OSF_SIA */ + } + + /* + * Get the shell from the password data. An empty shell field is + * legal, and means /bin/sh. + */ + shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; + + /* + * Make sure $SHELL points to the shell from the password file, + * even if shell is overridden from login.conf + */ + env = do_setup_env(s, shell); + +#ifdef HAVE_LOGIN_CAP + shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); +#endif + + /* we have to stash the hostname before we close our socket. */ + if (options.use_login) + hostname = get_remote_name_or_ip(utmp_len, + options.use_dns); + /* + * 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. + */ + child_close_fds(); + + /* + * Must take new environment into use so that .ssh/rc, + * /etc/ssh/sshrc and xauth are run in the proper environment. + */ + environ = env; + +#if defined(KRB5) && defined(USE_AFS) + /* + * At this point, we check to see if AFS is active and if we have + * a valid Kerberos 5 TGT. If so, it seems like a good idea to see + * if we can (and need to) extend the ticket into an AFS token. If + * we don't do this, we run into potential problems if the user's + * home directory is in AFS and it's not world-readable. + */ + + if (options.kerberos_get_afs_token && k_hasafs() && + (s->authctxt->krb5_ctx != NULL)) { + char cell[64]; + + debug("Getting AFS token"); + + k_setpag(); + + if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) + krb5_afslog(s->authctxt->krb5_ctx, + s->authctxt->krb5_fwd_ccache, cell, NULL); + + krb5_afslog_home(s->authctxt->krb5_ctx, + s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir); + } +#endif + + /* 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)); +#ifdef HAVE_LOGIN_CAP + if (login_getcapbool(lc, "requirehome", 0)) + exit(1); +#endif + } + + if (!options.use_login) + do_rc_files(s, shell); + + /* restore SIGPIPE for child */ + signal(SIGPIPE, SIG_DFL); + + if (options.use_login) { + launch_login(pw, hostname); + /* NEVERREACHED */ + } + + /* Get the last component of the shell name. */ + if ((shell0 = strrchr(shell, '/')) != NULL) + shell0++; + else + shell0 = 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 argv0[256]; + + /* Start the shell. Set initial character to '-'. */ + argv0[0] = '-'; + + if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1) + >= sizeof(argv0) - 1) { + errno = EINVAL; + perror(shell); + exit(1); + } + + /* Execute the shell. */ + argv[0] = argv0; + 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 *) shell0; + argv[1] = "-c"; + argv[2] = (char *) command; + argv[3] = NULL; + execve(shell, argv, env); + perror(shell); + exit(1); +} + +Session * +session_new(void) +{ + int i; + static int did_init = 0; + if (!did_init) { + debug("session_new: init"); + for (i = 0; i < MAX_SESSIONS; i++) { + sessions[i].used = 0; + } + did_init = 1; + } + for (i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (! s->used) { + memset(s, 0, sizeof(*s)); + s->chanid = -1; + s->ptyfd = -1; + s->ttyfd = -1; + s->used = 1; + s->self = i; + debug("session_new: session %d", i); + return s; + } + } + return NULL; +} + +static void +session_dump(void) +{ + int i; + for (i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + debug("dump: used %d session %d %p channel %d pid %ld", + s->used, + s->self, + s, + s->chanid, + (long)s->pid); + } +} + +int +session_open(Authctxt *authctxt, int chanid) +{ + Session *s = session_new(); + debug("session_open: channel %d", chanid); + if (s == NULL) { + error("no more sessions"); + return 0; + } + s->authctxt = authctxt; + s->pw = authctxt->pw; + if (s->pw == NULL || !authctxt->valid) + fatal("no user for session %d", s->self); + debug("session_open: session %d: link with channel %d", s->self, chanid); + s->chanid = chanid; + return 1; +} + +Session * +session_by_tty(char *tty) +{ + int i; + for (i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { + debug("session_by_tty: session %d tty %s", i, tty); + return s; + } + } + debug("session_by_tty: unknown tty %.100s", tty); + session_dump(); + return NULL; +} + +static Session * +session_by_channel(int id) +{ + int i; + for (i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (s->used && s->chanid == id) { + debug("session_by_channel: session %d channel %d", i, id); + return s; + } + } + debug("session_by_channel: unknown channel %d", id); + session_dump(); + return NULL; +} + +static Session * +session_by_pid(pid_t pid) +{ + int i; + debug("session_by_pid: pid %ld", (long)pid); + for (i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (s->used && s->pid == pid) + return s; + } + error("session_by_pid: unknown pid %ld", (long)pid); + session_dump(); + return NULL; +} + +static int +session_window_change_req(Session *s) +{ + s->col = packet_get_int(); + s->row = packet_get_int(); + s->xpixel = packet_get_int(); + s->ypixel = packet_get_int(); + packet_check_eom(); + pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); + return 1; +} + +static int +session_pty_req(Session *s) +{ + u_int len; + int n_bytes; + + if (no_pty_flag) { + debug("Allocating a pty not permitted for this authentication."); + return 0; + } + if (s->ttyfd != -1) { + packet_disconnect("Protocol error: you already have a pty."); + return 0; + } + + s->term = packet_get_string(&len); + + if (compat20) { + s->col = packet_get_int(); + s->row = packet_get_int(); + } else { + s->row = packet_get_int(); + s->col = packet_get_int(); + } + s->xpixel = packet_get_int(); + s->ypixel = packet_get_int(); + + if (strcmp(s->term, "") == 0) { + xfree(s->term); + s->term = NULL; + } + + /* Allocate a pty and open it. */ + debug("Allocating pty."); + if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { + if (s->term) + xfree(s->term); + s->term = NULL; + s->ptyfd = -1; + s->ttyfd = -1; + error("session_pty_req: session %d alloc failed", s->self); + return 0; + } + debug("session_pty_req: session %d alloc %s", s->self, s->tty); + + /* for SSH1 the tty modes length is not given */ + if (!compat20) + n_bytes = packet_remaining(); + tty_parse_modes(s->ttyfd, &n_bytes); + + if (!use_privsep) + pty_setowner(s->pw, s->tty); + + /* Set window size from the packet. */ + pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); + + packet_check_eom(); + session_proctitle(s); + return 1; +} + +static int +session_subsystem_req(Session *s) +{ + struct stat st; + u_int len; + int success = 0; + char *cmd, *subsys = packet_get_string(&len); + int i; + + packet_check_eom(); + logit("subsystem request for %.100s", subsys); + + for (i = 0; i < options.num_subsystems; i++) { + if (strcmp(subsys, options.subsystem_name[i]) == 0) { + cmd = options.subsystem_command[i]; + if (stat(cmd, &st) < 0) { + error("subsystem: cannot stat %s: %s", cmd, + strerror(errno)); + break; + } + debug("subsystem: exec() %s", cmd); + s->is_subsystem = 1; + do_exec(s, cmd); + success = 1; + break; + } + } + + if (!success) + logit("subsystem request for %.100s failed, subsystem not found", + subsys); + + xfree(subsys); + return success; +} + +static int +session_x11_req(Session *s) +{ + int success; + + s->single_connection = packet_get_char(); + s->auth_proto = packet_get_string(NULL); + s->auth_data = packet_get_string(NULL); + s->screen = packet_get_int(); + packet_check_eom(); + + success = session_setup_x11fwd(s); + if (!success) { + xfree(s->auth_proto); + xfree(s->auth_data); + s->auth_proto = NULL; + s->auth_data = NULL; + } + return success; +} + +static int +session_shell_req(Session *s) +{ + packet_check_eom(); + do_exec(s, NULL); + return 1; +} + +static int +session_exec_req(Session *s) +{ + u_int len; + char *command = packet_get_string(&len); + packet_check_eom(); + do_exec(s, command); + xfree(command); + return 1; +} + +static int +session_break_req(Session *s) +{ + + packet_get_int(); /* ignored */ + packet_check_eom(); + + if (s->ttyfd == -1 || + tcsendbreak(s->ttyfd, 0) < 0) + return 0; + return 1; +} + +static int +session_env_req(Session *s) +{ + char *name, *val; + u_int name_len, val_len, i; + + name = packet_get_string(&name_len); + val = packet_get_string(&val_len); + packet_check_eom(); + + /* Don't set too many environment variables */ + if (s->num_env > 128) { + debug2("Ignoring env request %s: too many env vars", name); + goto fail; + } + + for (i = 0; i < options.num_accept_env; i++) { + if (match_pattern(name, options.accept_env[i])) { + debug2("Setting env %d: %s=%s", s->num_env, name, val); + s->env = xrealloc(s->env, sizeof(*s->env) * + (s->num_env + 1)); + s->env[s->num_env].name = name; + s->env[s->num_env].val = val; + s->num_env++; + return (1); + } + } + debug2("Ignoring env request %s: disallowed name", name); + + fail: + xfree(name); + xfree(val); + return (0); +} + +static int +session_auth_agent_req(Session *s) +{ + static int called = 0; + packet_check_eom(); + if (no_agent_forwarding_flag) { + debug("session_auth_agent_req: no_agent_forwarding_flag"); + return 0; + } + if (called) { + return 0; + } else { + called = 1; + return auth_input_request_forwarding(s->pw); + } +} + +int +session_input_channel_req(Channel *c, const char *rtype) +{ + int success = 0; + Session *s; + + if ((s = session_by_channel(c->self)) == NULL) { + logit("session_input_channel_req: no session %d req %.100s", + c->self, rtype); + return 0; + } + debug("session_input_channel_req: session %d req %s", s->self, rtype); + + /* + * a session is in LARVAL state until a shell, a command + * or a subsystem is executed + */ + if (c->type == SSH_CHANNEL_LARVAL) { + if (strcmp(rtype, "shell") == 0) { + success = session_shell_req(s); + } else if (strcmp(rtype, "exec") == 0) { + success = session_exec_req(s); + } else if (strcmp(rtype, "pty-req") == 0) { + success = session_pty_req(s); + } else if (strcmp(rtype, "x11-req") == 0) { + success = session_x11_req(s); + } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) { + success = session_auth_agent_req(s); + } else if (strcmp(rtype, "subsystem") == 0) { + success = session_subsystem_req(s); + } else if (strcmp(rtype, "env") == 0) { + success = session_env_req(s); + } + } + if (strcmp(rtype, "window-change") == 0) { + success = session_window_change_req(s); + } else if (strcmp(rtype, "break") == 0) { + success = session_break_req(s); + } + + return success; +} + +void +session_set_fds(Session *s, int fdin, int fdout, int fderr) +{ + if (!compat20) + fatal("session_set_fds: called for proto != 2.0"); + /* + * now that have a child and a pipe to the child, + * we can activate our channel and register the fd's + */ + if (s->chanid == -1) + fatal("no channel for session %d", s->self); + channel_set_fds(s->chanid, + fdout, fdin, fderr, + fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, + 1, + CHAN_SES_WINDOW_DEFAULT); +} + +/* + * Function to perform pty cleanup. Also called if we get aborted abnormally + * (e.g., due to a dropped connection). + */ +void +session_pty_cleanup2(Session *s) +{ + if (s == NULL) { + error("session_pty_cleanup: no session"); + return; + } + if (s->ttyfd == -1) + return; + + debug("session_pty_cleanup: session %d release %s", s->self, s->tty); + + /* Record that the user has logged out. */ + if (s->pid != 0) + record_logout(s->pid, s->tty, s->pw->pw_name); + + /* Release the pseudo-tty. */ + if (getuid() == 0) + pty_release(s->tty); + + /* + * 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. + */ + if (close(s->ptymaster) < 0) + error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); + + /* unlink pty from session */ + s->ttyfd = -1; +} + +void +session_pty_cleanup(Session *s) +{ + PRIVSEP(session_pty_cleanup2(s)); +} + +static char * +sig2name(int sig) +{ +#define SSH_SIG(x) if (sig == SIG ## x) return #x + SSH_SIG(ABRT); + SSH_SIG(ALRM); + SSH_SIG(FPE); + SSH_SIG(HUP); + SSH_SIG(ILL); + SSH_SIG(INT); + SSH_SIG(KILL); + SSH_SIG(PIPE); + SSH_SIG(QUIT); + SSH_SIG(SEGV); + SSH_SIG(TERM); + SSH_SIG(USR1); + SSH_SIG(USR2); +#undef SSH_SIG + return "SIG@openssh.com"; +} + +static void +session_exit_message(Session *s, int status) +{ + Channel *c; + + if ((c = channel_lookup(s->chanid)) == NULL) + fatal("session_exit_message: session %d: no channel %d", + s->self, s->chanid); + debug("session_exit_message: session %d channel %d pid %ld", + s->self, s->chanid, (long)s->pid); + + if (WIFEXITED(status)) { + channel_request_start(s->chanid, "exit-status", 0); + packet_put_int(WEXITSTATUS(status)); + packet_send(); + } else if (WIFSIGNALED(status)) { + channel_request_start(s->chanid, "exit-signal", 0); + packet_put_cstring(sig2name(WTERMSIG(status))); +#ifdef WCOREDUMP + packet_put_char(WCOREDUMP(status)); +#else /* WCOREDUMP */ + packet_put_char(0); +#endif /* WCOREDUMP */ + packet_put_cstring(""); + packet_put_cstring(""); + packet_send(); + } else { + /* Some weird exit cause. Just exit. */ + packet_disconnect("wait returned status %04x.", status); + } + + /* disconnect channel */ + debug("session_exit_message: release channel %d", s->chanid); + channel_cancel_cleanup(s->chanid); + /* + * emulate a write failure with 'chan_write_failed', nobody will be + * interested in data we write. + * Note that we must not call 'chan_read_failed', since there could + * be some more data waiting in the pipe. + */ + if (c->ostate != CHAN_OUTPUT_CLOSED) + chan_write_failed(c); + s->chanid = -1; +} + +void +session_close(Session *s) +{ + int i; + + debug("session_close: session %d pid %ld", s->self, (long)s->pid); + if (s->ttyfd != -1) + session_pty_cleanup(s); + if (s->term) + xfree(s->term); + if (s->display) + xfree(s->display); + if (s->auth_display) + xfree(s->auth_display); + if (s->auth_data) + xfree(s->auth_data); + if (s->auth_proto) + xfree(s->auth_proto); + s->used = 0; + for (i = 0; i < s->num_env; i++) { + xfree(s->env[i].name); + xfree(s->env[i].val); + } + if (s->env != NULL) + xfree(s->env); + session_proctitle(s); +} + +void +session_close_by_pid(pid_t pid, int status) +{ + Session *s = session_by_pid(pid); + if (s == NULL) { + debug("session_close_by_pid: no session for pid %ld", + (long)pid); + return; + } + if (s->chanid != -1) + session_exit_message(s, status); + session_close(s); +} + +/* + * this is called when a channel dies before + * the session 'child' itself dies + */ +void +session_close_by_channel(int id, void *arg) +{ + Session *s = session_by_channel(id); + if (s == NULL) { + debug("session_close_by_channel: no session for id %d", id); + return; + } + debug("session_close_by_channel: channel %d child %ld", + id, (long)s->pid); + if (s->pid != 0) { + debug("session_close_by_channel: channel %d: has child", id); + /* + * delay detach of session, but release pty, since + * the fd's to the child are already closed + */ + if (s->ttyfd != -1) + session_pty_cleanup(s); + return; + } + /* detach by removing callback */ + channel_cancel_cleanup(s->chanid); + s->chanid = -1; + session_close(s); +} + +void +session_destroy_all(void (*closefunc)(Session *)) +{ + int i; + for (i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (s->used) { + if (closefunc != NULL) + closefunc(s); + else + session_close(s); + } + } +} + +static char * +session_tty_list(void) +{ + static char buf[1024]; + int i; + char *cp; + + buf[0] = '\0'; + for (i = 0; i < MAX_SESSIONS; i++) { + Session *s = &sessions[i]; + if (s->used && s->ttyfd != -1) { + + if (strncmp(s->tty, "/dev/", 5) != 0) { + cp = strrchr(s->tty, '/'); + cp = (cp == NULL) ? s->tty : cp + 1; + } else + cp = s->tty + 5; + + if (buf[0] != '\0') + strlcat(buf, ",", sizeof buf); + strlcat(buf, cp, sizeof buf); + } + } + if (buf[0] == '\0') + strlcpy(buf, "notty", sizeof buf); + return buf; +} + +void +session_proctitle(Session *s) +{ + if (s->pw == NULL) + error("no user for session %d", s->self); + else + setproctitle("%s@%s", s->pw->pw_name, session_tty_list()); +} + +int +session_setup_x11fwd(Session *s) +{ + struct stat st; + char display[512], auth_display[512]; + char hostname[MAXHOSTNAMELEN]; + + if (no_x11_forwarding_flag) { + packet_send_debug("X11 forwarding disabled in user configuration file."); + return 0; + } + if (!options.x11_forwarding) { + debug("X11 forwarding disabled in server configuration file."); + return 0; + } + if (!options.xauth_location || + (stat(options.xauth_location, &st) == -1)) { + packet_send_debug("No xauth program; cannot forward with spoofing."); + return 0; + } + if (options.use_login) { + packet_send_debug("X11 forwarding disabled; " + "not compatible with UseLogin=yes."); + return 0; + } + if (s->display != NULL) { + debug("X11 display already set."); + return 0; + } + if (x11_create_display_inet(options.x11_display_offset, + options.x11_use_localhost, s->single_connection, + &s->display_number) == -1) { + debug("x11_create_display_inet failed."); + return 0; + } + + /* Set up a suitable value for the DISPLAY variable. */ + if (gethostname(hostname, sizeof(hostname)) < 0) + fatal("gethostname: %.100s", strerror(errno)); + /* + * auth_display must be used as the displayname when the + * authorization entry is added with xauth(1). This will be + * different than the DISPLAY string for localhost displays. + */ + if (options.x11_use_localhost) { + snprintf(display, sizeof display, "localhost:%u.%u", + s->display_number, s->screen); + snprintf(auth_display, sizeof auth_display, "unix:%u.%u", + s->display_number, s->screen); + s->display = xstrdup(display); + s->auth_display = xstrdup(auth_display); + } else { +#ifdef IPADDR_IN_DISPLAY + struct hostent *he; + struct in_addr my_addr; + + he = gethostbyname(hostname); + if (he == NULL) { + error("Can't get IP address for X11 DISPLAY."); + packet_send_debug("Can't get IP address for X11 DISPLAY."); + return 0; + } + memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr)); + snprintf(display, sizeof display, "%.50s:%u.%u", inet_ntoa(my_addr), + s->display_number, s->screen); +#else + snprintf(display, sizeof display, "%.400s:%u.%u", hostname, + s->display_number, s->screen); +#endif + s->display = xstrdup(display); + s->auth_display = xstrdup(display); + } + + return 1; +} + +static void +do_authenticated2(Authctxt *authctxt) +{ + server_loop2(authctxt); +} + +void +do_cleanup(Authctxt *authctxt) +{ + static int called = 0; + + debug("do_cleanup"); + + /* no cleanup if we're in the child for login shell */ + if (is_child) + return; + + /* avoid double cleanup */ + if (called) + return; + called = 1; + + if (authctxt == NULL) + return; +#ifdef KRB5 + if (options.kerberos_ticket_cleanup && + authctxt->krb5_ctx) + krb5_cleanup_proc(authctxt); +#endif + +#ifdef GSSAPI + if (compat20 && options.gss_cleanup_creds) + ssh_gssapi_cleanup_creds(); +#endif + +#ifdef USE_PAM + if (options.use_pam) { + sshpam_cleanup(); + sshpam_thread_cleanup(); + } +#endif + + /* remove agent socket */ + auth_sock_cleanup_proc(authctxt->pw); + + /* + * Cleanup ptys/utmp only if privsep is disabled, + * or if running in monitor. + */ + if (!use_privsep || mm_is_monitor()) + session_destroy_all(session_pty_cleanup2); +} diff --git a/crypto/openssh-3.9p1/session.h b/crypto/openssh-3.9p1/session.h new file mode 100644 index 0000000000..48be5070c8 --- /dev/null +++ b/crypto/openssh-3.9p1/session.h @@ -0,0 +1,77 @@ +/* $OpenBSD: session.h,v 1.23 2004/07/17 05:31:41 dtucker Exp $ */ + +/* + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SESSION_H +#define SESSION_H + +#define TTYSZ 64 +typedef struct Session Session; +struct Session { + int used; + int self; + struct passwd *pw; + Authctxt *authctxt; + pid_t pid; + /* tty */ + char *term; + int ptyfd, ttyfd, ptymaster; + u_int row, col, xpixel, ypixel; + char tty[TTYSZ]; + /* X11 */ + u_int display_number; + char *display; + u_int screen; + char *auth_display; + char *auth_proto; + char *auth_data; + int single_connection; + /* proto 2 */ + int chanid; + int is_subsystem; + int num_env; + struct { + char *name; + char *val; + } *env; +}; + +void do_authenticated(Authctxt *); +void do_cleanup(Authctxt *); + +int session_open(Authctxt *, int); +int session_input_channel_req(Channel *, const char *); +void session_close_by_pid(pid_t, int); +void session_close_by_channel(int, void *); +void session_destroy_all(void (*)(Session *)); +void session_pty_cleanup2(Session *); + +Session *session_new(void); +Session *session_by_tty(char *); +void session_close(Session *); +void do_setusercontext(struct passwd *); +void child_set_env(char ***envp, u_int *envsizep, const char *name, + const char *value); + +#endif diff --git a/crypto/openssh-3.9p1/sftp-client.c b/crypto/openssh-3.9p1/sftp-client.c new file mode 100644 index 0000000000..0ffacbccc8 --- /dev/null +++ b/crypto/openssh-3.9p1/sftp-client.c @@ -0,0 +1,1156 @@ +/* + * Copyright (c) 2001-2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* XXX: memleaks */ +/* XXX: signed vs unsigned */ +/* XXX: remove all logging, only return status codes */ +/* XXX: copy between two remote sites */ + +#include "includes.h" +RCSID("$OpenBSD: sftp-client.c,v 1.51 2004/07/11 17:48:47 deraadt Exp $"); + +#include "openbsd-compat/sys-queue.h" + +#include "buffer.h" +#include "bufaux.h" +#include "getput.h" +#include "xmalloc.h" +#include "log.h" +#include "atomicio.h" +#include "progressmeter.h" + +#include "sftp.h" +#include "sftp-common.h" +#include "sftp-client.h" + +extern volatile sig_atomic_t interrupted; +extern int showprogress; + +/* Minimum amount of data to read at at time */ +#define MIN_READ_SIZE 512 + +/* Maximum packet size */ +#define MAX_MSG_LENGTH (256 * 1024) + +struct sftp_conn { + int fd_in; + int fd_out; + u_int transfer_buflen; + u_int num_requests; + u_int version; + u_int msg_id; +}; + +static void +send_msg(int fd, Buffer *m) +{ + u_char mlen[4]; + + if (buffer_len(m) > MAX_MSG_LENGTH) + fatal("Outbound message too long %u", buffer_len(m)); + + /* Send length first */ + PUT_32BIT(mlen, buffer_len(m)); + if (atomicio(vwrite, fd, mlen, sizeof(mlen)) <= 0) + fatal("Couldn't send packet: %s", strerror(errno)); + + if (atomicio(vwrite, fd, buffer_ptr(m), buffer_len(m)) <= 0) + fatal("Couldn't send packet: %s", strerror(errno)); + + buffer_clear(m); +} + +static void +get_msg(int fd, Buffer *m) +{ + ssize_t len; + u_int msg_len; + + buffer_append_space(m, 4); + len = atomicio(read, fd, buffer_ptr(m), 4); + if (len == 0) + fatal("Connection closed"); + else if (len == -1) + fatal("Couldn't read packet: %s", strerror(errno)); + + msg_len = buffer_get_int(m); + if (msg_len > MAX_MSG_LENGTH) + fatal("Received message too long %u", msg_len); + + buffer_append_space(m, msg_len); + len = atomicio(read, fd, buffer_ptr(m), msg_len); + if (len == 0) + fatal("Connection closed"); + else if (len == -1) + fatal("Read packet: %s", strerror(errno)); +} + +static void +send_string_request(int fd, u_int id, u_int code, char *s, + u_int len) +{ + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, code); + buffer_put_int(&msg, id); + buffer_put_string(&msg, s, len); + send_msg(fd, &msg); + debug3("Sent message fd %d T:%u I:%u", fd, code, id); + buffer_free(&msg); +} + +static void +send_string_attrs_request(int fd, u_int id, u_int code, char *s, + u_int len, Attrib *a) +{ + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, code); + buffer_put_int(&msg, id); + buffer_put_string(&msg, s, len); + encode_attrib(&msg, a); + send_msg(fd, &msg); + debug3("Sent message fd %d T:%u I:%u", fd, code, id); + buffer_free(&msg); +} + +static u_int +get_status(int fd, u_int expected_id) +{ + Buffer msg; + u_int type, id, status; + + buffer_init(&msg); + get_msg(fd, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + if (id != expected_id) + fatal("ID mismatch (%u != %u)", id, expected_id); + if (type != SSH2_FXP_STATUS) + fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", + SSH2_FXP_STATUS, type); + + status = buffer_get_int(&msg); + buffer_free(&msg); + + debug3("SSH2_FXP_STATUS %u", status); + + return(status); +} + +static char * +get_handle(int fd, u_int expected_id, u_int *len) +{ + Buffer msg; + u_int type, id; + char *handle; + + buffer_init(&msg); + get_msg(fd, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + if (id != expected_id) + fatal("ID mismatch (%u != %u)", id, expected_id); + if (type == SSH2_FXP_STATUS) { + int status = buffer_get_int(&msg); + + error("Couldn't get handle: %s", fx2txt(status)); + return(NULL); + } else if (type != SSH2_FXP_HANDLE) + fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u", + SSH2_FXP_HANDLE, type); + + handle = buffer_get_string(&msg, len); + buffer_free(&msg); + + return(handle); +} + +static Attrib * +get_decode_stat(int fd, u_int expected_id, int quiet) +{ + Buffer msg; + u_int type, id; + Attrib *a; + + buffer_init(&msg); + get_msg(fd, &msg); + + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + debug3("Received stat reply T:%u I:%u", type, id); + if (id != expected_id) + fatal("ID mismatch (%u != %u)", id, expected_id); + if (type == SSH2_FXP_STATUS) { + int status = buffer_get_int(&msg); + + if (quiet) + debug("Couldn't stat remote file: %s", fx2txt(status)); + else + error("Couldn't stat remote file: %s", fx2txt(status)); + return(NULL); + } else if (type != SSH2_FXP_ATTRS) { + fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", + SSH2_FXP_ATTRS, type); + } + a = decode_attrib(&msg); + buffer_free(&msg); + + return(a); +} + +struct sftp_conn * +do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) +{ + u_int type; + int version; + Buffer msg; + struct sftp_conn *ret; + + buffer_init(&msg); + buffer_put_char(&msg, SSH2_FXP_INIT); + buffer_put_int(&msg, SSH2_FILEXFER_VERSION); + send_msg(fd_out, &msg); + + buffer_clear(&msg); + + get_msg(fd_in, &msg); + + /* Expecting a VERSION reply */ + if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { + error("Invalid packet back from SSH2_FXP_INIT (type %u)", + type); + buffer_free(&msg); + return(NULL); + } + version = buffer_get_int(&msg); + + debug2("Remote version: %d", version); + + /* Check for extensions */ + while (buffer_len(&msg) > 0) { + char *name = buffer_get_string(&msg, NULL); + char *value = buffer_get_string(&msg, NULL); + + debug2("Init extension: \"%s\"", name); + xfree(name); + xfree(value); + } + + buffer_free(&msg); + + ret = xmalloc(sizeof(*ret)); + ret->fd_in = fd_in; + ret->fd_out = fd_out; + ret->transfer_buflen = transfer_buflen; + ret->num_requests = num_requests; + ret->version = version; + ret->msg_id = 1; + + /* Some filexfer v.0 servers don't support large packets */ + if (version == 0) + ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); + + return(ret); +} + +u_int +sftp_proto_version(struct sftp_conn *conn) +{ + return(conn->version); +} + +int +do_close(struct sftp_conn *conn, char *handle, u_int handle_len) +{ + u_int id, status; + Buffer msg; + + buffer_init(&msg); + + id = conn->msg_id++; + buffer_put_char(&msg, SSH2_FXP_CLOSE); + buffer_put_int(&msg, id); + buffer_put_string(&msg, handle, handle_len); + send_msg(conn->fd_out, &msg); + debug3("Sent message SSH2_FXP_CLOSE I:%u", id); + + status = get_status(conn->fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't close file: %s", fx2txt(status)); + + buffer_free(&msg); + + return(status); +} + + +static int +do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, + SFTP_DIRENT ***dir) +{ + Buffer msg; + u_int type, id, handle_len, i, expected_id, ents = 0; + char *handle; + + id = conn->msg_id++; + + buffer_init(&msg); + buffer_put_char(&msg, SSH2_FXP_OPENDIR); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, path); + send_msg(conn->fd_out, &msg); + + buffer_clear(&msg); + + handle = get_handle(conn->fd_in, id, &handle_len); + if (handle == NULL) + return(-1); + + if (dir) { + ents = 0; + *dir = xmalloc(sizeof(**dir)); + (*dir)[0] = NULL; + } + + for (; !interrupted;) { + int count; + + id = expected_id = conn->msg_id++; + + debug3("Sending SSH2_FXP_READDIR I:%u", id); + + buffer_clear(&msg); + buffer_put_char(&msg, SSH2_FXP_READDIR); + buffer_put_int(&msg, id); + buffer_put_string(&msg, handle, handle_len); + send_msg(conn->fd_out, &msg); + + buffer_clear(&msg); + + get_msg(conn->fd_in, &msg); + + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + debug3("Received reply T:%u I:%u", type, id); + + if (id != expected_id) + fatal("ID mismatch (%u != %u)", id, expected_id); + + if (type == SSH2_FXP_STATUS) { + int status = buffer_get_int(&msg); + + debug3("Received SSH2_FXP_STATUS %d", status); + + if (status == SSH2_FX_EOF) { + break; + } else { + error("Couldn't read directory: %s", + fx2txt(status)); + do_close(conn, handle, handle_len); + xfree(handle); + return(status); + } + } else if (type != SSH2_FXP_NAME) + fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", + SSH2_FXP_NAME, type); + + count = buffer_get_int(&msg); + if (count == 0) + break; + debug3("Received %d SSH2_FXP_NAME responses", count); + for (i = 0; i < count; i++) { + char *filename, *longname; + Attrib *a; + + filename = buffer_get_string(&msg, NULL); + longname = buffer_get_string(&msg, NULL); + a = decode_attrib(&msg); + + if (printflag) + printf("%s\n", longname); + + if (dir) { + *dir = xrealloc(*dir, sizeof(**dir) * + (ents + 2)); + (*dir)[ents] = xmalloc(sizeof(***dir)); + (*dir)[ents]->filename = xstrdup(filename); + (*dir)[ents]->longname = xstrdup(longname); + memcpy(&(*dir)[ents]->a, a, sizeof(*a)); + (*dir)[++ents] = NULL; + } + + xfree(filename); + xfree(longname); + } + } + + buffer_free(&msg); + do_close(conn, handle, handle_len); + xfree(handle); + + /* Don't return partial matches on interrupt */ + if (interrupted && dir != NULL && *dir != NULL) { + free_sftp_dirents(*dir); + *dir = xmalloc(sizeof(**dir)); + **dir = NULL; + } + + return(0); +} + +int +do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) +{ + return(do_lsreaddir(conn, path, 0, dir)); +} + +void free_sftp_dirents(SFTP_DIRENT **s) +{ + int i; + + for (i = 0; s[i]; i++) { + xfree(s[i]->filename); + xfree(s[i]->longname); + xfree(s[i]); + } + xfree(s); +} + +int +do_rm(struct sftp_conn *conn, char *path) +{ + u_int status, id; + + debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); + + id = conn->msg_id++; + send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path, + strlen(path)); + status = get_status(conn->fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't delete file: %s", fx2txt(status)); + return(status); +} + +int +do_mkdir(struct sftp_conn *conn, char *path, Attrib *a) +{ + u_int status, id; + + id = conn->msg_id++; + send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path, + strlen(path), a); + + status = get_status(conn->fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't create directory: %s", fx2txt(status)); + + return(status); +} + +int +do_rmdir(struct sftp_conn *conn, char *path) +{ + u_int status, id; + + id = conn->msg_id++; + send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path, + strlen(path)); + + status = get_status(conn->fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't remove directory: %s", fx2txt(status)); + + return(status); +} + +Attrib * +do_stat(struct sftp_conn *conn, char *path, int quiet) +{ + u_int id; + + id = conn->msg_id++; + + send_string_request(conn->fd_out, id, + conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, + path, strlen(path)); + + return(get_decode_stat(conn->fd_in, id, quiet)); +} + +Attrib * +do_lstat(struct sftp_conn *conn, char *path, int quiet) +{ + u_int id; + + if (conn->version == 0) { + if (quiet) + debug("Server version does not support lstat operation"); + else + logit("Server version does not support lstat operation"); + return(do_stat(conn, path, quiet)); + } + + id = conn->msg_id++; + send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path, + strlen(path)); + + return(get_decode_stat(conn->fd_in, id, quiet)); +} + +Attrib * +do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) +{ + u_int id; + + id = conn->msg_id++; + send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle, + handle_len); + + return(get_decode_stat(conn->fd_in, id, quiet)); +} + +int +do_setstat(struct sftp_conn *conn, char *path, Attrib *a) +{ + u_int status, id; + + id = conn->msg_id++; + send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path, + strlen(path), a); + + status = get_status(conn->fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't setstat on \"%s\": %s", path, + fx2txt(status)); + + return(status); +} + +int +do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, + Attrib *a) +{ + u_int status, id; + + id = conn->msg_id++; + send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle, + handle_len, a); + + status = get_status(conn->fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't fsetstat: %s", fx2txt(status)); + + return(status); +} + +char * +do_realpath(struct sftp_conn *conn, char *path) +{ + Buffer msg; + u_int type, expected_id, count, id; + char *filename, *longname; + Attrib *a; + + expected_id = id = conn->msg_id++; + send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path, + strlen(path)); + + buffer_init(&msg); + + get_msg(conn->fd_in, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + if (id != expected_id) + fatal("ID mismatch (%u != %u)", id, expected_id); + + if (type == SSH2_FXP_STATUS) { + u_int status = buffer_get_int(&msg); + + error("Couldn't canonicalise: %s", fx2txt(status)); + return(NULL); + } else if (type != SSH2_FXP_NAME) + fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", + SSH2_FXP_NAME, type); + + count = buffer_get_int(&msg); + if (count != 1) + fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); + + filename = buffer_get_string(&msg, NULL); + longname = buffer_get_string(&msg, NULL); + a = decode_attrib(&msg); + + debug3("SSH_FXP_REALPATH %s -> %s", path, filename); + + xfree(longname); + + buffer_free(&msg); + + return(filename); +} + +int +do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) +{ + Buffer msg; + u_int status, id; + + buffer_init(&msg); + + /* Send rename request */ + id = conn->msg_id++; + buffer_put_char(&msg, SSH2_FXP_RENAME); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, oldpath); + buffer_put_cstring(&msg, newpath); + send_msg(conn->fd_out, &msg); + debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath, + newpath); + buffer_free(&msg); + + status = get_status(conn->fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, + newpath, fx2txt(status)); + + return(status); +} + +int +do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) +{ + Buffer msg; + u_int status, id; + + if (conn->version < 3) { + error("This server does not support the symlink operation"); + return(SSH2_FX_OP_UNSUPPORTED); + } + + buffer_init(&msg); + + /* Send symlink request */ + id = conn->msg_id++; + buffer_put_char(&msg, SSH2_FXP_SYMLINK); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, oldpath); + buffer_put_cstring(&msg, newpath); + send_msg(conn->fd_out, &msg); + debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, + newpath); + buffer_free(&msg); + + status = get_status(conn->fd_in, id); + if (status != SSH2_FX_OK) + error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, + newpath, fx2txt(status)); + + return(status); +} + +char * +do_readlink(struct sftp_conn *conn, char *path) +{ + Buffer msg; + u_int type, expected_id, count, id; + char *filename, *longname; + Attrib *a; + + expected_id = id = conn->msg_id++; + send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path, + strlen(path)); + + buffer_init(&msg); + + get_msg(conn->fd_in, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + + if (id != expected_id) + fatal("ID mismatch (%u != %u)", id, expected_id); + + if (type == SSH2_FXP_STATUS) { + u_int status = buffer_get_int(&msg); + + error("Couldn't readlink: %s", fx2txt(status)); + return(NULL); + } else if (type != SSH2_FXP_NAME) + fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", + SSH2_FXP_NAME, type); + + count = buffer_get_int(&msg); + if (count != 1) + fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); + + filename = buffer_get_string(&msg, NULL); + longname = buffer_get_string(&msg, NULL); + a = decode_attrib(&msg); + + debug3("SSH_FXP_READLINK %s -> %s", path, filename); + + xfree(longname); + + buffer_free(&msg); + + return(filename); +} + +static void +send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, + char *handle, u_int handle_len) +{ + Buffer msg; + + buffer_init(&msg); + buffer_clear(&msg); + buffer_put_char(&msg, SSH2_FXP_READ); + buffer_put_int(&msg, id); + buffer_put_string(&msg, handle, handle_len); + buffer_put_int64(&msg, offset); + buffer_put_int(&msg, len); + send_msg(fd_out, &msg); + buffer_free(&msg); +} + +int +do_download(struct sftp_conn *conn, char *remote_path, char *local_path, + int pflag) +{ + Attrib junk, *a; + Buffer msg; + char *handle; + int local_fd, status, num_req, max_req, write_error; + int read_error, write_errno; + u_int64_t offset, size; + u_int handle_len, mode, type, id, buflen; + off_t progress_counter; + struct request { + u_int id; + u_int len; + u_int64_t offset; + TAILQ_ENTRY(request) tq; + }; + TAILQ_HEAD(reqhead, request) requests; + struct request *req; + + TAILQ_INIT(&requests); + + a = do_stat(conn, remote_path, 0); + if (a == NULL) + return(-1); + + /* XXX: should we preserve set[ug]id? */ + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) + mode = a->perm & 0777; + else + mode = 0666; + + if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && + (!S_ISREG(a->perm))) { + error("Cannot download non-regular file: %s", remote_path); + return(-1); + } + + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) + size = a->size; + else + size = 0; + + buflen = conn->transfer_buflen; + buffer_init(&msg); + + /* Send open request */ + id = conn->msg_id++; + buffer_put_char(&msg, SSH2_FXP_OPEN); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, remote_path); + buffer_put_int(&msg, SSH2_FXF_READ); + attrib_clear(&junk); /* Send empty attributes */ + encode_attrib(&msg, &junk); + send_msg(conn->fd_out, &msg); + debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); + + handle = get_handle(conn->fd_in, id, &handle_len); + if (handle == NULL) { + buffer_free(&msg); + return(-1); + } + + local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, + mode | S_IWRITE); + if (local_fd == -1) { + error("Couldn't open local file \"%s\" for writing: %s", + local_path, strerror(errno)); + buffer_free(&msg); + xfree(handle); + return(-1); + } + + /* Read from remote and write to local */ + write_error = read_error = write_errno = num_req = offset = 0; + max_req = 1; + progress_counter = 0; + + if (showprogress && size != 0) + start_progress_meter(remote_path, size, &progress_counter); + + while (num_req > 0 || max_req > 0) { + char *data; + u_int len; + + /* + * Simulate EOF on interrupt: stop sending new requests and + * allow outstanding requests to drain gracefully + */ + if (interrupted) { + if (num_req == 0) /* If we haven't started yet... */ + break; + max_req = 0; + } + + /* Send some more requests */ + while (num_req < max_req) { + debug3("Request range %llu -> %llu (%d/%d)", + (unsigned long long)offset, + (unsigned long long)offset + buflen - 1, + num_req, max_req); + req = xmalloc(sizeof(*req)); + req->id = conn->msg_id++; + req->len = buflen; + req->offset = offset; + offset += buflen; + num_req++; + TAILQ_INSERT_TAIL(&requests, req, tq); + send_read_request(conn->fd_out, req->id, req->offset, + req->len, handle, handle_len); + } + + buffer_clear(&msg); + get_msg(conn->fd_in, &msg); + type = buffer_get_char(&msg); + id = buffer_get_int(&msg); + debug3("Received reply T:%u I:%u R:%d", type, id, max_req); + + /* Find the request in our queue */ + for(req = TAILQ_FIRST(&requests); + req != NULL && req->id != id; + req = TAILQ_NEXT(req, tq)) + ; + if (req == NULL) + fatal("Unexpected reply %u", id); + + switch (type) { + case SSH2_FXP_STATUS: + status = buffer_get_int(&msg); + if (status != SSH2_FX_EOF) + read_error = 1; + max_req = 0; + TAILQ_REMOVE(&requests, req, tq); + xfree(req); + num_req--; + break; + case SSH2_FXP_DATA: + data = buffer_get_string(&msg, &len); + debug3("Received data %llu -> %llu", + (unsigned long long)req->offset, + (unsigned long long)req->offset + len - 1); + if (len > req->len) + fatal("Received more data than asked for " + "%u > %u", len, req->len); + if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || + atomicio(vwrite, local_fd, data, len) != len) && + !write_error) { + write_errno = errno; + write_error = 1; + max_req = 0; + } + progress_counter += len; + xfree(data); + + if (len == req->len) { + TAILQ_REMOVE(&requests, req, tq); + xfree(req); + num_req--; + } else { + /* Resend the request for the missing data */ + debug3("Short data block, re-requesting " + "%llu -> %llu (%2d)", + (unsigned long long)req->offset + len, + (unsigned long long)req->offset + + req->len - 1, num_req); + req->id = conn->msg_id++; + req->len -= len; + req->offset += len; + send_read_request(conn->fd_out, req->id, + req->offset, req->len, handle, handle_len); + /* Reduce the request size */ + if (len < buflen) + buflen = MAX(MIN_READ_SIZE, len); + } + if (max_req > 0) { /* max_req = 0 iff EOF received */ + if (size > 0 && offset > size) { + /* Only one request at a time + * after the expected EOF */ + debug3("Finish at %llu (%2d)", + (unsigned long long)offset, + num_req); + max_req = 1; + } else if (max_req <= conn->num_requests) { + ++max_req; + } + } + break; + default: + fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", + SSH2_FXP_DATA, type); + } + } + + if (showprogress && size) + stop_progress_meter(); + + /* Sanity check */ + if (TAILQ_FIRST(&requests) != NULL) + fatal("Transfer complete, but requests still in queue"); + + if (read_error) { + error("Couldn't read from remote file \"%s\" : %s", + remote_path, fx2txt(status)); + do_close(conn, handle, handle_len); + } else if (write_error) { + error("Couldn't write to \"%s\": %s", local_path, + strerror(write_errno)); + status = -1; + do_close(conn, handle, handle_len); + } else { + status = do_close(conn, handle, handle_len); + + /* Override umask and utimes if asked */ +#ifdef HAVE_FCHMOD + if (pflag && fchmod(local_fd, mode) == -1) +#else + if (pflag && chmod(local_path, mode) == -1) +#endif /* HAVE_FCHMOD */ + error("Couldn't set mode on \"%s\": %s", local_path, + strerror(errno)); + if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { + struct timeval tv[2]; + tv[0].tv_sec = a->atime; + tv[1].tv_sec = a->mtime; + tv[0].tv_usec = tv[1].tv_usec = 0; + if (utimes(local_path, tv) == -1) + error("Can't set times on \"%s\": %s", + local_path, strerror(errno)); + } + } + close(local_fd); + buffer_free(&msg); + xfree(handle); + + return(status); +} + +int +do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, + int pflag) +{ + int local_fd, status; + u_int handle_len, id, type; + u_int64_t offset; + char *handle, *data; + Buffer msg; + struct stat sb; + Attrib a; + u_int32_t startid; + u_int32_t ackid; + struct outstanding_ack { + u_int id; + u_int len; + u_int64_t offset; + TAILQ_ENTRY(outstanding_ack) tq; + }; + TAILQ_HEAD(ackhead, outstanding_ack) acks; + struct outstanding_ack *ack = NULL; + + TAILQ_INIT(&acks); + + if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { + error("Couldn't open local file \"%s\" for reading: %s", + local_path, strerror(errno)); + return(-1); + } + if (fstat(local_fd, &sb) == -1) { + error("Couldn't fstat local file \"%s\": %s", + local_path, strerror(errno)); + close(local_fd); + return(-1); + } + if (!S_ISREG(sb.st_mode)) { + error("%s is not a regular file", local_path); + close(local_fd); + return(-1); + } + stat_to_attrib(&sb, &a); + + a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; + a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; + a.perm &= 0777; + if (!pflag) + a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; + + buffer_init(&msg); + + /* Send open request */ + id = conn->msg_id++; + buffer_put_char(&msg, SSH2_FXP_OPEN); + buffer_put_int(&msg, id); + buffer_put_cstring(&msg, remote_path); + buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); + encode_attrib(&msg, &a); + send_msg(conn->fd_out, &msg); + debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); + + buffer_clear(&msg); + + handle = get_handle(conn->fd_in, id, &handle_len); + if (handle == NULL) { + close(local_fd); + buffer_free(&msg); + return(-1); + } + + startid = ackid = id + 1; + data = xmalloc(conn->transfer_buflen); + + /* Read from local and write to remote */ + offset = 0; + if (showprogress) + start_progress_meter(local_path, sb.st_size, &offset); + + for (;;) { + int len; + + /* + * Can't use atomicio here because it returns 0 on EOF, + * thus losing the last block of the file. + * Simulate an EOF on interrupt, allowing ACKs from the + * server to drain. + */ + if (interrupted) + len = 0; + else do + len = read(local_fd, data, conn->transfer_buflen); + while ((len == -1) && (errno == EINTR || errno == EAGAIN)); + + if (len == -1) + fatal("Couldn't read from \"%s\": %s", local_path, + strerror(errno)); + + if (len != 0) { + ack = xmalloc(sizeof(*ack)); + ack->id = ++id; + ack->offset = offset; + ack->len = len; + TAILQ_INSERT_TAIL(&acks, ack, tq); + + buffer_clear(&msg); + buffer_put_char(&msg, SSH2_FXP_WRITE); + buffer_put_int(&msg, ack->id); + buffer_put_string(&msg, handle, handle_len); + buffer_put_int64(&msg, offset); + buffer_put_string(&msg, data, len); + send_msg(conn->fd_out, &msg); + debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", + id, (unsigned long long)offset, len); + } else if (TAILQ_FIRST(&acks) == NULL) + break; + + if (ack == NULL) + fatal("Unexpected ACK %u", id); + + if (id == startid || len == 0 || + id - ackid >= conn->num_requests) { + u_int r_id; + + buffer_clear(&msg); + get_msg(conn->fd_in, &msg); + type = buffer_get_char(&msg); + r_id = buffer_get_int(&msg); + + if (type != SSH2_FXP_STATUS) + fatal("Expected SSH2_FXP_STATUS(%d) packet, " + "got %d", SSH2_FXP_STATUS, type); + + status = buffer_get_int(&msg); + debug3("SSH2_FXP_STATUS %d", status); + + /* Find the request in our queue */ + for(ack = TAILQ_FIRST(&acks); + ack != NULL && ack->id != r_id; + ack = TAILQ_NEXT(ack, tq)) + ; + if (ack == NULL) + fatal("Can't find request for ID %u", r_id); + TAILQ_REMOVE(&acks, ack, tq); + + if (status != SSH2_FX_OK) { + error("Couldn't write to remote file \"%s\": %s", + remote_path, fx2txt(status)); + do_close(conn, handle, handle_len); + close(local_fd); + xfree(data); + xfree(ack); + goto done; + } + debug3("In write loop, ack for %u %u bytes at %llu", + ack->id, ack->len, (unsigned long long)ack->offset); + ++ackid; + xfree(ack); + } + offset += len; + } + if (showprogress) + stop_progress_meter(); + xfree(data); + + if (close(local_fd) == -1) { + error("Couldn't close local file \"%s\": %s", local_path, + strerror(errno)); + do_close(conn, handle, handle_len); + status = -1; + goto done; + } + + /* Override umask and utimes if asked */ + if (pflag) + do_fsetstat(conn, handle, handle_len, &a); + + status = do_close(conn, handle, handle_len); + +done: + xfree(handle); + buffer_free(&msg); + return(status); +} diff --git a/crypto/openssh-3.9p1/sftp-client.h b/crypto/openssh-3.9p1/sftp-client.h new file mode 100644 index 0000000000..a0e8e44b3c --- /dev/null +++ b/crypto/openssh-3.9p1/sftp-client.h @@ -0,0 +1,99 @@ +/* $OpenBSD: sftp-client.h,v 1.12 2004/02/17 05:39:51 djm Exp $ */ + +/* + * Copyright (c) 2001-2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Client side of SSH2 filexfer protocol */ + +#ifndef _SFTP_CLIENT_H +#define _SFTP_CLIENT_H + +typedef struct SFTP_DIRENT SFTP_DIRENT; + +struct SFTP_DIRENT { + char *filename; + char *longname; + Attrib a; +}; + +/* + * Initialiase a SSH filexfer connection. Returns -1 on error or + * protocol version on success. + */ +struct sftp_conn *do_init(int, int, u_int, u_int); + +u_int sftp_proto_version(struct sftp_conn *); + +/* Close file referred to by 'handle' */ +int do_close(struct sftp_conn *, char *, u_int); + +/* Read contents of 'path' to NULL-terminated array 'dir' */ +int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***); + +/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */ +void free_sftp_dirents(SFTP_DIRENT **); + +/* Delete file 'path' */ +int do_rm(struct sftp_conn *, char *); + +/* Create directory 'path' */ +int do_mkdir(struct sftp_conn *, char *, Attrib *); + +/* Remove directory 'path' */ +int do_rmdir(struct sftp_conn *, char *); + +/* Get file attributes of 'path' (follows symlinks) */ +Attrib *do_stat(struct sftp_conn *, char *, int); + +/* Get file attributes of 'path' (does not follow symlinks) */ +Attrib *do_lstat(struct sftp_conn *, char *, int); + +/* Get file attributes of open file 'handle' */ +Attrib *do_fstat(struct sftp_conn *, char *, u_int, int); + +/* Set file attributes of 'path' */ +int do_setstat(struct sftp_conn *, char *, Attrib *); + +/* Set file attributes of open file 'handle' */ +int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *); + +/* Canonicalise 'path' - caller must free result */ +char *do_realpath(struct sftp_conn *, char *); + +/* Rename 'oldpath' to 'newpath' */ +int do_rename(struct sftp_conn *, char *, char *); + +/* Rename 'oldpath' to 'newpath' */ +int do_symlink(struct sftp_conn *, char *, char *); + +/* Return target of symlink 'path' - caller must free result */ +char *do_readlink(struct sftp_conn *, char *); + +/* XXX: add callbacks to do_download/do_upload so we can do progress meter */ + +/* + * Download 'remote_path' to 'local_path'. Preserve permissions and times + * if 'pflag' is set + */ +int do_download(struct sftp_conn *, char *, char *, int); + +/* + * Upload 'local_path' to 'remote_path'. Preserve permissions and times + * if 'pflag' is set + */ +int do_upload(struct sftp_conn *, char *, char *, int); + +#endif diff --git a/crypto/openssh-3.9p1/sftp-common.c b/crypto/openssh-3.9p1/sftp-common.c new file mode 100644 index 0000000000..4cea3c3056 --- /dev/null +++ b/crypto/openssh-3.9p1/sftp-common.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: sftp-common.c,v 1.10 2003/11/10 16:23:41 jakob Exp $"); + +#include "buffer.h" +#include "bufaux.h" +#include "log.h" +#include "xmalloc.h" + +#include "sftp.h" +#include "sftp-common.h" + +/* Clear contents of attributes structure */ +void +attrib_clear(Attrib *a) +{ + a->flags = 0; + a->size = 0; + a->uid = 0; + a->gid = 0; + a->perm = 0; + a->atime = 0; + a->mtime = 0; +} + +/* Convert from struct stat to filexfer attribs */ +void +stat_to_attrib(const struct stat *st, Attrib *a) +{ + attrib_clear(a); + a->flags = 0; + a->flags |= SSH2_FILEXFER_ATTR_SIZE; + a->size = st->st_size; + a->flags |= SSH2_FILEXFER_ATTR_UIDGID; + a->uid = st->st_uid; + a->gid = st->st_gid; + a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + a->perm = st->st_mode; + a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME; + a->atime = st->st_atime; + a->mtime = st->st_mtime; +} + +/* Convert from filexfer attribs to struct stat */ +void +attrib_to_stat(const Attrib *a, struct stat *st) +{ + memset(st, 0, sizeof(*st)); + + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) + st->st_size = a->size; + if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + st->st_uid = a->uid; + st->st_gid = a->gid; + } + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) + st->st_mode = a->perm; + if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + st->st_atime = a->atime; + st->st_mtime = a->mtime; + } +} + +/* Decode attributes in buffer */ +Attrib * +decode_attrib(Buffer *b) +{ + static Attrib a; + + attrib_clear(&a); + a.flags = buffer_get_int(b); + if (a.flags & SSH2_FILEXFER_ATTR_SIZE) + a.size = buffer_get_int64(b); + if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { + a.uid = buffer_get_int(b); + a.gid = buffer_get_int(b); + } + if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) + a.perm = buffer_get_int(b); + if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + a.atime = buffer_get_int(b); + a.mtime = buffer_get_int(b); + } + /* vendor-specific extensions */ + if (a.flags & SSH2_FILEXFER_ATTR_EXTENDED) { + char *type, *data; + int i, count; + + count = buffer_get_int(b); + for (i = 0; i < count; i++) { + type = buffer_get_string(b, NULL); + data = buffer_get_string(b, NULL); + debug3("Got file attribute \"%s\"", type); + xfree(type); + xfree(data); + } + } + return &a; +} + +/* Encode attributes to buffer */ +void +encode_attrib(Buffer *b, const Attrib *a) +{ + buffer_put_int(b, a->flags); + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) + buffer_put_int64(b, a->size); + if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + buffer_put_int(b, a->uid); + buffer_put_int(b, a->gid); + } + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) + buffer_put_int(b, a->perm); + if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + buffer_put_int(b, a->atime); + buffer_put_int(b, a->mtime); + } +} + +/* Convert from SSH2_FX_ status to text error message */ +const char * +fx2txt(int status) +{ + switch (status) { + case SSH2_FX_OK: + return("No error"); + case SSH2_FX_EOF: + return("End of file"); + case SSH2_FX_NO_SUCH_FILE: + return("No such file or directory"); + case SSH2_FX_PERMISSION_DENIED: + return("Permission denied"); + case SSH2_FX_FAILURE: + return("Failure"); + case SSH2_FX_BAD_MESSAGE: + return("Bad message"); + case SSH2_FX_NO_CONNECTION: + return("No connection"); + case SSH2_FX_CONNECTION_LOST: + return("Connection lost"); + case SSH2_FX_OP_UNSUPPORTED: + return("Operation unsupported"); + default: + return("Unknown status"); + } + /* NOTREACHED */ +} + +/* + * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh + */ +char * +ls_file(const char *name, const struct stat *st, int remote) +{ + int ulen, glen, sz = 0; + struct passwd *pw; + struct group *gr; + struct tm *ltime = localtime(&st->st_mtime); + char *user, *group; + char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; + + strmode(st->st_mode, mode); + if (!remote && (pw = getpwuid(st->st_uid)) != NULL) { + user = pw->pw_name; + } else { + snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid); + user = ubuf; + } + if (!remote && (gr = getgrgid(st->st_gid)) != NULL) { + group = gr->gr_name; + } else { + snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid); + group = gbuf; + } + if (ltime != NULL) { + if (time(NULL) - st->st_mtime < (365*24*60*60)/2) + sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime); + else + sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime); + } + if (sz == 0) + tbuf[0] = '\0'; + ulen = MAX(strlen(user), 8); + glen = MAX(strlen(group), 8); + snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode, + (u_int)st->st_nlink, ulen, user, glen, group, + (unsigned long long)st->st_size, tbuf, name); + return xstrdup(buf); +} diff --git a/crypto/openssh-3.9p1/sftp-common.h b/crypto/openssh-3.9p1/sftp-common.h new file mode 100644 index 0000000000..b42ba91409 --- /dev/null +++ b/crypto/openssh-3.9p1/sftp-common.h @@ -0,0 +1,48 @@ +/* $OpenBSD: sftp-common.h,v 1.5 2003/11/10 16:23:41 jakob Exp $ */ + +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Damien Miller. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +typedef struct Attrib Attrib; + +/* File attributes */ +struct Attrib { + u_int32_t flags; + u_int64_t size; + u_int32_t uid; + u_int32_t gid; + u_int32_t perm; + u_int32_t atime; + u_int32_t mtime; +}; + +void attrib_clear(Attrib *); +void stat_to_attrib(const struct stat *, Attrib *); +void attrib_to_stat(const Attrib *, struct stat *); +Attrib *decode_attrib(Buffer *); +void encode_attrib(Buffer *, const Attrib *); +char *ls_file(const char *, const struct stat *, int); + +const char *fx2txt(int); diff --git a/crypto/openssh-3.9p1/sftp-glob.c b/crypto/openssh-3.9p1/sftp-glob.c new file mode 100644 index 0000000000..16c5e206aa --- /dev/null +++ b/crypto/openssh-3.9p1/sftp-glob.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2001-2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" +RCSID("$OpenBSD: sftp-glob.c,v 1.15 2004/02/17 07:17:29 djm Exp $"); + +#include "buffer.h" +#include "bufaux.h" +#include "xmalloc.h" +#include "log.h" + +#include "sftp.h" +#include "sftp-common.h" +#include "sftp-client.h" + +int remote_glob(struct sftp_conn *, const char *, int, + int (*)(const char *, int), glob_t *); + +struct SFTP_OPENDIR { + SFTP_DIRENT **dir; + int offset; +}; + +static struct { + struct sftp_conn *conn; +} cur; + +static void * +fudge_opendir(const char *path) +{ + struct SFTP_OPENDIR *r; + + r = xmalloc(sizeof(*r)); + + if (do_readdir(cur.conn, (char *)path, &r->dir)) { + xfree(r); + return(NULL); + } + + r->offset = 0; + + return((void *)r); +} + +static struct dirent * +fudge_readdir(struct SFTP_OPENDIR *od) +{ + /* Solaris needs sizeof(dirent) + path length (see below) */ + static char buf[sizeof(struct dirent) + MAXPATHLEN]; + struct dirent *ret = (struct dirent *)buf; +#ifdef __GNU_LIBRARY__ + static int inum = 1; +#endif /* __GNU_LIBRARY__ */ + + if (od->dir[od->offset] == NULL) + return(NULL); + + memset(buf, 0, sizeof(buf)); + + /* + * Solaris defines dirent->d_name as a one byte array and expects + * you to hack around it. + */ +#ifdef BROKEN_ONE_BYTE_DIRENT_D_NAME + strlcpy(ret->d_name, od->dir[od->offset++]->filename, MAXPATHLEN); +#else + strlcpy(ret->d_name, od->dir[od->offset++]->filename, + sizeof(ret->d_name)); +#endif +#ifdef __GNU_LIBRARY__ + /* + * Idiot glibc uses extensions to struct dirent for readdir with + * ALTDIRFUNCs. Not that this is documented anywhere but the + * source... Fake an inode number to appease it. + */ + ret->d_ino = inum++; + if (!inum) + inum = 1; +#endif /* __GNU_LIBRARY__ */ + + return(ret); +} + +static void +fudge_closedir(struct SFTP_OPENDIR *od) +{ + free_sftp_dirents(od->dir); + xfree(od); +} + +static int +fudge_lstat(const char *path, struct stat *st) +{ + Attrib *a; + + if (!(a = do_lstat(cur.conn, (char *)path, 0))) + return(-1); + + attrib_to_stat(a, st); + + return(0); +} + +static int +fudge_stat(const char *path, struct stat *st) +{ + Attrib *a; + + if (!(a = do_stat(cur.conn, (char *)path, 0))) + return(-1); + + attrib_to_stat(a, st); + + return(0); +} + +int +remote_glob(struct sftp_conn *conn, const char *pattern, int flags, + int (*errfunc)(const char *, int), glob_t *pglob) +{ + pglob->gl_opendir = fudge_opendir; + pglob->gl_readdir = (struct dirent *(*)(void *))fudge_readdir; + pglob->gl_closedir = (void (*)(void *))fudge_closedir; + pglob->gl_lstat = fudge_lstat; + pglob->gl_stat = fudge_stat; + + memset(&cur, 0, sizeof(cur)); + cur.conn = conn; + + return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob)); +} diff --git a/crypto/openssh-3.9p1/sftp-server.8 b/crypto/openssh-3.9p1/sftp-server.8 new file mode 100644 index 0000000000..42f5d437cd --- /dev/null +++ b/crypto/openssh-3.9p1/sftp-server.8 @@ -0,0 +1,63 @@ +.\" $OpenBSD: sftp-server.8,v 1.10 2003/10/08 08:27:36 jmc Exp $ +.\" +.\" Copyright (c) 2000 Markus Friedl. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd August 30, 2000 +.Dt SFTP-SERVER 8 +.Os +.Sh NAME +.Nm sftp-server +.Nd SFTP server subsystem +.Sh SYNOPSIS +.Nm sftp-server +.Sh DESCRIPTION +.Nm +is a program that speaks the server side of SFTP protocol +to stdout and expects client requests from stdin. +.Nm +is not intended to be called directly, but from +.Xr sshd 8 +using the +.Cm Subsystem +option. +See +.Xr sshd_config 5 +for more information. +.Sh SEE ALSO +.Xr sftp 1 , +.Xr ssh 1 , +.Xr sshd_config 5 , +.Xr sshd 8 +.Rs +.%A T. Ylonen +.%A S. Lehtinen +.%T "SSH File Transfer Protocol" +.%N draft-ietf-secsh-filexfer-00.txt +.%D January 2001 +.%O work in progress material +.Re +.Sh AUTHORS +.An Markus Friedl Aq markus@openbsd.org +.Sh HISTORY +.Nm +first appeared in OpenBSD 2.8 . diff --git a/crypto/openssh-3.9p1/sftp-server.c b/crypto/openssh-3.9p1/sftp-server.c new file mode 100644 index 0000000000..e822800575 --- /dev/null +++ b/crypto/openssh-3.9p1/sftp-server.c @@ -0,0 +1,1111 @@ +/* + * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "includes.h" +RCSID("$OpenBSD: sftp-server.c,v 1.47 2004/06/25 05:38:48 dtucker Exp $"); + +#include "buffer.h" +#include "bufaux.h" +#include "getput.h" +#include "log.h" +#include "xmalloc.h" + +#include "sftp.h" +#include "sftp-common.h" + +/* helper */ +#define get_int64() buffer_get_int64(&iqueue); +#define get_int() buffer_get_int(&iqueue); +#define get_string(lenp) buffer_get_string(&iqueue, lenp); +#define TRACE debug + +extern char *__progname; + +/* input and output queue */ +Buffer iqueue; +Buffer oqueue; + +/* Version of client */ +int version; + +/* portable attributes, etc. */ + +typedef struct Stat Stat; + +struct Stat { + char *name; + char *long_name; + Attrib attrib; +}; + +static int +errno_to_portable(int unixerrno) +{ + int ret = 0; + + switch (unixerrno) { + case 0: + ret = SSH2_FX_OK; + break; + case ENOENT: + case ENOTDIR: + case EBADF: + case ELOOP: + ret = SSH2_FX_NO_SUCH_FILE; + break; + case EPERM: + case EACCES: + case EFAULT: + ret = SSH2_FX_PERMISSION_DENIED; + break; + case ENAMETOOLONG: + case EINVAL: + ret = SSH2_FX_BAD_MESSAGE; + break; + default: + ret = SSH2_FX_FAILURE; + break; + } + return ret; +} + +static int +flags_from_portable(int pflags) +{ + int flags = 0; + + if ((pflags & SSH2_FXF_READ) && + (pflags & SSH2_FXF_WRITE)) { + flags = O_RDWR; + } else if (pflags & SSH2_FXF_READ) { + flags = O_RDONLY; + } else if (pflags & SSH2_FXF_WRITE) { + flags = O_WRONLY; + } + if (pflags & SSH2_FXF_CREAT) + flags |= O_CREAT; + if (pflags & SSH2_FXF_TRUNC) + flags |= O_TRUNC; + if (pflags & SSH2_FXF_EXCL) + flags |= O_EXCL; + return flags; +} + +static Attrib * +get_attrib(void) +{ + return decode_attrib(&iqueue); +} + +/* handle handles */ + +typedef struct Handle Handle; +struct Handle { + int use; + DIR *dirp; + int fd; + char *name; +}; + +enum { + HANDLE_UNUSED, + HANDLE_DIR, + HANDLE_FILE +}; + +Handle handles[100]; + +static void +handle_init(void) +{ + int i; + + for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) + handles[i].use = HANDLE_UNUSED; +} + +static int +handle_new(int use, const char *name, int fd, DIR *dirp) +{ + int i; + + for (i = 0; i < sizeof(handles)/sizeof(Handle); i++) { + if (handles[i].use == HANDLE_UNUSED) { + handles[i].use = use; + handles[i].dirp = dirp; + handles[i].fd = fd; + handles[i].name = xstrdup(name); + return i; + } + } + return -1; +} + +static int +handle_is_ok(int i, int type) +{ + return i >= 0 && i < sizeof(handles)/sizeof(Handle) && + handles[i].use == type; +} + +static int +handle_to_string(int handle, char **stringp, int *hlenp) +{ + if (stringp == NULL || hlenp == NULL) + return -1; + *stringp = xmalloc(sizeof(int32_t)); + PUT_32BIT(*stringp, handle); + *hlenp = sizeof(int32_t); + return 0; +} + +static int +handle_from_string(const char *handle, u_int hlen) +{ + int val; + + if (hlen != sizeof(int32_t)) + return -1; + val = GET_32BIT(handle); + if (handle_is_ok(val, HANDLE_FILE) || + handle_is_ok(val, HANDLE_DIR)) + return val; + return -1; +} + +static char * +handle_to_name(int handle) +{ + if (handle_is_ok(handle, HANDLE_DIR)|| + handle_is_ok(handle, HANDLE_FILE)) + return handles[handle].name; + return NULL; +} + +static DIR * +handle_to_dir(int handle) +{ + if (handle_is_ok(handle, HANDLE_DIR)) + return handles[handle].dirp; + return NULL; +} + +static int +handle_to_fd(int handle) +{ + if (handle_is_ok(handle, HANDLE_FILE)) + return handles[handle].fd; + return -1; +} + +static int +handle_close(int handle) +{ + int ret = -1; + + if (handle_is_ok(handle, HANDLE_FILE)) { + ret = close(handles[handle].fd); + handles[handle].use = HANDLE_UNUSED; + xfree(handles[handle].name); + } else if (handle_is_ok(handle, HANDLE_DIR)) { + ret = closedir(handles[handle].dirp); + handles[handle].use = HANDLE_UNUSED; + xfree(handles[handle].name); + } else { + errno = ENOENT; + } + return ret; +} + +static int +get_handle(void) +{ + char *handle; + int val = -1; + u_int hlen; + + handle = get_string(&hlen); + if (hlen < 256) + val = handle_from_string(handle, hlen); + xfree(handle); + return val; +} + +/* send replies */ + +static void +send_msg(Buffer *m) +{ + int mlen = buffer_len(m); + + buffer_put_int(&oqueue, mlen); + buffer_append(&oqueue, buffer_ptr(m), mlen); + buffer_consume(m, mlen); +} + +static void +send_status(u_int32_t id, u_int32_t status) +{ + Buffer msg; + const char *status_messages[] = { + "Success", /* SSH_FX_OK */ + "End of file", /* SSH_FX_EOF */ + "No such file", /* SSH_FX_NO_SUCH_FILE */ + "Permission denied", /* SSH_FX_PERMISSION_DENIED */ + "Failure", /* SSH_FX_FAILURE */ + "Bad message", /* SSH_FX_BAD_MESSAGE */ + "No connection", /* SSH_FX_NO_CONNECTION */ + "Connection lost", /* SSH_FX_CONNECTION_LOST */ + "Operation unsupported", /* SSH_FX_OP_UNSUPPORTED */ + "Unknown error" /* Others */ + }; + + TRACE("sent status id %u error %u", id, status); + buffer_init(&msg); + buffer_put_char(&msg, SSH2_FXP_STATUS); + buffer_put_int(&msg, id); + buffer_put_int(&msg, status); + if (version >= 3) { + buffer_put_cstring(&msg, + status_messages[MIN(status,SSH2_FX_MAX)]); + buffer_put_cstring(&msg, ""); + } + send_msg(&msg); + buffer_free(&msg); +} +static void +send_data_or_handle(char type, u_int32_t id, const char *data, int dlen) +{ + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, type); + buffer_put_int(&msg, id); + buffer_put_string(&msg, data, dlen); + send_msg(&msg); + buffer_free(&msg); +} + +static void +send_data(u_int32_t id, const char *data, int dlen) +{ + TRACE("sent data id %u len %d", id, dlen); + send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); +} + +static void +send_handle(u_int32_t id, int handle) +{ + char *string; + int hlen; + + handle_to_string(handle, &string, &hlen); + TRACE("sent handle id %u handle %d", id, handle); + send_data_or_handle(SSH2_FXP_HANDLE, id, string, hlen); + xfree(string); +} + +static void +send_names(u_int32_t id, int count, const Stat *stats) +{ + Buffer msg; + int i; + + buffer_init(&msg); + buffer_put_char(&msg, SSH2_FXP_NAME); + buffer_put_int(&msg, id); + buffer_put_int(&msg, count); + TRACE("sent names id %u count %d", id, count); + for (i = 0; i < count; i++) { + buffer_put_cstring(&msg, stats[i].name); + buffer_put_cstring(&msg, stats[i].long_name); + encode_attrib(&msg, &stats[i].attrib); + } + send_msg(&msg); + buffer_free(&msg); +} + +static void +send_attrib(u_int32_t id, const Attrib *a) +{ + Buffer msg; + + TRACE("sent attrib id %u have 0x%x", id, a->flags); + buffer_init(&msg); + buffer_put_char(&msg, SSH2_FXP_ATTRS); + buffer_put_int(&msg, id); + encode_attrib(&msg, a); + send_msg(&msg); + buffer_free(&msg); +} + +/* parse incoming */ + +static void +process_init(void) +{ + Buffer msg; + + version = get_int(); + TRACE("client version %d", version); + buffer_init(&msg); + buffer_put_char(&msg, SSH2_FXP_VERSION); + buffer_put_int(&msg, SSH2_FILEXFER_VERSION); + send_msg(&msg); + buffer_free(&msg); +} + +static void +process_open(void) +{ + u_int32_t id, pflags; + Attrib *a; + char *name; + int handle, fd, flags, mode, status = SSH2_FX_FAILURE; + + id = get_int(); + name = get_string(NULL); + pflags = get_int(); /* portable flags */ + a = get_attrib(); + flags = flags_from_portable(pflags); + mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a->perm : 0666; + TRACE("open id %u name %s flags %d mode 0%o", id, name, pflags, mode); + fd = open(name, flags, mode); + if (fd < 0) { + status = errno_to_portable(errno); + } else { + handle = handle_new(HANDLE_FILE, name, fd, NULL); + if (handle < 0) { + close(fd); + } else { + send_handle(id, handle); + status = SSH2_FX_OK; + } + } + if (status != SSH2_FX_OK) + send_status(id, status); + xfree(name); +} + +static void +process_close(void) +{ + u_int32_t id; + int handle, ret, status = SSH2_FX_FAILURE; + + id = get_int(); + handle = get_handle(); + TRACE("close id %u handle %d", id, handle); + ret = handle_close(handle); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + send_status(id, status); +} + +static void +process_read(void) +{ + char buf[64*1024]; + u_int32_t id, len; + int handle, fd, ret, status = SSH2_FX_FAILURE; + u_int64_t off; + + id = get_int(); + handle = get_handle(); + off = get_int64(); + len = get_int(); + + TRACE("read id %u handle %d off %llu len %d", id, handle, + (u_int64_t)off, len); + if (len > sizeof buf) { + len = sizeof buf; + logit("read change len %d", len); + } + fd = handle_to_fd(handle); + if (fd >= 0) { + if (lseek(fd, off, SEEK_SET) < 0) { + error("process_read: seek failed"); + status = errno_to_portable(errno); + } else { + ret = read(fd, buf, len); + if (ret < 0) { + status = errno_to_portable(errno); + } else if (ret == 0) { + status = SSH2_FX_EOF; + } else { + send_data(id, buf, ret); + status = SSH2_FX_OK; + } + } + } + if (status != SSH2_FX_OK) + send_status(id, status); +} + +static void +process_write(void) +{ + u_int32_t id; + u_int64_t off; + u_int len; + int handle, fd, ret, status = SSH2_FX_FAILURE; + char *data; + + id = get_int(); + handle = get_handle(); + off = get_int64(); + data = get_string(&len); + + TRACE("write id %u handle %d off %llu len %d", id, handle, + (u_int64_t)off, len); + fd = handle_to_fd(handle); + if (fd >= 0) { + if (lseek(fd, off, SEEK_SET) < 0) { + status = errno_to_portable(errno); + error("process_write: seek failed"); + } else { +/* XXX ATOMICIO ? */ + ret = write(fd, data, len); + if (ret == -1) { + error("process_write: write failed"); + status = errno_to_portable(errno); + } else if (ret == len) { + status = SSH2_FX_OK; + } else { + logit("nothing at all written"); + } + } + } + send_status(id, status); + xfree(data); +} + +static void +process_do_stat(int do_lstat) +{ + Attrib a; + struct stat st; + u_int32_t id; + char *name; + int ret, status = SSH2_FX_FAILURE; + + id = get_int(); + name = get_string(NULL); + TRACE("%sstat id %u name %s", do_lstat ? "l" : "", id, name); + ret = do_lstat ? lstat(name, &st) : stat(name, &st); + if (ret < 0) { + status = errno_to_portable(errno); + } else { + stat_to_attrib(&st, &a); + send_attrib(id, &a); + status = SSH2_FX_OK; + } + if (status != SSH2_FX_OK) + send_status(id, status); + xfree(name); +} + +static void +process_stat(void) +{ + process_do_stat(0); +} + +static void +process_lstat(void) +{ + process_do_stat(1); +} + +static void +process_fstat(void) +{ + Attrib a; + struct stat st; + u_int32_t id; + int fd, ret, handle, status = SSH2_FX_FAILURE; + + id = get_int(); + handle = get_handle(); + TRACE("fstat id %u handle %d", id, handle); + fd = handle_to_fd(handle); + if (fd >= 0) { + ret = fstat(fd, &st); + if (ret < 0) { + status = errno_to_portable(errno); + } else { + stat_to_attrib(&st, &a); + send_attrib(id, &a); + status = SSH2_FX_OK; + } + } + if (status != SSH2_FX_OK) + send_status(id, status); +} + +static struct timeval * +attrib_to_tv(const Attrib *a) +{ + static struct timeval tv[2]; + + tv[0].tv_sec = a->atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = a->mtime; + tv[1].tv_usec = 0; + return tv; +} + +static void +process_setstat(void) +{ + Attrib *a; + u_int32_t id; + char *name; + int status = SSH2_FX_OK, ret; + + id = get_int(); + name = get_string(NULL); + a = get_attrib(); + TRACE("setstat id %u name %s", id, name); + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { + ret = truncate(name, a->size); + if (ret == -1) + status = errno_to_portable(errno); + } + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { + ret = chmod(name, a->perm & 0777); + if (ret == -1) + status = errno_to_portable(errno); + } + if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { + ret = utimes(name, attrib_to_tv(a)); + if (ret == -1) + status = errno_to_portable(errno); + } + if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { + ret = chown(name, a->uid, a->gid); + if (ret == -1) + status = errno_to_portable(errno); + } + send_status(id, status); + xfree(name); +} + +static void +process_fsetstat(void) +{ + Attrib *a; + u_int32_t id; + int handle, fd, ret; + int status = SSH2_FX_OK; + char *name; + + id = get_int(); + handle = get_handle(); + a = get_attrib(); + TRACE("fsetstat id %u handle %d", id, handle); + fd = handle_to_fd(handle); + name = handle_to_name(handle); + if (fd < 0 || name == NULL) { + status = SSH2_FX_FAILURE; + } else { + if (a->flags & SSH2_FILEXFER_ATTR_SIZE) { + ret = ftruncate(fd, a->size); + if (ret == -1) + status = errno_to_portable(errno); + } + if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { +#ifdef HAVE_FCHMOD + ret = fchmod(fd, a->perm & 0777); +#else + ret = chmod(name, a->perm & 0777); +#endif + if (ret == -1) + status = errno_to_portable(errno); + } + if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { +#ifdef HAVE_FUTIMES + ret = futimes(fd, attrib_to_tv(a)); +#else + ret = utimes(name, attrib_to_tv(a)); +#endif + if (ret == -1) + status = errno_to_portable(errno); + } + if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { +#ifdef HAVE_FCHOWN + ret = fchown(fd, a->uid, a->gid); +#else + ret = chown(name, a->uid, a->gid); +#endif + if (ret == -1) + status = errno_to_portable(errno); + } + } + send_status(id, status); +} + +static void +process_opendir(void) +{ + DIR *dirp = NULL; + char *path; + int handle, status = SSH2_FX_FAILURE; + u_int32_t id; + + id = get_int(); + path = get_string(NULL); + TRACE("opendir id %u path %s", id, path); + dirp = opendir(path); + if (dirp == NULL) { + status = errno_to_portable(errno); + } else { + handle = handle_new(HANDLE_DIR, path, 0, dirp); + if (handle < 0) { + closedir(dirp); + } else { + send_handle(id, handle); + status = SSH2_FX_OK; + } + + } + if (status != SSH2_FX_OK) + send_status(id, status); + xfree(path); +} + +static void +process_readdir(void) +{ + DIR *dirp; + struct dirent *dp; + char *path; + int handle; + u_int32_t id; + + id = get_int(); + handle = get_handle(); + TRACE("readdir id %u handle %d", id, handle); + dirp = handle_to_dir(handle); + path = handle_to_name(handle); + if (dirp == NULL || path == NULL) { + send_status(id, SSH2_FX_FAILURE); + } else { + struct stat st; + char pathname[1024]; + Stat *stats; + int nstats = 10, count = 0, i; + + stats = xmalloc(nstats * sizeof(Stat)); + while ((dp = readdir(dirp)) != NULL) { + if (count >= nstats) { + nstats *= 2; + stats = xrealloc(stats, nstats * sizeof(Stat)); + } +/* XXX OVERFLOW ? */ + snprintf(pathname, sizeof pathname, "%s%s%s", path, + strcmp(path, "/") ? "/" : "", dp->d_name); + if (lstat(pathname, &st) < 0) + continue; + stat_to_attrib(&st, &(stats[count].attrib)); + stats[count].name = xstrdup(dp->d_name); + stats[count].long_name = ls_file(dp->d_name, &st, 0); + count++; + /* send up to 100 entries in one message */ + /* XXX check packet size instead */ + if (count == 100) + break; + } + if (count > 0) { + send_names(id, count, stats); + for (i = 0; i < count; i++) { + xfree(stats[i].name); + xfree(stats[i].long_name); + } + } else { + send_status(id, SSH2_FX_EOF); + } + xfree(stats); + } +} + +static void +process_remove(void) +{ + char *name; + u_int32_t id; + int status = SSH2_FX_FAILURE; + int ret; + + id = get_int(); + name = get_string(NULL); + TRACE("remove id %u name %s", id, name); + ret = unlink(name); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + send_status(id, status); + xfree(name); +} + +static void +process_mkdir(void) +{ + Attrib *a; + u_int32_t id; + char *name; + int ret, mode, status = SSH2_FX_FAILURE; + + id = get_int(); + name = get_string(NULL); + a = get_attrib(); + mode = (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? + a->perm & 0777 : 0777; + TRACE("mkdir id %u name %s mode 0%o", id, name, mode); + ret = mkdir(name, mode); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + send_status(id, status); + xfree(name); +} + +static void +process_rmdir(void) +{ + u_int32_t id; + char *name; + int ret, status; + + id = get_int(); + name = get_string(NULL); + TRACE("rmdir id %u name %s", id, name); + ret = rmdir(name); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + send_status(id, status); + xfree(name); +} + +static void +process_realpath(void) +{ + char resolvedname[MAXPATHLEN]; + u_int32_t id; + char *path; + + id = get_int(); + path = get_string(NULL); + if (path[0] == '\0') { + xfree(path); + path = xstrdup("."); + } + TRACE("realpath id %u path %s", id, path); + if (realpath(path, resolvedname) == NULL) { + send_status(id, errno_to_portable(errno)); + } else { + Stat s; + attrib_clear(&s.attrib); + s.name = s.long_name = resolvedname; + send_names(id, 1, &s); + } + xfree(path); +} + +static void +process_rename(void) +{ + u_int32_t id; + char *oldpath, *newpath; + int status; + struct stat sb; + + id = get_int(); + oldpath = get_string(NULL); + newpath = get_string(NULL); + TRACE("rename id %u old %s new %s", id, oldpath, newpath); + status = SSH2_FX_FAILURE; + if (lstat(oldpath, &sb) == -1) + status = errno_to_portable(errno); + else if (S_ISREG(sb.st_mode)) { + /* Race-free rename of regular files */ + if (link(oldpath, newpath) == -1) { + if (errno == EOPNOTSUPP +#ifdef LINK_OPNOTSUPP_ERRNO + || errno == LINK_OPNOTSUPP_ERRNO +#endif + ) { + struct stat st; + + /* + * fs doesn't support links, so fall back to + * stat+rename. This is racy. + */ + if (stat(newpath, &st) == -1) { + if (rename(oldpath, newpath) == -1) + status = + errno_to_portable(errno); + else + status = SSH2_FX_OK; + } + } else { + status = errno_to_portable(errno); + } + } else if (unlink(oldpath) == -1) { + status = errno_to_portable(errno); + /* clean spare link */ + unlink(newpath); + } else + status = SSH2_FX_OK; + } else if (stat(newpath, &sb) == -1) { + if (rename(oldpath, newpath) == -1) + status = errno_to_portable(errno); + else + status = SSH2_FX_OK; + } + send_status(id, status); + xfree(oldpath); + xfree(newpath); +} + +static void +process_readlink(void) +{ + u_int32_t id; + int len; + char buf[MAXPATHLEN]; + char *path; + + id = get_int(); + path = get_string(NULL); + TRACE("readlink id %u path %s", id, path); + if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1) + send_status(id, errno_to_portable(errno)); + else { + Stat s; + + buf[len] = '\0'; + attrib_clear(&s.attrib); + s.name = s.long_name = buf; + send_names(id, 1, &s); + } + xfree(path); +} + +static void +process_symlink(void) +{ + u_int32_t id; + char *oldpath, *newpath; + int ret, status; + + id = get_int(); + oldpath = get_string(NULL); + newpath = get_string(NULL); + TRACE("symlink id %u old %s new %s", id, oldpath, newpath); + /* this will fail if 'newpath' exists */ + ret = symlink(oldpath, newpath); + status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; + send_status(id, status); + xfree(oldpath); + xfree(newpath); +} + +static void +process_extended(void) +{ + u_int32_t id; + char *request; + + id = get_int(); + request = get_string(NULL); + send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ + xfree(request); +} + +/* stolen from ssh-agent */ + +static void +process(void) +{ + u_int msg_len; + u_int buf_len; + u_int consumed; + u_int type; + u_char *cp; + + buf_len = buffer_len(&iqueue); + if (buf_len < 5) + return; /* Incomplete message. */ + cp = buffer_ptr(&iqueue); + msg_len = GET_32BIT(cp); + if (msg_len > 256 * 1024) { + error("bad message "); + exit(11); + } + if (buf_len < msg_len + 4) + return; + buffer_consume(&iqueue, 4); + buf_len -= 4; + type = buffer_get_char(&iqueue); + switch (type) { + case SSH2_FXP_INIT: + process_init(); + break; + case SSH2_FXP_OPEN: + process_open(); + break; + case SSH2_FXP_CLOSE: + process_close(); + break; + case SSH2_FXP_READ: + process_read(); + break; + case SSH2_FXP_WRITE: + process_write(); + break; + case SSH2_FXP_LSTAT: + process_lstat(); + break; + case SSH2_FXP_FSTAT: + process_fstat(); + break; + case SSH2_FXP_SETSTAT: + process_setstat(); + break; + case SSH2_FXP_FSETSTAT: + process_fsetstat(); + break; + case SSH2_FXP_OPENDIR: + process_opendir(); + break; + case SSH2_FXP_READDIR: + process_readdir(); + break; + case SSH2_FXP_REMOVE: + process_remove(); + break; + case SSH2_FXP_MKDIR: + process_mkdir(); + break; + case SSH2_FXP_RMDIR: + process_rmdir(); + break; + case SSH2_FXP_REALPATH: + process_realpath(); + break; + case SSH2_FXP_STAT: + process_stat(); + break; + case SSH2_FXP_RENAME: + process_rename(); + break; + case SSH2_FXP_READLINK: + process_readlink(); + break; + case SSH2_FXP_SYMLINK: + process_symlink(); + break; + case SSH2_FXP_EXTENDED: + process_extended(); + break; + default: + error("Unknown message %d", type); + break; + } + /* discard the remaining bytes from the current packet */ + if (buf_len < buffer_len(&iqueue)) + fatal("iqueue grows"); + consumed = buf_len - buffer_len(&iqueue); + if (msg_len < consumed) + fatal("msg_len %d < consumed %d", msg_len, consumed); + if (msg_len > consumed) + buffer_consume(&iqueue, msg_len - consumed); +} + +int +main(int ac, char **av) +{ + fd_set *rset, *wset; + int in, out, max; + ssize_t len, olen, set_size; + + /* XXX should use getopt */ + + __progname = ssh_get_progname(av[0]); + handle_init(); + +#ifdef DEBUG_SFTP_SERVER + log_init("sftp-server", SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 0); +#endif + + in = dup(STDIN_FILENO); + out = dup(STDOUT_FILENO); + +#ifdef HAVE_CYGWIN + setmode(in, O_BINARY); + setmode(out, O_BINARY); +#endif + + max = 0; + if (in > max) + max = in; + if (out > max) + max = out; + + buffer_init(&iqueue); + buffer_init(&oqueue); + + set_size = howmany(max + 1, NFDBITS) * sizeof(fd_mask); + rset = (fd_set *)xmalloc(set_size); + wset = (fd_set *)xmalloc(set_size); + + for (;;) { + memset(rset, 0, set_size); + memset(wset, 0, set_size); + + FD_SET(in, rset); + olen = buffer_len(&oqueue); + if (olen > 0) + FD_SET(out, wset); + + if (select(max+1, rset, wset, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + exit(2); + } + + /* copy stdin to iqueue */ + if (FD_ISSET(in, rset)) { + char buf[4*4096]; + len = read(in, buf, sizeof buf); + if (len == 0) { + debug("read eof"); + exit(0); + } else if (len < 0) { + error("read error"); + exit(1); + } else { + buffer_append(&iqueue, buf, len); + } + } + /* send oqueue to stdout */ + if (FD_ISSET(out, wset)) { + len = write(out, buffer_ptr(&oqueue), olen); + if (len < 0) { + error("write error"); + exit(1); + } else { + buffer_consume(&oqueue, len); + } + } + /* process requests from client */ + process(); + } +} diff --git a/crypto/openssh-3.9p1/sftp.1 b/crypto/openssh-3.9p1/sftp.1 new file mode 100644 index 0000000000..3b035b1d40 --- /dev/null +++ b/crypto/openssh-3.9p1/sftp.1 @@ -0,0 +1,396 @@ +.\" $OpenBSD: sftp.1,v 1.57 2004/06/21 22:41:31 djm Exp $ +.\" +.\" Copyright (c) 2001 Damien Miller. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd February 4, 2001 +.Dt SFTP 1 +.Os +.Sh NAME +.Nm sftp +.Nd secure file transfer program +.Sh SYNOPSIS +.Nm sftp +.Bk -words +.Op Fl 1Cv +.Op Fl B Ar buffer_size +.Op Fl b Ar batchfile +.Op Fl F Ar ssh_config +.Op Fl o Ar ssh_option +.Op Fl P Ar sftp_server_path +.Op Fl R Ar num_requests +.Op Fl S Ar program +.Op Fl s Ar subsystem | sftp_server +.Ar host +.Ek +.Nm sftp +.Oo Oo Ar user Ns @ Oc Ns +.Ar host Ns Oo : Ns Ar file Oo +.Ar file Oc Oc Oc +.Nm sftp +.Oo Oo Ar user Ns @ Oc Ns +.Ar host Ns Oo : Ns Ar dir Ns +.Oo Ar / Oc Oc Oc +.Nm sftp +.Fl b Ar batchfile +.Oo Ar user Ns @ Oc Ns Ar host +.Sh DESCRIPTION +.Nm +is an interactive file transfer program, similar to +.Xr ftp 1 , +which performs all operations over an encrypted +.Xr ssh 1 +transport. +It may also use many features of ssh, such as public key authentication and +compression. +.Nm +connects and logs into the specified +.Ar host , +then enters an interactive command mode. +.Pp +The second usage format will retrieve files automatically if a non-interactive +authentication method is used; otherwise it will do so after +successful interactive authentication. +.Pp +The third usage format allows the sftp client to start in a remote directory. +.Pp +The final usage format allows for automated sessions using the +.Fl b +option. +In such cases, it is usually necessary to configure public key authentication +to obviate the need to enter a password at connection time (see +.Xr sshd 8 +and +.Xr ssh-keygen 1 +for details). +The options are as follows: +.Bl -tag -width Ds +.It Fl 1 +Specify the use of protocol version 1. +.It Fl B Ar buffer_size +Specify the size of the buffer that +.Nm +uses when transferring files. +Larger buffers require fewer round trips at the cost of higher +memory consumption. +The default is 32768 bytes. +.It Fl b Ar batchfile +Batch mode reads a series of commands from an input +.Ar batchfile +instead of +.Em stdin . +Since it lacks user interaction it should be used in conjunction with +non-interactive authentication. +A +.Ar batchfile +of +.Sq \- +may be used to indicate standard input. +.Nm +will abort if any of the following +commands fail: +.Ic get , put , rename , ln , +.Ic rm , mkdir , chdir , ls , +.Ic lchdir , chmod , chown , chgrp , lpwd +and +.Ic lmkdir . +Termination on error can be suppressed on a command by command basis by +prefixing the command with a +.Sq \- +character (for example, +.Ic -rm /tmp/blah* ) . +.It Fl C +Enables compression (via ssh's +.Fl C +flag). +.It Fl F Ar ssh_config +Specifies an alternative +per-user configuration file for +.Xr ssh 1 . +This option is directly passed to +.Xr ssh 1 . +.It Fl o Ar ssh_option +Can be used to pass options to +.Nm ssh +in the format used in +.Xr ssh_config 5 . +This is useful for specifying options +for which there is no separate +.Nm sftp +command-line flag. +For example, to specify an alternate port use: +.Ic sftp -oPort=24 . +For full details of the options listed below, and their possible values, see +.Xr ssh_config 5 . +.Pp +.Bl -tag -width Ds -offset indent -compact +.It AddressFamily +.It BatchMode +.It BindAddress +.It ChallengeResponseAuthentication +.It CheckHostIP +.It Cipher +.It Ciphers +.It Compression +.It CompressionLevel +.It ConnectionAttempts +.It ConnectTimeout +.It ControlMaster +.It ControlPath +.It GlobalKnownHostsFile +.It GSSAPIAuthentication +.It GSSAPIDelegateCredentials +.It Host +.It HostbasedAuthentication +.It HostKeyAlgorithms +.It HostKeyAlias +.It HostName +.It IdentityFile +.It IdentitiesOnly +.It LogLevel +.It MACs +.It NoHostAuthenticationForLocalhost +.It NumberOfPasswordPrompts +.It PasswordAuthentication +.It Port +.It PreferredAuthentications +.It Protocol +.It ProxyCommand +.It PubkeyAuthentication +.It RhostsRSAAuthentication +.It RSAAuthentication +.It SendEnv +.It ServerAliveInterval +.It ServerAliveCountMax +.It SmartcardDevice +.It StrictHostKeyChecking +.It TCPKeepAlive +.It UsePrivilegedPort +.It User +.It UserKnownHostsFile +.It VerifyHostKeyDNS +.El +.It Fl P Ar sftp_server_path +Connect directly to a local sftp server +(rather than via +.Xr ssh 1 ) +This option may be useful in debugging the client and server. +.It Fl R Ar num_requests +Specify how many requests may be outstanding at any one time. +Increasing this may slightly improve file transfer speed +but will increase memory usage. +The default is 16 outstanding requests. +.It Fl S Ar program +Name of the +.Ar program +to use for the encrypted connection. +The program must understand +.Xr ssh 1 +options. +.It Fl s Ar subsystem | sftp_server +Specifies the SSH2 subsystem or the path for an sftp server +on the remote host. +A path is useful for using +.Nm +over protocol version 1, or when the remote +.Xr sshd 8 +does not have an sftp subsystem configured. +.It Fl v +Raise logging level. +This option is also passed to ssh. +.El +.Sh INTERACTIVE COMMANDS +Once in interactive mode, +.Nm +understands a set of commands similar to those of +.Xr ftp 1 . +Commands are case insensitive and pathnames may be enclosed in quotes if they +contain spaces. +.Bl -tag -width "lmdir path" +.It Ic bye +Quit +.Nm sftp . +.It Ic cd Ar path +Change remote directory to +.Ar path . +.It Ic chgrp Ar grp Ar path +Change group of file +.Ar path +to +.Ar grp . +.Ar grp +must be a numeric GID. +.It Ic chmod Ar mode Ar path +Change permissions of file +.Ar path +to +.Ar mode . +.It Ic chown Ar own Ar path +Change owner of file +.Ar path +to +.Ar own . +.Ar own +must be a numeric UID. +.It Ic exit +Quit +.Nm sftp . +.It Xo Ic get +.Op Ar flags +.Ar remote-path +.Op Ar local-path +.Xc +Retrieve the +.Ar remote-path +and store it on the local machine. +If the local +path name is not specified, it is given the same name it has on the +remote machine. +If the +.Fl P +flag is specified, then the file's full permission and access time are +copied too. +.It Ic help +Display help text. +.It Ic lcd Ar path +Change local directory to +.Ar path . +.It Ic lls Op Ar ls-options Op Ar path +Display local directory listing of either +.Ar path +or current directory if +.Ar path +is not specified. +.It Ic lmkdir Ar path +Create local directory specified by +.Ar path . +.It Ic ln Ar oldpath Ar newpath +Create a symbolic link from +.Ar oldpath +to +.Ar newpath . +.It Ic lpwd +Print local working directory. +.It Xo Ic ls +.Op Ar flags +.Op Ar path +.Xc +Display remote directory listing of either +.Ar path +or current directory if +.Ar path +is not specified. +If the +.Fl l +flag is specified, then display additional details including permissions +and ownership information. +The +.Fl n +flag will produce a long listing with user and group information presented +numerically. +.Pp +By default, +.Ic ls +listings are sorted in lexicographical order. +This may be changed by specifying the +.Fl S +(sort by file size), +.Fl t +(sort by last modification time), or +.Fl f +(don't sort at all) flags. +Additionally, the sort order may be reversed using the +.Fl r +flag. +.It Ic lumask Ar umask +Set local umask to +.Ar umask . +.It Ic mkdir Ar path +Create remote directory specified by +.Ar path . +.It Ic progress +Toggle display of progress meter. +.It Xo Ic put +.Op Ar flags +.Ar local-path +.Op Ar remote-path +.Xc +Upload +.Ar local-path +and store it on the remote machine. +If the remote path name is not specified, it is given the same name it has +on the local machine. +If the +.Fl P +flag is specified, then the file's full permission and access time are +copied too. +.It Ic pwd +Display remote working directory. +.It Ic quit +Quit +.Nm sftp . +.It Ic rename Ar oldpath Ar newpath +Rename remote file from +.Ar oldpath +to +.Ar newpath . +.It Ic rm Ar path +Delete remote file specified by +.Ar path . +.It Ic rmdir Ar path +Remove remote directory specified by +.Ar path . +.It Ic symlink Ar oldpath Ar newpath +Create a symbolic link from +.Ar oldpath +to +.Ar newpath . +.It Ic version +Display the +.Nm +protocol version. +.It Ic \&! Ar command +Execute +.Ar command +in local shell. +.It Ic \&! +Escape to local shell. +.It Ic \&? +Synonym for help. +.El +.Sh SEE ALSO +.Xr ftp 1 , +.Xr scp 1 , +.Xr ssh 1 , +.Xr ssh-add 1 , +.Xr ssh-keygen 1 , +.Xr ssh_config 5 , +.Xr sftp-server 8 , +.Xr sshd 8 +.Rs +.%A T. Ylonen +.%A S. Lehtinen +.%T "SSH File Transfer Protocol" +.%N draft-ietf-secsh-filexfer-00.txt +.%D January 2001 +.%O work in progress material +.Re diff --git a/crypto/openssh-3.9p1/sftp.c b/crypto/openssh-3.9p1/sftp.c new file mode 100644 index 0000000000..f01c9194c3 --- /dev/null +++ b/crypto/openssh-3.9p1/sftp.c @@ -0,0 +1,1519 @@ +/* + * Copyright (c) 2001-2004 Damien Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +RCSID("$OpenBSD: sftp.c,v 1.56 2004/07/11 17:48:47 deraadt Exp $"); + +#include "buffer.h" +#include "xmalloc.h" +#include "log.h" +#include "pathnames.h" +#include "misc.h" + +#include "sftp.h" +#include "sftp-common.h" +#include "sftp-client.h" + +/* File to read commands from */ +FILE* infile; + +/* Are we in batchfile mode? */ +int batchmode = 0; + +/* Size of buffer used when copying files */ +size_t copy_buffer_len = 32768; + +/* Number of concurrent outstanding requests */ +size_t num_requests = 16; + +/* PID of ssh transport process */ +static pid_t sshpid = -1; + +/* This is set to 0 if the progressmeter is not desired. */ +int showprogress = 1; + +/* SIGINT received during command processing */ +volatile sig_atomic_t interrupted = 0; + +/* I wish qsort() took a separate ctx for the comparison function...*/ +int sort_flag; + +int remote_glob(struct sftp_conn *, const char *, int, + int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ + +extern char *__progname; + +/* Separators for interactive commands */ +#define WHITESPACE " \t\r\n" + +/* ls flags */ +#define LS_LONG_VIEW 0x01 /* Full view ala ls -l */ +#define LS_SHORT_VIEW 0x02 /* Single row view ala ls -1 */ +#define LS_NUMERIC_VIEW 0x04 /* Long view with numeric uid/gid */ +#define LS_NAME_SORT 0x08 /* Sort by name (default) */ +#define LS_TIME_SORT 0x10 /* Sort by mtime */ +#define LS_SIZE_SORT 0x20 /* Sort by file size */ +#define LS_REVERSE_SORT 0x40 /* Reverse sort order */ +#define LS_SHOW_ALL 0x80 /* Don't skip filenames starting with '.' */ + +#define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW) +#define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) + +/* Commands for interactive mode */ +#define I_CHDIR 1 +#define I_CHGRP 2 +#define I_CHMOD 3 +#define I_CHOWN 4 +#define I_GET 5 +#define I_HELP 6 +#define I_LCHDIR 7 +#define I_LLS 8 +#define I_LMKDIR 9 +#define I_LPWD 10 +#define I_LS 11 +#define I_LUMASK 12 +#define I_MKDIR 13 +#define I_PUT 14 +#define I_PWD 15 +#define I_QUIT 16 +#define I_RENAME 17 +#define I_RM 18 +#define I_RMDIR 19 +#define I_SHELL 20 +#define I_SYMLINK 21 +#define I_VERSION 22 +#define I_PROGRESS 23 + +struct CMD { + const char *c; + const int n; +}; + +static const struct CMD cmds[] = { + { "bye", I_QUIT }, + { "cd", I_CHDIR }, + { "chdir", I_CHDIR }, + { "chgrp", I_CHGRP }, + { "chmod", I_CHMOD }, + { "chown", I_CHOWN }, + { "dir", I_LS }, + { "exit", I_QUIT }, + { "get", I_GET }, + { "mget", I_GET }, + { "help", I_HELP }, + { "lcd", I_LCHDIR }, + { "lchdir", I_LCHDIR }, + { "lls", I_LLS }, + { "lmkdir", I_LMKDIR }, + { "ln", I_SYMLINK }, + { "lpwd", I_LPWD }, + { "ls", I_LS }, + { "lumask", I_LUMASK }, + { "mkdir", I_MKDIR }, + { "progress", I_PROGRESS }, + { "put", I_PUT }, + { "mput", I_PUT }, + { "pwd", I_PWD }, + { "quit", I_QUIT }, + { "rename", I_RENAME }, + { "rm", I_RM }, + { "rmdir", I_RMDIR }, + { "symlink", I_SYMLINK }, + { "version", I_VERSION }, + { "!", I_SHELL }, + { "?", I_HELP }, + { NULL, -1} +}; + +int interactive_loop(int fd_in, int fd_out, char *file1, char *file2); + +static void +killchild(int signo) +{ + if (sshpid > 1) + kill(sshpid, SIGTERM); + + _exit(1); +} + +static void +cmd_interrupt(int signo) +{ + const char msg[] = "\rInterrupt \n"; + + write(STDERR_FILENO, msg, sizeof(msg) - 1); + interrupted = 1; +} + +static void +help(void) +{ + printf("Available commands:\n"); + printf("cd path Change remote directory to 'path'\n"); + printf("lcd path Change local directory to 'path'\n"); + printf("chgrp grp path Change group of file 'path' to 'grp'\n"); + printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); + printf("chown own path Change owner of file 'path' to 'own'\n"); + printf("help Display this help text\n"); + printf("get remote-path [local-path] Download file\n"); + printf("lls [ls-options [path]] Display local directory listing\n"); + printf("ln oldpath newpath Symlink remote file\n"); + printf("lmkdir path Create local directory\n"); + printf("lpwd Print local working directory\n"); + printf("ls [path] Display remote directory listing\n"); + printf("lumask umask Set local umask to 'umask'\n"); + printf("mkdir path Create remote directory\n"); + printf("progress Toggle display of progress meter\n"); + printf("put local-path [remote-path] Upload file\n"); + printf("pwd Display remote working directory\n"); + printf("exit Quit sftp\n"); + printf("quit Quit sftp\n"); + printf("rename oldpath newpath Rename remote file\n"); + printf("rmdir path Remove remote directory\n"); + printf("rm path Delete remote file\n"); + printf("symlink oldpath newpath Symlink remote file\n"); + printf("version Show SFTP version\n"); + printf("!command Execute 'command' in local shell\n"); + printf("! Escape to local shell\n"); + printf("? Synonym for help\n"); +} + +static void +local_do_shell(const char *args) +{ + int status; + char *shell; + pid_t pid; + + if (!*args) + args = NULL; + + if ((shell = getenv("SHELL")) == NULL) + shell = _PATH_BSHELL; + + if ((pid = fork()) == -1) + fatal("Couldn't fork: %s", strerror(errno)); + + if (pid == 0) { + /* XXX: child has pipe fds to ssh subproc open - issue? */ + if (args) { + debug3("Executing %s -c \"%s\"", shell, args); + execl(shell, shell, "-c", args, (char *)NULL); + } else { + debug3("Executing %s", shell); + execl(shell, shell, (char *)NULL); + } + fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell, + strerror(errno)); + _exit(1); + } + while (waitpid(pid, &status, 0) == -1) + if (errno != EINTR) + fatal("Couldn't wait for child: %s", strerror(errno)); + if (!WIFEXITED(status)) + error("Shell exited abormally"); + else if (WEXITSTATUS(status)) + error("Shell exited with status %d", WEXITSTATUS(status)); +} + +static void +local_do_ls(const char *args) +{ + if (!args || !*args) + local_do_shell(_PATH_LS); + else { + int len = strlen(_PATH_LS " ") + strlen(args) + 1; + char *buf = xmalloc(len); + + /* XXX: quoting - rip quoting code from ftp? */ + snprintf(buf, len, _PATH_LS " %s", args); + local_do_shell(buf); + xfree(buf); + } +} + +/* Strip one path (usually the pwd) from the start of another */ +static char * +path_strip(char *path, char *strip) +{ + size_t len; + + if (strip == NULL) + return (xstrdup(path)); + + len = strlen(strip); + if (strip != NULL && strncmp(path, strip, len) == 0) { + if (strip[len - 1] != '/' && path[len] == '/') + len++; + return (xstrdup(path + len)); + } + + return (xstrdup(path)); +} + +static char * +path_append(char *p1, char *p2) +{ + char *ret; + int len = strlen(p1) + strlen(p2) + 2; + + ret = xmalloc(len); + strlcpy(ret, p1, len); + if (p1[strlen(p1) - 1] != '/') + strlcat(ret, "/", len); + strlcat(ret, p2, len); + + return(ret); +} + +static char * +make_absolute(char *p, char *pwd) +{ + char *abs_str; + + /* Derelativise */ + if (p && p[0] != '/') { + abs_str = path_append(pwd, p); + xfree(p); + return(abs_str); + } else + return(p); +} + +static int +infer_path(const char *p, char **ifp) +{ + char *cp; + + cp = strrchr(p, '/'); + if (cp == NULL) { + *ifp = xstrdup(p); + return(0); + } + + if (!cp[1]) { + error("Invalid path"); + return(-1); + } + + *ifp = xstrdup(cp + 1); + return(0); +} + +static int +parse_getput_flags(const char **cpp, int *pflag) +{ + const char *cp = *cpp; + + /* Check for flags */ + if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) { + switch (cp[1]) { + case 'p': + case 'P': + *pflag = 1; + break; + default: + error("Invalid flag -%c", cp[1]); + return(-1); + } + cp += 2; + *cpp = cp + strspn(cp, WHITESPACE); + } + + return(0); +} + +static int +parse_ls_flags(const char **cpp, int *lflag) +{ + const char *cp = *cpp; + + /* Defaults */ + *lflag = LS_NAME_SORT; + + /* Check for flags */ + if (cp++[0] == '-') { + for(; strchr(WHITESPACE, *cp) == NULL; cp++) { + switch (*cp) { + case 'l': + *lflag &= ~VIEW_FLAGS; + *lflag |= LS_LONG_VIEW; + break; + case '1': + *lflag &= ~VIEW_FLAGS; + *lflag |= LS_SHORT_VIEW; + break; + case 'n': + *lflag &= ~VIEW_FLAGS; + *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW; + break; + case 'S': + *lflag &= ~SORT_FLAGS; + *lflag |= LS_SIZE_SORT; + break; + case 't': + *lflag &= ~SORT_FLAGS; + *lflag |= LS_TIME_SORT; + break; + case 'r': + *lflag |= LS_REVERSE_SORT; + break; + case 'f': + *lflag &= ~SORT_FLAGS; + break; + case 'a': + *lflag |= LS_SHOW_ALL; + break; + default: + error("Invalid flag -%c", *cp); + return(-1); + } + } + *cpp = cp + strspn(cp, WHITESPACE); + } + + return(0); +} + +static int +get_pathname(const char **cpp, char **path) +{ + const char *cp = *cpp, *end; + char quot; + int i, j; + + cp += strspn(cp, WHITESPACE); + if (!*cp) { + *cpp = cp; + *path = NULL; + return (0); + } + + *path = xmalloc(strlen(cp) + 1); + + /* Check for quoted filenames */ + if (*cp == '\"' || *cp == '\'') { + quot = *cp++; + + /* Search for terminating quote, unescape some chars */ + for (i = j = 0; i <= strlen(cp); i++) { + if (cp[i] == quot) { /* Found quote */ + i++; + (*path)[j] = '\0'; + break; + } + if (cp[i] == '\0') { /* End of string */ + error("Unterminated quote"); + goto fail; + } + if (cp[i] == '\\') { /* Escaped characters */ + i++; + if (cp[i] != '\'' && cp[i] != '\"' && + cp[i] != '\\') { + error("Bad escaped character '\\%c'", + cp[i]); + goto fail; + } + } + (*path)[j++] = cp[i]; + } + + if (j == 0) { + error("Empty quotes"); + goto fail; + } + *cpp = cp + i + strspn(cp + i, WHITESPACE); + } else { + /* Read to end of filename */ + end = strpbrk(cp, WHITESPACE); + if (end == NULL) + end = strchr(cp, '\0'); + *cpp = end + strspn(end, WHITESPACE); + + memcpy(*path, cp, end - cp); + (*path)[end - cp] = '\0'; + } + return (0); + + fail: + xfree(*path); + *path = NULL; + return (-1); +} + +static int +is_dir(char *path) +{ + struct stat sb; + + /* XXX: report errors? */ + if (stat(path, &sb) == -1) + return(0); + + return(sb.st_mode & S_IFDIR); +} + +static int +is_reg(char *path) +{ + struct stat sb; + + if (stat(path, &sb) == -1) + fatal("stat %s: %s", path, strerror(errno)); + + return(S_ISREG(sb.st_mode)); +} + +static int +remote_is_dir(struct sftp_conn *conn, char *path) +{ + Attrib *a; + + /* XXX: report errors? */ + if ((a = do_stat(conn, path, 1)) == NULL) + return(0); + if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) + return(0); + return(a->perm & S_IFDIR); +} + +static int +process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) +{ + char *abs_src = NULL; + char *abs_dst = NULL; + char *tmp; + glob_t g; + int err = 0; + int i; + + abs_src = xstrdup(src); + abs_src = make_absolute(abs_src, pwd); + + memset(&g, 0, sizeof(g)); + debug3("Looking up %s", abs_src); + if (remote_glob(conn, abs_src, 0, NULL, &g)) { + error("File \"%s\" not found.", abs_src); + err = -1; + goto out; + } + + /* If multiple matches, dst must be a directory or unspecified */ + if (g.gl_matchc > 1 && dst && !is_dir(dst)) { + error("Multiple files match, but \"%s\" is not a directory", + dst); + err = -1; + goto out; + } + + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + if (infer_path(g.gl_pathv[i], &tmp)) { + err = -1; + goto out; + } + + if (g.gl_matchc == 1 && dst) { + /* If directory specified, append filename */ + if (is_dir(dst)) { + if (infer_path(g.gl_pathv[0], &tmp)) { + err = 1; + goto out; + } + abs_dst = path_append(dst, tmp); + xfree(tmp); + } else + abs_dst = xstrdup(dst); + } else if (dst) { + abs_dst = path_append(dst, tmp); + xfree(tmp); + } else + abs_dst = tmp; + + printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); + if (do_download(conn, g.gl_pathv[i], abs_dst, pflag) == -1) + err = -1; + xfree(abs_dst); + abs_dst = NULL; + } + +out: + xfree(abs_src); + if (abs_dst) + xfree(abs_dst); + globfree(&g); + return(err); +} + +static int +process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) +{ + char *tmp_dst = NULL; + char *abs_dst = NULL; + char *tmp; + glob_t g; + int err = 0; + int i; + + if (dst) { + tmp_dst = xstrdup(dst); + tmp_dst = make_absolute(tmp_dst, pwd); + } + + memset(&g, 0, sizeof(g)); + debug3("Looking up %s", src); + if (glob(src, 0, NULL, &g)) { + error("File \"%s\" not found.", src); + err = -1; + goto out; + } + + /* If multiple matches, dst may be directory or unspecified */ + if (g.gl_matchc > 1 && tmp_dst && !remote_is_dir(conn, tmp_dst)) { + error("Multiple files match, but \"%s\" is not a directory", + tmp_dst); + err = -1; + goto out; + } + + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + if (!is_reg(g.gl_pathv[i])) { + error("skipping non-regular file %s", + g.gl_pathv[i]); + continue; + } + if (infer_path(g.gl_pathv[i], &tmp)) { + err = -1; + goto out; + } + + if (g.gl_matchc == 1 && tmp_dst) { + /* If directory specified, append filename */ + if (remote_is_dir(conn, tmp_dst)) { + if (infer_path(g.gl_pathv[0], &tmp)) { + err = 1; + goto out; + } + abs_dst = path_append(tmp_dst, tmp); + xfree(tmp); + } else + abs_dst = xstrdup(tmp_dst); + + } else if (tmp_dst) { + abs_dst = path_append(tmp_dst, tmp); + xfree(tmp); + } else + abs_dst = make_absolute(tmp, pwd); + + printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); + if (do_upload(conn, g.gl_pathv[i], abs_dst, pflag) == -1) + err = -1; + } + +out: + if (abs_dst) + xfree(abs_dst); + if (tmp_dst) + xfree(tmp_dst); + globfree(&g); + return(err); +} + +static int +sdirent_comp(const void *aa, const void *bb) +{ + SFTP_DIRENT *a = *(SFTP_DIRENT **)aa; + SFTP_DIRENT *b = *(SFTP_DIRENT **)bb; + int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; + +#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) + if (sort_flag & LS_NAME_SORT) + return (rmul * strcmp(a->filename, b->filename)); + else if (sort_flag & LS_TIME_SORT) + return (rmul * NCMP(a->a.mtime, b->a.mtime)); + else if (sort_flag & LS_SIZE_SORT) + return (rmul * NCMP(a->a.size, b->a.size)); + + fatal("Unknown ls sort type"); +} + +/* sftp ls.1 replacement for directories */ +static int +do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) +{ + int n, c = 1, colspace = 0, columns = 1; + SFTP_DIRENT **d; + + if ((n = do_readdir(conn, path, &d)) != 0) + return (n); + + if (!(lflag & LS_SHORT_VIEW)) { + int m = 0, width = 80; + struct winsize ws; + char *tmp; + + /* Count entries for sort and find longest filename */ + for (n = 0; d[n] != NULL; n++) { + if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL)) + m = MAX(m, strlen(d[n]->filename)); + } + + /* Add any subpath that also needs to be counted */ + tmp = path_strip(path, strip_path); + m += strlen(tmp); + xfree(tmp); + + if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) + width = ws.ws_col; + + columns = width / (m + 2); + columns = MAX(columns, 1); + colspace = width / columns; + colspace = MIN(colspace, width); + } + + if (lflag & SORT_FLAGS) { + sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); + qsort(d, n, sizeof(*d), sdirent_comp); + } + + for (n = 0; d[n] != NULL && !interrupted; n++) { + char *tmp, *fname; + + if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) + continue; + + tmp = path_append(path, d[n]->filename); + fname = path_strip(tmp, strip_path); + xfree(tmp); + + if (lflag & LS_LONG_VIEW) { + if (lflag & LS_NUMERIC_VIEW) { + char *lname; + struct stat sb; + + memset(&sb, 0, sizeof(sb)); + attrib_to_stat(&d[n]->a, &sb); + lname = ls_file(fname, &sb, 1); + printf("%s\n", lname); + xfree(lname); + } else + printf("%s\n", d[n]->longname); + } else { + printf("%-*s", colspace, fname); + if (c >= columns) { + printf("\n"); + c = 1; + } else + c++; + } + + xfree(fname); + } + + if (!(lflag & LS_LONG_VIEW) && (c != 1)) + printf("\n"); + + free_sftp_dirents(d); + return (0); +} + +/* sftp ls.1 replacement which handles path globs */ +static int +do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, + int lflag) +{ + glob_t g; + int i, c = 1, colspace = 0, columns = 1; + Attrib *a; + + memset(&g, 0, sizeof(g)); + + if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE, + NULL, &g)) { + error("Can't ls: \"%s\" not found", path); + return (-1); + } + + if (interrupted) + goto out; + + /* + * If the glob returns a single match, which is the same as the + * input glob, and it is a directory, then just list its contents + */ + if (g.gl_pathc == 1 && + strncmp(path, g.gl_pathv[0], strlen(g.gl_pathv[0]) - 1) == 0) { + if ((a = do_lstat(conn, path, 1)) == NULL) { + globfree(&g); + return (-1); + } + if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && + S_ISDIR(a->perm)) { + globfree(&g); + return (do_ls_dir(conn, path, strip_path, lflag)); + } + } + + if (!(lflag & LS_SHORT_VIEW)) { + int m = 0, width = 80; + struct winsize ws; + + /* Count entries for sort and find longest filename */ + for (i = 0; g.gl_pathv[i]; i++) + m = MAX(m, strlen(g.gl_pathv[i])); + + if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) + width = ws.ws_col; + + columns = width / (m + 2); + columns = MAX(columns, 1); + colspace = width / columns; + } + + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + char *fname; + + fname = path_strip(g.gl_pathv[i], strip_path); + + if (lflag & LS_LONG_VIEW) { + char *lname; + struct stat sb; + + /* + * XXX: this is slow - 1 roundtrip per path + * A solution to this is to fork glob() and + * build a sftp specific version which keeps the + * attribs (which currently get thrown away) + * that the server returns as well as the filenames. + */ + memset(&sb, 0, sizeof(sb)); + a = do_lstat(conn, g.gl_pathv[i], 1); + if (a != NULL) + attrib_to_stat(a, &sb); + lname = ls_file(fname, &sb, 1); + printf("%s\n", lname); + xfree(lname); + } else { + printf("%-*s", colspace, fname); + if (c >= columns) { + printf("\n"); + c = 1; + } else + c++; + } + xfree(fname); + } + + if (!(lflag & LS_LONG_VIEW) && (c != 1)) + printf("\n"); + + out: + if (g.gl_pathc) + globfree(&g); + + return (0); +} + +static int +parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, + unsigned long *n_arg, char **path1, char **path2) +{ + const char *cmd, *cp = *cpp; + char *cp2; + int base = 0; + long l; + int i, cmdnum; + + /* Skip leading whitespace */ + cp = cp + strspn(cp, WHITESPACE); + + /* Ignore blank lines and lines which begin with comment '#' char */ + if (*cp == '\0' || *cp == '#') + return (0); + + /* Check for leading '-' (disable error processing) */ + *iflag = 0; + if (*cp == '-') { + *iflag = 1; + cp++; + } + + /* Figure out which command we have */ + for (i = 0; cmds[i].c; i++) { + int cmdlen = strlen(cmds[i].c); + + /* Check for command followed by whitespace */ + if (!strncasecmp(cp, cmds[i].c, cmdlen) && + strchr(WHITESPACE, cp[cmdlen])) { + cp += cmdlen; + cp = cp + strspn(cp, WHITESPACE); + break; + } + } + cmdnum = cmds[i].n; + cmd = cmds[i].c; + + /* Special case */ + if (*cp == '!') { + cp++; + cmdnum = I_SHELL; + } else if (cmdnum == -1) { + error("Invalid command."); + return (-1); + } + + /* Get arguments and parse flags */ + *lflag = *pflag = *n_arg = 0; + *path1 = *path2 = NULL; + switch (cmdnum) { + case I_GET: + case I_PUT: + if (parse_getput_flags(&cp, pflag)) + return(-1); + /* Get first pathname (mandatory) */ + if (get_pathname(&cp, path1)) + return(-1); + if (*path1 == NULL) { + error("You must specify at least one path after a " + "%s command.", cmd); + return(-1); + } + /* Try to get second pathname (optional) */ + if (get_pathname(&cp, path2)) + return(-1); + break; + case I_RENAME: + case I_SYMLINK: + if (get_pathname(&cp, path1)) + return(-1); + if (get_pathname(&cp, path2)) + return(-1); + if (!*path1 || !*path2) { + error("You must specify two paths after a %s " + "command.", cmd); + return(-1); + } + break; + case I_RM: + case I_MKDIR: + case I_RMDIR: + case I_CHDIR: + case I_LCHDIR: + case I_LMKDIR: + /* Get pathname (mandatory) */ + if (get_pathname(&cp, path1)) + return(-1); + if (*path1 == NULL) { + error("You must specify a path after a %s command.", + cmd); + return(-1); + } + break; + case I_LS: + if (parse_ls_flags(&cp, lflag)) + return(-1); + /* Path is optional */ + if (get_pathname(&cp, path1)) + return(-1); + break; + case I_LLS: + case I_SHELL: + /* Uses the rest of the line */ + break; + case I_LUMASK: + base = 8; + case I_CHMOD: + base = 8; + case I_CHOWN: + case I_CHGRP: + /* Get numeric arg (mandatory) */ + l = strtol(cp, &cp2, base); + if (cp2 == cp || ((l == LONG_MIN || l == LONG_MAX) && + errno == ERANGE) || l < 0) { + error("You must supply a numeric argument " + "to the %s command.", cmd); + return(-1); + } + cp = cp2; + *n_arg = l; + if (cmdnum == I_LUMASK && strchr(WHITESPACE, *cp)) + break; + if (cmdnum == I_LUMASK || !strchr(WHITESPACE, *cp)) { + error("You must supply a numeric argument " + "to the %s command.", cmd); + return(-1); + } + cp += strspn(cp, WHITESPACE); + + /* Get pathname (mandatory) */ + if (get_pathname(&cp, path1)) + return(-1); + if (*path1 == NULL) { + error("You must specify a path after a %s command.", + cmd); + return(-1); + } + break; + case I_QUIT: + case I_PWD: + case I_LPWD: + case I_HELP: + case I_VERSION: + case I_PROGRESS: + break; + default: + fatal("Command not implemented"); + } + + *cpp = cp; + return(cmdnum); +} + +static int +parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, + int err_abort) +{ + char *path1, *path2, *tmp; + int pflag, lflag, iflag, cmdnum, i; + unsigned long n_arg; + Attrib a, *aa; + char path_buf[MAXPATHLEN]; + int err = 0; + glob_t g; + + path1 = path2 = NULL; + cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &n_arg, + &path1, &path2); + + if (iflag != 0) + err_abort = 0; + + memset(&g, 0, sizeof(g)); + + /* Perform command */ + switch (cmdnum) { + case 0: + /* Blank line */ + break; + case -1: + /* Unrecognized command */ + err = -1; + break; + case I_GET: + err = process_get(conn, path1, path2, *pwd, pflag); + break; + case I_PUT: + err = process_put(conn, path1, path2, *pwd, pflag); + break; + case I_RENAME: + path1 = make_absolute(path1, *pwd); + path2 = make_absolute(path2, *pwd); + err = do_rename(conn, path1, path2); + break; + case I_SYMLINK: + path2 = make_absolute(path2, *pwd); + err = do_symlink(conn, path1, path2); + break; + case I_RM: + path1 = make_absolute(path1, *pwd); + remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + printf("Removing %s\n", g.gl_pathv[i]); + err = do_rm(conn, g.gl_pathv[i]); + if (err != 0 && err_abort) + break; + } + break; + case I_MKDIR: + path1 = make_absolute(path1, *pwd); + attrib_clear(&a); + a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + a.perm = 0777; + err = do_mkdir(conn, path1, &a); + break; + case I_RMDIR: + path1 = make_absolute(path1, *pwd); + err = do_rmdir(conn, path1); + break; + case I_CHDIR: + path1 = make_absolute(path1, *pwd); + if ((tmp = do_realpath(conn, path1)) == NULL) { + err = 1; + break; + } + if ((aa = do_stat(conn, tmp, 0)) == NULL) { + xfree(tmp); + err = 1; + break; + } + if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { + error("Can't change directory: Can't check target"); + xfree(tmp); + err = 1; + break; + } + if (!S_ISDIR(aa->perm)) { + error("Can't change directory: \"%s\" is not " + "a directory", tmp); + xfree(tmp); + err = 1; + break; + } + xfree(*pwd); + *pwd = tmp; + break; + case I_LS: + if (!path1) { + do_globbed_ls(conn, *pwd, *pwd, lflag); + break; + } + + /* Strip pwd off beginning of non-absolute paths */ + tmp = NULL; + if (*path1 != '/') + tmp = *pwd; + + path1 = make_absolute(path1, *pwd); + err = do_globbed_ls(conn, path1, tmp, lflag); + break; + case I_LCHDIR: + if (chdir(path1) == -1) { + error("Couldn't change local directory to " + "\"%s\": %s", path1, strerror(errno)); + err = 1; + } + break; + case I_LMKDIR: + if (mkdir(path1, 0777) == -1) { + error("Couldn't create local directory " + "\"%s\": %s", path1, strerror(errno)); + err = 1; + } + break; + case I_LLS: + local_do_ls(cmd); + break; + case I_SHELL: + local_do_shell(cmd); + break; + case I_LUMASK: + umask(n_arg); + printf("Local umask: %03lo\n", n_arg); + break; + case I_CHMOD: + path1 = make_absolute(path1, *pwd); + attrib_clear(&a); + a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; + a.perm = n_arg; + remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + printf("Changing mode on %s\n", g.gl_pathv[i]); + err = do_setstat(conn, g.gl_pathv[i], &a); + if (err != 0 && err_abort) + break; + } + break; + case I_CHOWN: + case I_CHGRP: + path1 = make_absolute(path1, *pwd); + remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); + for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) { + if (err != 0 && err_abort) + break; + else + continue; + } + if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { + error("Can't get current ownership of " + "remote file \"%s\"", g.gl_pathv[i]); + if (err != 0 && err_abort) + break; + else + continue; + } + aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; + if (cmdnum == I_CHOWN) { + printf("Changing owner on %s\n", g.gl_pathv[i]); + aa->uid = n_arg; + } else { + printf("Changing group on %s\n", g.gl_pathv[i]); + aa->gid = n_arg; + } + err = do_setstat(conn, g.gl_pathv[i], aa); + if (err != 0 && err_abort) + break; + } + break; + case I_PWD: + printf("Remote working directory: %s\n", *pwd); + break; + case I_LPWD: + if (!getcwd(path_buf, sizeof(path_buf))) { + error("Couldn't get local cwd: %s", strerror(errno)); + err = -1; + break; + } + printf("Local working directory: %s\n", path_buf); + break; + case I_QUIT: + /* Processed below */ + break; + case I_HELP: + help(); + break; + case I_VERSION: + printf("SFTP protocol version %u\n", sftp_proto_version(conn)); + break; + case I_PROGRESS: + showprogress = !showprogress; + if (showprogress) + printf("Progress meter enabled\n"); + else + printf("Progress meter disabled\n"); + break; + default: + fatal("%d is not implemented", cmdnum); + } + + if (g.gl_pathc) + globfree(&g); + if (path1) + xfree(path1); + if (path2) + xfree(path2); + + /* If an unignored error occurs in batch mode we should abort. */ + if (err_abort && err != 0) + return (-1); + else if (cmdnum == I_QUIT) + return (1); + + return (0); +} + +int +interactive_loop(int fd_in, int fd_out, char *file1, char *file2) +{ + char *pwd; + char *dir = NULL; + char cmd[2048]; + struct sftp_conn *conn; + int err; + + conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests); + if (conn == NULL) + fatal("Couldn't initialise connection to server"); + + pwd = do_realpath(conn, "."); + if (pwd == NULL) + fatal("Need cwd"); + + if (file1 != NULL) { + dir = xstrdup(file1); + dir = make_absolute(dir, pwd); + + if (remote_is_dir(conn, dir) && file2 == NULL) { + printf("Changing to: %s\n", dir); + snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); + if (parse_dispatch_command(conn, cmd, &pwd, 1) != 0) + return (-1); + } else { + if (file2 == NULL) + snprintf(cmd, sizeof cmd, "get %s", dir); + else + snprintf(cmd, sizeof cmd, "get %s %s", dir, + file2); + + err = parse_dispatch_command(conn, cmd, &pwd, 1); + xfree(dir); + xfree(pwd); + return (err); + } + xfree(dir); + } + +#if HAVE_SETVBUF + setvbuf(stdout, NULL, _IOLBF, 0); + setvbuf(infile, NULL, _IOLBF, 0); +#else + setlinebuf(stdout); + setlinebuf(infile); +#endif + + err = 0; + for (;;) { + char *cp; + + signal(SIGINT, SIG_IGN); + + printf("sftp> "); + + /* XXX: use libedit */ + if (fgets(cmd, sizeof(cmd), infile) == NULL) { + printf("\n"); + break; + } + + if (batchmode) /* Echo command */ + printf("%s", cmd); + + cp = strrchr(cmd, '\n'); + if (cp) + *cp = '\0'; + + /* Handle user interrupts gracefully during commands */ + interrupted = 0; + signal(SIGINT, cmd_interrupt); + + err = parse_dispatch_command(conn, cmd, &pwd, batchmode); + if (err != 0) + break; + } + xfree(pwd); + + /* err == 1 signifies normal "quit" exit */ + return (err >= 0 ? 0 : -1); +} + +static void +connect_to_server(char *path, char **args, int *in, int *out) +{ + int c_in, c_out; + +#ifdef USE_PIPES + int pin[2], pout[2]; + + if ((pipe(pin) == -1) || (pipe(pout) == -1)) + fatal("pipe: %s", strerror(errno)); + *in = pin[0]; + *out = pout[1]; + c_in = pout[0]; + c_out = pin[1]; +#else /* USE_PIPES */ + int inout[2]; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) + fatal("socketpair: %s", strerror(errno)); + *in = *out = inout[0]; + c_in = c_out = inout[1]; +#endif /* USE_PIPES */ + + if ((sshpid = fork()) == -1) + fatal("fork: %s", strerror(errno)); + else if (sshpid == 0) { + if ((dup2(c_in, STDIN_FILENO) == -1) || + (dup2(c_out, STDOUT_FILENO) == -1)) { + fprintf(stderr, "dup2: %s\n", strerror(errno)); + _exit(1); + } + close(*in); + close(*out); + close(c_in); + close(c_out); + + /* + * The underlying ssh is in the same process group, so we must + * ignore SIGINT if we want to gracefully abort commands, + * otherwise the signal will make it to the ssh process and + * kill it too + */ + signal(SIGINT, SIG_IGN); + execvp(path, args); + fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); + _exit(1); + } + + signal(SIGTERM, killchild); + signal(SIGINT, killchild); + signal(SIGHUP, killchild); + close(c_in); + close(c_out); +} + +static void +usage(void) +{ + extern char *__progname; + + fprintf(stderr, + "usage: %s [-1Cv] [-B buffer_size] [-b batchfile] [-F ssh_config]\n" + " [-o ssh_option] [-P sftp_server_path] [-R num_requests]\n" + " [-S program] [-s subsystem | sftp_server] host\n" + " %s [[user@]host[:file [file]]]\n" + " %s [[user@]host[:dir[/]]]\n" + " %s -b batchfile [user@]host\n", __progname, __progname, __progname, __progname); + exit(1); +} + +int +main(int argc, char **argv) +{ + int in, out, ch, err; + char *host, *userhost, *cp, *file2 = NULL; + int debug_level = 0, sshver = 2; + char *file1 = NULL, *sftp_server = NULL; + char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; + LogLevel ll = SYSLOG_LEVEL_INFO; + arglist args; + extern int optind; + extern char *optarg; + + __progname = ssh_get_progname(argv[0]); + args.list = NULL; + addargs(&args, "ssh"); /* overwritten with ssh_program */ + addargs(&args, "-oForwardX11 no"); + addargs(&args, "-oForwardAgent no"); + addargs(&args, "-oClearAllForwardings yes"); + + ll = SYSLOG_LEVEL_INFO; + infile = stdin; + + while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { + switch (ch) { + case 'C': + addargs(&args, "-C"); + break; + case 'v': + if (debug_level < 3) { + addargs(&args, "-v"); + ll = SYSLOG_LEVEL_DEBUG1 + debug_level; + } + debug_level++; + break; + case 'F': + case 'o': + addargs(&args, "-%c%s", ch, optarg); + break; + case '1': + sshver = 1; + if (sftp_server == NULL) + sftp_server = _PATH_SFTP_SERVER; + break; + case 's': + sftp_server = optarg; + break; + case 'S': + ssh_program = optarg; + break; + case 'b': + if (batchmode) + fatal("Batch file already specified."); + + /* Allow "-" as stdin */ + if (strcmp(optarg, "-") != 0 && + (infile = fopen(optarg, "r")) == NULL) + fatal("%s (%s).", strerror(errno), optarg); + showprogress = 0; + batchmode = 1; + break; + case 'P': + sftp_direct = optarg; + break; + case 'B': + copy_buffer_len = strtol(optarg, &cp, 10); + if (copy_buffer_len == 0 || *cp != '\0') + fatal("Invalid buffer size \"%s\"", optarg); + break; + case 'R': + num_requests = strtol(optarg, &cp, 10); + if (num_requests == 0 || *cp != '\0') + fatal("Invalid number of requests \"%s\"", + optarg); + break; + case 'h': + default: + usage(); + } + } + + if (!isatty(STDERR_FILENO)) + showprogress = 0; + + log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); + + if (sftp_direct == NULL) { + if (optind == argc || argc > (optind + 2)) + usage(); + + userhost = xstrdup(argv[optind]); + file2 = argv[optind+1]; + + if ((host = strrchr(userhost, '@')) == NULL) + host = userhost; + else { + *host++ = '\0'; + if (!userhost[0]) { + fprintf(stderr, "Missing username\n"); + usage(); + } + addargs(&args, "-l%s",userhost); + } + + if ((cp = colon(host)) != NULL) { + *cp++ = '\0'; + file1 = cp; + } + + host = cleanhostname(host); + if (!*host) { + fprintf(stderr, "Missing hostname\n"); + usage(); + } + + addargs(&args, "-oProtocol %d", sshver); + + /* no subsystem if the server-spec contains a '/' */ + if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) + addargs(&args, "-s"); + + addargs(&args, "%s", host); + addargs(&args, "%s", (sftp_server != NULL ? + sftp_server : "sftp")); + args.list[0] = ssh_program; + + if (!batchmode) + fprintf(stderr, "Connecting to %s...\n", host); + connect_to_server(ssh_program, args.list, &in, &out); + } else { + args.list = NULL; + addargs(&args, "sftp-server"); + + if (!batchmode) + fprintf(stderr, "Attaching to %s...\n", sftp_direct); + connect_to_server(sftp_direct, args.list, &in, &out); + } + + err = interactive_loop(in, out, file1, file2); + +#if !defined(USE_PIPES) + shutdown(in, SHUT_RDWR); + shutdown(out, SHUT_RDWR); +#endif + + close(in); + close(out); + if (batchmode) + fclose(infile); + + while (waitpid(sshpid, NULL, 0) == -1) + if (errno != EINTR) + fatal("Couldn't wait for ssh process: %s", + strerror(errno)); + + exit(err == 0 ? 0 : 1); +} diff --git a/crypto/openssh-3.9p1/sftp.h b/crypto/openssh-3.9p1/sftp.h new file mode 100644 index 0000000000..675c6086e9 --- /dev/null +++ b/crypto/openssh-3.9p1/sftp.h @@ -0,0 +1,92 @@ +/* $OpenBSD: sftp.h,v 1.4 2002/02/13 00:59:23 djm Exp $ */ + +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * draft-ietf-secsh-filexfer-01.txt + */ + +/* version */ +#define SSH2_FILEXFER_VERSION 3 + +/* client to server */ +#define SSH2_FXP_INIT 1 +#define SSH2_FXP_OPEN 3 +#define SSH2_FXP_CLOSE 4 +#define SSH2_FXP_READ 5 +#define SSH2_FXP_WRITE 6 +#define SSH2_FXP_LSTAT 7 +#define SSH2_FXP_STAT_VERSION_0 7 +#define SSH2_FXP_FSTAT 8 +#define SSH2_FXP_SETSTAT 9 +#define SSH2_FXP_FSETSTAT 10 +#define SSH2_FXP_OPENDIR 11 +#define SSH2_FXP_READDIR 12 +#define SSH2_FXP_REMOVE 13 +#define SSH2_FXP_MKDIR 14 +#define SSH2_FXP_RMDIR 15 +#define SSH2_FXP_REALPATH 16 +#define SSH2_FXP_STAT 17 +#define SSH2_FXP_RENAME 18 +#define SSH2_FXP_READLINK 19 +#define SSH2_FXP_SYMLINK 20 + +/* server to client */ +#define SSH2_FXP_VERSION 2 +#define SSH2_FXP_STATUS 101 +#define SSH2_FXP_HANDLE 102 +#define SSH2_FXP_DATA 103 +#define SSH2_FXP_NAME 104 +#define SSH2_FXP_ATTRS 105 + +#define SSH2_FXP_EXTENDED 200 +#define SSH2_FXP_EXTENDED_REPLY 201 + +/* attributes */ +#define SSH2_FILEXFER_ATTR_SIZE 0x00000001 +#define SSH2_FILEXFER_ATTR_UIDGID 0x00000002 +#define SSH2_FILEXFER_ATTR_PERMISSIONS 0x00000004 +#define SSH2_FILEXFER_ATTR_ACMODTIME 0x00000008 +#define SSH2_FILEXFER_ATTR_EXTENDED 0x80000000 + +/* portable open modes */ +#define SSH2_FXF_READ 0x00000001 +#define SSH2_FXF_WRITE 0x00000002 +#define SSH2_FXF_APPEND 0x00000004 +#define SSH2_FXF_CREAT 0x00000008 +#define SSH2_FXF_TRUNC 0x00000010 +#define SSH2_FXF_EXCL 0x00000020 + +/* status messages */ +#define SSH2_FX_OK 0 +#define SSH2_FX_EOF 1 +#define SSH2_FX_NO_SUCH_FILE 2 +#define SSH2_FX_PERMISSION_DENIED 3 +#define SSH2_FX_FAILURE 4 +#define SSH2_FX_BAD_MESSAGE 5 +#define SSH2_FX_NO_CONNECTION 6 +#define SSH2_FX_CONNECTION_LOST 7 +#define SSH2_FX_OP_UNSUPPORTED 8 +#define SSH2_FX_MAX 8 diff --git a/crypto/openssh-3.9p1/ssh-add.1 b/crypto/openssh-3.9p1/ssh-add.1 new file mode 100644 index 0000000000..6348197b33 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-add.1 @@ -0,0 +1,174 @@ +.\" $OpenBSD: ssh-add.1,v 1.40 2003/11/25 23:10:08 matthieu Exp $ +.\" +.\" -*- nroff -*- +.\" +.\" Author: Tatu Ylonen +.\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +.\" All rights reserved +.\" +.\" 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". +.\" +.\" +.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. +.\" Copyright (c) 1999 Aaron Campbell. All rights reserved. +.\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd September 25, 1999 +.Dt SSH-ADD 1 +.Os +.Sh NAME +.Nm ssh-add +.Nd adds RSA or DSA identities to the authentication agent +.Sh SYNOPSIS +.Nm ssh-add +.Op Fl lLdDxXc +.Op Fl t Ar life +.Op Ar +.Nm ssh-add +.Fl s Ar reader +.Nm ssh-add +.Fl e Ar reader +.Sh DESCRIPTION +.Nm +adds RSA or DSA identities to the authentication agent, +.Xr ssh-agent 1 . +When run without arguments, it adds the files +.Pa $HOME/.ssh/id_rsa , +.Pa $HOME/.ssh/id_dsa +and +.Pa $HOME/.ssh/identity . +Alternative file names can be given on the command line. +If any file requires a passphrase, +.Nm +asks for the passphrase from the user. +The passphrase is read from the user's tty. +.Nm +retries the last passphrase if multiple identity files are given. +.Pp +The authentication agent must be running and the +.Ev SSH_AUTH_SOCK +environment variable must contain the name of its socket for +.Nm +to work. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl l +Lists fingerprints of all identities currently represented by the agent. +.It Fl L +Lists public key parameters of all identities currently represented by the agent. +.It Fl d +Instead of adding the identity, removes the identity from the agent. +.It Fl D +Deletes all identities from the agent. +.It Fl x +Lock the agent with a password. +.It Fl X +Unlock the agent. +.It Fl t Ar life +Set a maximum lifetime when adding identities to an agent. +The lifetime may be specified in seconds or in a time format +specified in +.Xr sshd_config 5 . +.It Fl c +Indicates that added identities should be subject to confirmation before +being used for authentication. +Confirmation is performed by the +.Ev SSH_ASKPASS +program mentioned below. +Successful confirmation is signaled by a zero exit status from the +.Ev SSH_ASKPASS +program, rather than text entered into the requester. +.It Fl s Ar reader +Add key in smartcard +.Ar reader . +.It Fl e Ar reader +Remove key in smartcard +.Ar reader . +.El +.Sh ENVIRONMENT +.Bl -tag -width Ds +.It Ev "DISPLAY" and "SSH_ASKPASS" +If +.Nm +needs a passphrase, it will read the passphrase from the current +terminal if it was run from a terminal. +If +.Nm +does not have a terminal associated with it but +.Ev DISPLAY +and +.Ev SSH_ASKPASS +are set, it will execute the program specified by +.Ev SSH_ASKPASS +and open an X11 window to read the passphrase. +This is particularly useful when calling +.Nm +from a +.Pa .Xsession +or related script. +(Note that on some machines it +may be necessary to redirect the input from +.Pa /dev/null +to make this work.) +.It Ev SSH_AUTH_SOCK +Identifies the path of a unix-domain socket used to communicate with the +agent. +.El +.Sh FILES +.Bl -tag -width Ds +.It Pa $HOME/.ssh/identity +Contains the protocol version 1 RSA authentication identity of the user. +.It Pa $HOME/.ssh/id_dsa +Contains the protocol version 2 DSA authentication identity of the user. +.It Pa $HOME/.ssh/id_rsa +Contains the protocol version 2 RSA authentication identity of the user. +.El +.Pp +Identity files should not be readable by anyone but the user. +Note that +.Nm +ignores identity files if they are accessible by others. +.Sh DIAGNOSTICS +Exit status is 0 on success, 1 if the specified command fails, +and 2 if +.Nm +is unable to contact the authentication agent. +.Sh SEE ALSO +.Xr ssh 1 , +.Xr ssh-agent 1 , +.Xr ssh-keygen 1 , +.Xr sshd 8 +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. diff --git a/crypto/openssh-3.9p1/ssh-add.c b/crypto/openssh-3.9p1/ssh-add.c new file mode 100644 index 0000000000..06a52464e0 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-add.c @@ -0,0 +1,415 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Adds an identity to the authentication server, or removes an identity. + * + * 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". + * + * SSH2 implementation, + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh-add.c,v 1.70 2004/05/08 00:21:31 djm Exp $"); + +#include + +#include "ssh.h" +#include "rsa.h" +#include "log.h" +#include "xmalloc.h" +#include "key.h" +#include "authfd.h" +#include "authfile.h" +#include "pathnames.h" +#include "misc.h" + +/* argv0 */ +extern char *__progname; + +/* Default files to add */ +static char *default_files[] = { + _PATH_SSH_CLIENT_ID_RSA, + _PATH_SSH_CLIENT_ID_DSA, + _PATH_SSH_CLIENT_IDENTITY, + NULL +}; + +/* Default lifetime (0 == forever) */ +static int lifetime = 0; + +/* User has to confirm key use */ +static int confirm = 0; + +/* we keep a cache of one passphrases */ +static char *pass = NULL; +static void +clear_pass(void) +{ + if (pass) { + memset(pass, 0, strlen(pass)); + xfree(pass); + pass = NULL; + } +} + +static int +delete_file(AuthenticationConnection *ac, const char *filename) +{ + Key *public; + char *comment = NULL; + int ret = -1; + + public = key_load_public(filename, &comment); + if (public == NULL) { + printf("Bad key file %s\n", filename); + return -1; + } + if (ssh_remove_identity(ac, public)) { + fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment); + ret = 0; + } else + fprintf(stderr, "Could not remove identity: %s\n", filename); + + key_free(public); + xfree(comment); + + return ret; +} + +/* Send a request to remove all identities. */ +static int +delete_all(AuthenticationConnection *ac) +{ + int ret = -1; + + if (ssh_remove_all_identities(ac, 1)) + ret = 0; + /* ignore error-code for ssh2 */ + ssh_remove_all_identities(ac, 2); + + if (ret == 0) + fprintf(stderr, "All identities removed.\n"); + else + fprintf(stderr, "Failed to remove all identities.\n"); + + return ret; +} + +static int +add_file(AuthenticationConnection *ac, const char *filename) +{ + struct stat st; + Key *private; + char *comment = NULL; + char msg[1024]; + int ret = -1; + + if (stat(filename, &st) < 0) { + perror(filename); + return -1; + } + /* At first, try empty passphrase */ + private = key_load_private(filename, "", &comment); + if (comment == NULL) + comment = xstrdup(filename); + /* try last */ + if (private == NULL && pass != NULL) + private = key_load_private(filename, pass, NULL); + if (private == NULL) { + /* clear passphrase since it did not work */ + clear_pass(); + snprintf(msg, sizeof msg, "Enter passphrase for %.200s: ", + comment); + for (;;) { + pass = read_passphrase(msg, RP_ALLOW_STDIN); + if (strcmp(pass, "") == 0) { + clear_pass(); + xfree(comment); + return -1; + } + private = key_load_private(filename, pass, &comment); + if (private != NULL) + break; + clear_pass(); + snprintf(msg, sizeof msg, + "Bad passphrase, try again for %.200s: ", comment); + } + } + + if (ssh_add_identity_constrained(ac, private, comment, lifetime, + confirm)) { + fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); + ret = 0; + if (lifetime != 0) + fprintf(stderr, + "Lifetime set to %d seconds\n", lifetime); + if (confirm != 0) + fprintf(stderr, + "The user has to confirm each use of the key\n"); + } else if (ssh_add_identity(ac, private, comment)) { + fprintf(stderr, "Identity added: %s (%s)\n", filename, comment); + ret = 0; + } else { + fprintf(stderr, "Could not add identity: %s\n", filename); + } + + xfree(comment); + key_free(private); + + return ret; +} + +static int +update_card(AuthenticationConnection *ac, int add, const char *id) +{ + char *pin; + int ret = -1; + + pin = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN); + if (pin == NULL) + return -1; + + if (ssh_update_card(ac, add, id, pin, lifetime, confirm)) { + fprintf(stderr, "Card %s: %s\n", + add ? "added" : "removed", id); + ret = 0; + } else { + fprintf(stderr, "Could not %s card: %s\n", + add ? "add" : "remove", id); + ret = -1; + } + xfree(pin); + return ret; +} + +static int +list_identities(AuthenticationConnection *ac, int do_fp) +{ + Key *key; + char *comment, *fp; + int had_identities = 0; + int version; + + for (version = 1; version <= 2; version++) { + for (key = ssh_get_first_identity(ac, &comment, version); + key != NULL; + key = ssh_get_next_identity(ac, &comment, version)) { + had_identities = 1; + if (do_fp) { + fp = key_fingerprint(key, SSH_FP_MD5, + SSH_FP_HEX); + printf("%d %s %s (%s)\n", + key_size(key), fp, comment, key_type(key)); + xfree(fp); + } else { + if (!key_write(key, stdout)) + fprintf(stderr, "key_write failed"); + fprintf(stdout, " %s\n", comment); + } + key_free(key); + xfree(comment); + } + } + if (!had_identities) { + printf("The agent has no identities.\n"); + return -1; + } + return 0; +} + +static int +lock_agent(AuthenticationConnection *ac, int lock) +{ + char prompt[100], *p1, *p2; + int passok = 1, ret = -1; + + strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); + p1 = read_passphrase(prompt, RP_ALLOW_STDIN); + if (lock) { + strlcpy(prompt, "Again: ", sizeof prompt); + p2 = read_passphrase(prompt, RP_ALLOW_STDIN); + if (strcmp(p1, p2) != 0) { + fprintf(stderr, "Passwords do not match.\n"); + passok = 0; + } + memset(p2, 0, strlen(p2)); + xfree(p2); + } + if (passok && ssh_lock_agent(ac, lock, p1)) { + fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); + ret = 0; + } else + fprintf(stderr, "Failed to %slock agent.\n", lock ? "" : "un"); + memset(p1, 0, strlen(p1)); + xfree(p1); + return (ret); +} + +static int +do_file(AuthenticationConnection *ac, int deleting, char *file) +{ + if (deleting) { + if (delete_file(ac, file) == -1) + return -1; + } else { + if (add_file(ac, file) == -1) + return -1; + } + return 0; +} + +static void +usage(void) +{ + fprintf(stderr, "Usage: %s [options]\n", __progname); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -l List fingerprints of all identities.\n"); + fprintf(stderr, " -L List public key parameters of all identities.\n"); + fprintf(stderr, " -d Delete identity.\n"); + fprintf(stderr, " -D Delete all identities.\n"); + fprintf(stderr, " -x Lock agent.\n"); + fprintf(stderr, " -X Unlock agent.\n"); + fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); + fprintf(stderr, " -c Require confirmation to sign using identities\n"); +#ifdef SMARTCARD + fprintf(stderr, " -s reader Add key in smartcard reader.\n"); + fprintf(stderr, " -e reader Remove key in smartcard reader.\n"); +#endif +} + +int +main(int argc, char **argv) +{ + extern char *optarg; + extern int optind; + AuthenticationConnection *ac = NULL; + char *sc_reader_id = NULL; + int i, ch, deleting = 0, ret = 0; + + __progname = ssh_get_progname(argv[0]); + init_rng(); + seed_rng(); + + SSLeay_add_all_algorithms(); + + /* At first, get a connection to the authentication agent. */ + ac = ssh_get_authentication_connection(); + if (ac == NULL) { + fprintf(stderr, "Could not open a connection to your authentication agent.\n"); + exit(2); + } + while ((ch = getopt(argc, argv, "lLcdDxXe:s:t:")) != -1) { + switch (ch) { + case 'l': + case 'L': + if (list_identities(ac, ch == 'l' ? 1 : 0) == -1) + ret = 1; + goto done; + break; + case 'x': + case 'X': + if (lock_agent(ac, ch == 'x' ? 1 : 0) == -1) + ret = 1; + goto done; + break; + case 'c': + confirm = 1; + break; + case 'd': + deleting = 1; + break; + case 'D': + if (delete_all(ac) == -1) + ret = 1; + goto done; + break; + case 's': + sc_reader_id = optarg; + break; + case 'e': + deleting = 1; + sc_reader_id = optarg; + break; + case 't': + if ((lifetime = convtime(optarg)) == -1) { + fprintf(stderr, "Invalid lifetime\n"); + ret = 1; + goto done; + } + break; + default: + usage(); + ret = 1; + goto done; + } + } + argc -= optind; + argv += optind; + if (sc_reader_id != NULL) { + if (update_card(ac, !deleting, sc_reader_id) == -1) + ret = 1; + goto done; + } + if (argc == 0) { + char buf[MAXPATHLEN]; + struct passwd *pw; + struct stat st; + int count = 0; + + if ((pw = getpwuid(getuid())) == NULL) { + fprintf(stderr, "No user found with uid %u\n", + (u_int)getuid()); + ret = 1; + goto done; + } + + for(i = 0; default_files[i]; i++) { + snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, + default_files[i]); + if (stat(buf, &st) < 0) + continue; + if (do_file(ac, deleting, buf) == -1) + ret = 1; + else + count++; + } + if (count == 0) + ret = 1; + } else { + for(i = 0; i < argc; i++) { + if (do_file(ac, deleting, argv[i]) == -1) + ret = 1; + } + } + clear_pass(); + +done: + ssh_close_authentication_connection(ac); + return ret; +} diff --git a/crypto/openssh-3.9p1/ssh-agent.1 b/crypto/openssh-3.9p1/ssh-agent.1 new file mode 100644 index 0000000000..226804e5f0 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-agent.1 @@ -0,0 +1,207 @@ +.\" $OpenBSD: ssh-agent.1,v 1.41 2004/07/11 17:48:47 deraadt Exp $ +.\" +.\" Author: Tatu Ylonen +.\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +.\" All rights reserved +.\" +.\" 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". +.\" +.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. +.\" Copyright (c) 1999 Aaron Campbell. All rights reserved. +.\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd September 25, 1999 +.Dt SSH-AGENT 1 +.Os +.Sh NAME +.Nm ssh-agent +.Nd authentication agent +.Sh SYNOPSIS +.Nm ssh-agent +.Op Fl a Ar bind_address +.Op Fl c Li | Fl s +.Op Fl t Ar life +.Op Fl d +.Op Ar command Op Ar args ... +.Nm ssh-agent +.Op Fl c Li | Fl s +.Fl k +.Sh DESCRIPTION +.Nm +is a program to hold private keys used for public key authentication +(RSA, DSA). +The idea is that +.Nm +is started in the beginning of an X-session or a login session, and +all other windows or programs are started as clients to the ssh-agent +program. +Through use of environment variables the agent can be located +and automatically used for authentication when logging in to other +machines using +.Xr ssh 1 . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a Ar bind_address +Bind the agent to the unix-domain socket +.Ar bind_address . +The default is +.Pa /tmp/ssh-XXXXXXXX/agent. . +.It Fl c +Generate C-shell commands on +.Dv stdout . +This is the default if +.Ev SHELL +looks like it's a csh style of shell. +.It Fl s +Generate Bourne shell commands on +.Dv stdout . +This is the default if +.Ev SHELL +does not look like it's a csh style of shell. +.It Fl k +Kill the current agent (given by the +.Ev SSH_AGENT_PID +environment variable). +.It Fl t Ar life +Set a default value for the maximum lifetime of identities added to the agent. +The lifetime may be specified in seconds or in a time format specified in +.Xr sshd 8 . +A lifetime specified for an identity with +.Xr ssh-add 1 +overrides this value. +Without this option the default maximum lifetime is forever. +.It Fl d +Debug mode. +When this option is specified +.Nm +will not fork. +.El +.Pp +If a commandline is given, this is executed as a subprocess of the agent. +When the command dies, so does the agent. +.Pp +The agent initially does not have any private keys. +Keys are added using +.Xr ssh-add 1 . +When executed without arguments, +.Xr ssh-add 1 +adds the files +.Pa $HOME/.ssh/id_rsa , +.Pa $HOME/.ssh/id_dsa +and +.Pa $HOME/.ssh/identity . +If the identity has a passphrase, +.Xr ssh-add 1 +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. +.Ic ssh-add -l +displays the identities currently held by the agent. +.Pp +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 SSH +remote logins, and the user can thus use the privileges given by the +identities anywhere in the network in a secure way. +.Pp +There are two main ways to get an agent set up: +The first is that the agent starts a new subcommand into which some environment +variables are exported, eg +.Cm ssh-agent xterm & . +The second is that the agent prints the needed shell commands (either +.Xr sh 1 +or +.Xr csh 1 +syntax can be generated) which can be evalled in the calling shell, eg +.Cm eval `ssh-agent -s` +for Bourne-type shells such as +.Xr sh 1 +or +.Xr ksh 1 +and +.Cm eval `ssh-agent -c` +for +.Xr csh 1 +and derivatives. +.Pp +Later +.Xr ssh 1 +looks at these variables and uses them to establish a connection to the agent. +.Pp +The agent will never send a private key over its request channel. +Instead, operations that require a private key will be performed +by the agent, and the result will be returned to the requester. +This way, private keys are not exposed to clients using the agent. +.Pp +A unix-domain socket is created +and the name of this socket is stored in the +.Ev SSH_AUTH_SOCK +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. +.Pp +The +.Ev SSH_AGENT_PID +environment variable holds the agent's process ID. +.Pp +The agent exits automatically when the command given on the command +line terminates. +.Sh FILES +.Bl -tag -width Ds +.It Pa $HOME/.ssh/identity +Contains the protocol version 1 RSA authentication identity of the user. +.It Pa $HOME/.ssh/id_dsa +Contains the protocol version 2 DSA authentication identity of the user. +.It Pa $HOME/.ssh/id_rsa +Contains the protocol version 2 RSA authentication identity of the user. +.It Pa /tmp/ssh-XXXXXXXX/agent. +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. +.El +.Sh SEE ALSO +.Xr ssh 1 , +.Xr ssh-add 1 , +.Xr ssh-keygen 1 , +.Xr sshd 8 +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. diff --git a/crypto/openssh-3.9p1/ssh-agent.c b/crypto/openssh-3.9p1/ssh-agent.c new file mode 100644 index 0000000000..bc4d8d33a2 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-agent.c @@ -0,0 +1,1239 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * The authentication agent program. + * + * 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". + * + * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +#include "openbsd-compat/sys-queue.h" +RCSID("$OpenBSD: ssh-agent.c,v 1.120 2004/08/11 21:43:05 avsm Exp $"); + +#include +#include + +#include "ssh.h" +#include "rsa.h" +#include "buffer.h" +#include "bufaux.h" +#include "xmalloc.h" +#include "getput.h" +#include "key.h" +#include "authfd.h" +#include "compat.h" +#include "log.h" +#include "misc.h" + +#ifdef SMARTCARD +#include "scard.h" +#endif + +#if defined(HAVE_SYS_PRCTL_H) +#include /* For prctl() and PR_SET_DUMPABLE */ +#endif + +typedef enum { + AUTH_UNUSED, + AUTH_SOCKET, + AUTH_CONNECTION +} sock_type; + +typedef struct { + int fd; + sock_type type; + Buffer input; + Buffer output; + Buffer request; +} SocketEntry; + +u_int sockets_alloc = 0; +SocketEntry *sockets = NULL; + +typedef struct identity { + TAILQ_ENTRY(identity) next; + Key *key; + char *comment; + u_int death; + u_int confirm; +} Identity; + +typedef struct { + int nentries; + TAILQ_HEAD(idqueue, identity) idlist; +} Idtab; + +/* private key table, one per protocol version */ +Idtab idtable[3]; + +int max_fd = 0; + +/* pid of shell == parent of agent */ +pid_t parent_pid = -1; + +/* pathname and directory for AUTH_SOCKET */ +char socket_name[1024]; +char socket_dir[1024]; + +/* locking */ +int locked = 0; +char *lock_passwd = NULL; + +extern char *__progname; + +/* Default lifetime (0 == forever) */ +static int lifetime = 0; + +static void +close_socket(SocketEntry *e) +{ + close(e->fd); + e->fd = -1; + e->type = AUTH_UNUSED; + buffer_free(&e->input); + buffer_free(&e->output); + buffer_free(&e->request); +} + +static void +idtab_init(void) +{ + int i; + + for (i = 0; i <=2; i++) { + TAILQ_INIT(&idtable[i].idlist); + idtable[i].nentries = 0; + } +} + +/* return private key table for requested protocol version */ +static Idtab * +idtab_lookup(int version) +{ + if (version < 1 || version > 2) + fatal("internal error, bad protocol version %d", version); + return &idtable[version]; +} + +static void +free_identity(Identity *id) +{ + key_free(id->key); + xfree(id->comment); + xfree(id); +} + +/* return matching private key for given public key */ +static Identity * +lookup_identity(Key *key, int version) +{ + Identity *id; + + Idtab *tab = idtab_lookup(version); + TAILQ_FOREACH(id, &tab->idlist, next) { + if (key_equal(key, id->key)) + return (id); + } + return (NULL); +} + +/* Check confirmation of keysign request */ +static int +confirm_key(Identity *id) +{ + char *p, prompt[1024]; + int ret = -1; + + p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX); + snprintf(prompt, sizeof(prompt), "Allow use of key %s?\n" + "Key fingerprint %s.", id->comment, p); + xfree(p); + p = read_passphrase(prompt, RP_ALLOW_EOF); + if (p != NULL) { + /* + * Accept empty responses and responses consisting + * of the word "yes" as affirmative. + */ + if (*p == '\0' || *p == '\n' || strcasecmp(p, "yes") == 0) + ret = 0; + xfree(p); + } + return (ret); +} + +/* send list of supported public keys to 'client' */ +static void +process_request_identities(SocketEntry *e, int version) +{ + Idtab *tab = idtab_lookup(version); + Identity *id; + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, (version == 1) ? + SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER); + buffer_put_int(&msg, tab->nentries); + TAILQ_FOREACH(id, &tab->idlist, next) { + if (id->key->type == KEY_RSA1) { + buffer_put_int(&msg, BN_num_bits(id->key->rsa->n)); + buffer_put_bignum(&msg, id->key->rsa->e); + buffer_put_bignum(&msg, id->key->rsa->n); + } else { + u_char *blob; + u_int blen; + key_to_blob(id->key, &blob, &blen); + buffer_put_string(&msg, blob, blen); + xfree(blob); + } + buffer_put_cstring(&msg, id->comment); + } + buffer_put_int(&e->output, buffer_len(&msg)); + buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); + buffer_free(&msg); +} + +/* ssh1 only */ +static void +process_authentication_challenge1(SocketEntry *e) +{ + u_char buf[32], mdbuf[16], session_id[16]; + u_int response_type; + BIGNUM *challenge; + Identity *id; + int i, len; + Buffer msg; + MD5_CTX md; + Key *key; + + buffer_init(&msg); + key = key_new(KEY_RSA1); + if ((challenge = BN_new()) == NULL) + fatal("process_authentication_challenge1: BN_new failed"); + + (void) buffer_get_int(&e->request); /* ignored */ + buffer_get_bignum(&e->request, key->rsa->e); + buffer_get_bignum(&e->request, key->rsa->n); + buffer_get_bignum(&e->request, challenge); + + /* Only protocol 1.1 is supported */ + if (buffer_len(&e->request) == 0) + goto failure; + buffer_get(&e->request, session_id, 16); + response_type = buffer_get_int(&e->request); + if (response_type != 1) + goto failure; + + id = lookup_identity(key, 1); + if (id != NULL && (!id->confirm || confirm_key(id) == 0)) { + Key *private = id->key; + /* Decrypt the challenge using the private key. */ + if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0) + goto failure; + + /* The response is MD5 of decrypted challenge plus session id. */ + len = BN_num_bytes(challenge); + if (len <= 0 || len > 32) { + logit("process_authentication_challenge: bad challenge length %d", len); + goto failure; + } + memset(buf, 0, 32); + BN_bn2bin(challenge, buf + 32 - len); + MD5_Init(&md); + MD5_Update(&md, buf, 32); + MD5_Update(&md, session_id, 16); + MD5_Final(mdbuf, &md); + + /* 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; + } + +failure: + /* Unknown identity or protocol error. 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)); + key_free(key); + BN_clear_free(challenge); + buffer_free(&msg); +} + +/* ssh2 only */ +static void +process_sign_request2(SocketEntry *e) +{ + u_char *blob, *data, *signature = NULL; + u_int blen, dlen, slen = 0; + extern int datafellows; + int ok = -1, flags; + Buffer msg; + Key *key; + + datafellows = 0; + + blob = buffer_get_string(&e->request, &blen); + data = buffer_get_string(&e->request, &dlen); + + flags = buffer_get_int(&e->request); + if (flags & SSH_AGENT_OLD_SIGNATURE) + datafellows = SSH_BUG_SIGBLOB; + + key = key_from_blob(blob, blen); + if (key != NULL) { + Identity *id = lookup_identity(key, 2); + if (id != NULL && (!id->confirm || confirm_key(id) == 0)) + ok = key_sign(id->key, &signature, &slen, data, dlen); + } + key_free(key); + buffer_init(&msg); + if (ok == 0) { + buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE); + buffer_put_string(&msg, signature, slen); + } else { + buffer_put_char(&msg, SSH_AGENT_FAILURE); + } + buffer_put_int(&e->output, buffer_len(&msg)); + buffer_append(&e->output, buffer_ptr(&msg), + buffer_len(&msg)); + buffer_free(&msg); + xfree(data); + xfree(blob); + if (signature != NULL) + xfree(signature); +} + +/* shared */ +static void +process_remove_identity(SocketEntry *e, int version) +{ + u_int blen, bits; + int success = 0; + Key *key = NULL; + u_char *blob; + + switch (version) { + case 1: + key = key_new(KEY_RSA1); + bits = buffer_get_int(&e->request); + buffer_get_bignum(&e->request, key->rsa->e); + buffer_get_bignum(&e->request, key->rsa->n); + + if (bits != key_size(key)) + logit("Warning: identity keysize mismatch: actual %u, announced %u", + key_size(key), bits); + break; + case 2: + blob = buffer_get_string(&e->request, &blen); + key = key_from_blob(blob, blen); + xfree(blob); + break; + } + if (key != NULL) { + Identity *id = lookup_identity(key, version); + if (id != NULL) { + /* + * 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 move + * all the entries between the empty slot and the end + * of the array. + */ + Idtab *tab = idtab_lookup(version); + if (tab->nentries < 1) + fatal("process_remove_identity: " + "internal error: tab->nentries %d", + tab->nentries); + TAILQ_REMOVE(&tab->idlist, id, next); + free_identity(id); + tab->nentries--; + success = 1; + } + key_free(key); + } + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, + success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); +} + +static void +process_remove_all_identities(SocketEntry *e, int version) +{ + Idtab *tab = idtab_lookup(version); + Identity *id; + + /* Loop over all identities and clear the keys. */ + for (id = TAILQ_FIRST(&tab->idlist); id; + id = TAILQ_FIRST(&tab->idlist)) { + TAILQ_REMOVE(&tab->idlist, id, next); + free_identity(id); + } + + /* Mark that there are no identities. */ + tab->nentries = 0; + + /* Send success. */ + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_SUCCESS); +} + +static void +reaper(void) +{ + u_int now = time(NULL); + Identity *id, *nxt; + int version; + Idtab *tab; + + for (version = 1; version < 3; version++) { + tab = idtab_lookup(version); + for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) { + nxt = TAILQ_NEXT(id, next); + if (id->death != 0 && now >= id->death) { + TAILQ_REMOVE(&tab->idlist, id, next); + free_identity(id); + tab->nentries--; + } + } + } +} + +static void +process_add_identity(SocketEntry *e, int version) +{ + Idtab *tab = idtab_lookup(version); + int type, success = 0, death = 0, confirm = 0; + char *type_name, *comment; + Key *k = NULL; + + switch (version) { + case 1: + k = key_new_private(KEY_RSA1); + (void) buffer_get_int(&e->request); /* ignored */ + buffer_get_bignum(&e->request, k->rsa->n); + buffer_get_bignum(&e->request, k->rsa->e); + buffer_get_bignum(&e->request, k->rsa->d); + buffer_get_bignum(&e->request, k->rsa->iqmp); + + /* SSH and SSL have p and q swapped */ + buffer_get_bignum(&e->request, k->rsa->q); /* p */ + buffer_get_bignum(&e->request, k->rsa->p); /* q */ + + /* Generate additional parameters */ + rsa_generate_additional_parameters(k->rsa); + break; + case 2: + type_name = buffer_get_string(&e->request, NULL); + type = key_type_from_name(type_name); + xfree(type_name); + switch (type) { + case KEY_DSA: + k = key_new_private(type); + buffer_get_bignum2(&e->request, k->dsa->p); + buffer_get_bignum2(&e->request, k->dsa->q); + buffer_get_bignum2(&e->request, k->dsa->g); + buffer_get_bignum2(&e->request, k->dsa->pub_key); + buffer_get_bignum2(&e->request, k->dsa->priv_key); + break; + case KEY_RSA: + k = key_new_private(type); + buffer_get_bignum2(&e->request, k->rsa->n); + buffer_get_bignum2(&e->request, k->rsa->e); + buffer_get_bignum2(&e->request, k->rsa->d); + buffer_get_bignum2(&e->request, k->rsa->iqmp); + buffer_get_bignum2(&e->request, k->rsa->p); + buffer_get_bignum2(&e->request, k->rsa->q); + + /* Generate additional parameters */ + rsa_generate_additional_parameters(k->rsa); + break; + default: + buffer_clear(&e->request); + goto send; + } + break; + } + /* enable blinding */ + switch (k->type) { + case KEY_RSA: + case KEY_RSA1: + if (RSA_blinding_on(k->rsa, NULL) != 1) { + error("process_add_identity: RSA_blinding_on failed"); + key_free(k); + goto send; + } + break; + } + comment = buffer_get_string(&e->request, NULL); + if (k == NULL) { + xfree(comment); + goto send; + } + success = 1; + while (buffer_len(&e->request)) { + switch (buffer_get_char(&e->request)) { + case SSH_AGENT_CONSTRAIN_LIFETIME: + death = time(NULL) + buffer_get_int(&e->request); + break; + case SSH_AGENT_CONSTRAIN_CONFIRM: + confirm = 1; + break; + default: + break; + } + } + if (lifetime && !death) + death = time(NULL) + lifetime; + if (lookup_identity(k, version) == NULL) { + Identity *id = xmalloc(sizeof(Identity)); + id->key = k; + id->comment = comment; + id->death = death; + id->confirm = confirm; + TAILQ_INSERT_TAIL(&tab->idlist, id, next); + /* Increment the number of identities. */ + tab->nentries++; + } else { + key_free(k); + xfree(comment); + } +send: + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, + success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); +} + +/* XXX todo: encrypt sensitive data with passphrase */ +static void +process_lock_agent(SocketEntry *e, int lock) +{ + int success = 0; + char *passwd; + + passwd = buffer_get_string(&e->request, NULL); + if (locked && !lock && strcmp(passwd, lock_passwd) == 0) { + locked = 0; + memset(lock_passwd, 0, strlen(lock_passwd)); + xfree(lock_passwd); + lock_passwd = NULL; + success = 1; + } else if (!locked && lock) { + locked = 1; + lock_passwd = xstrdup(passwd); + success = 1; + } + memset(passwd, 0, strlen(passwd)); + xfree(passwd); + + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, + success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); +} + +static void +no_identities(SocketEntry *e, u_int type) +{ + Buffer msg; + + buffer_init(&msg); + buffer_put_char(&msg, + (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ? + SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER); + buffer_put_int(&msg, 0); + buffer_put_int(&e->output, buffer_len(&msg)); + buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg)); + buffer_free(&msg); +} + +#ifdef SMARTCARD +static void +process_add_smartcard_key (SocketEntry *e) +{ + char *sc_reader_id = NULL, *pin; + int i, version, success = 0, death = 0, confirm = 0; + Key **keys, *k; + Identity *id; + Idtab *tab; + + sc_reader_id = buffer_get_string(&e->request, NULL); + pin = buffer_get_string(&e->request, NULL); + + while (buffer_len(&e->request)) { + switch (buffer_get_char(&e->request)) { + case SSH_AGENT_CONSTRAIN_LIFETIME: + death = time(NULL) + buffer_get_int(&e->request); + break; + case SSH_AGENT_CONSTRAIN_CONFIRM: + confirm = 1; + break; + default: + break; + } + } + if (lifetime && !death) + death = time(NULL) + lifetime; + + keys = sc_get_keys(sc_reader_id, pin); + xfree(sc_reader_id); + xfree(pin); + + if (keys == NULL || keys[0] == NULL) { + error("sc_get_keys failed"); + goto send; + } + for (i = 0; keys[i] != NULL; i++) { + k = keys[i]; + version = k->type == KEY_RSA1 ? 1 : 2; + tab = idtab_lookup(version); + if (lookup_identity(k, version) == NULL) { + id = xmalloc(sizeof(Identity)); + id->key = k; + id->comment = sc_get_key_label(k); + id->death = death; + id->confirm = confirm; + TAILQ_INSERT_TAIL(&tab->idlist, id, next); + tab->nentries++; + success = 1; + } else { + key_free(k); + } + keys[i] = NULL; + } + xfree(keys); +send: + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, + success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); +} + +static void +process_remove_smartcard_key(SocketEntry *e) +{ + char *sc_reader_id = NULL, *pin; + int i, version, success = 0; + Key **keys, *k = NULL; + Identity *id; + Idtab *tab; + + sc_reader_id = buffer_get_string(&e->request, NULL); + pin = buffer_get_string(&e->request, NULL); + keys = sc_get_keys(sc_reader_id, pin); + xfree(sc_reader_id); + xfree(pin); + + if (keys == NULL || keys[0] == NULL) { + error("sc_get_keys failed"); + goto send; + } + for (i = 0; keys[i] != NULL; i++) { + k = keys[i]; + version = k->type == KEY_RSA1 ? 1 : 2; + if ((id = lookup_identity(k, version)) != NULL) { + tab = idtab_lookup(version); + TAILQ_REMOVE(&tab->idlist, id, next); + tab->nentries--; + free_identity(id); + success = 1; + } + key_free(k); + keys[i] = NULL; + } + xfree(keys); +send: + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, + success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE); +} +#endif /* SMARTCARD */ + +/* dispatch incoming messages */ + +static void +process_message(SocketEntry *e) +{ + u_int msg_len, type; + u_char *cp; + + /* kill dead keys */ + reaper(); + + if (buffer_len(&e->input) < 5) + return; /* Incomplete message. */ + cp = buffer_ptr(&e->input); + msg_len = GET_32BIT(cp); + if (msg_len > 256 * 1024) { + close_socket(e); + return; + } + if (buffer_len(&e->input) < msg_len + 4) + return; + + /* move the current input to e->request */ + buffer_consume(&e->input, 4); + buffer_clear(&e->request); + buffer_append(&e->request, buffer_ptr(&e->input), msg_len); + buffer_consume(&e->input, msg_len); + type = buffer_get_char(&e->request); + + /* check wheter agent is locked */ + if (locked && type != SSH_AGENTC_UNLOCK) { + buffer_clear(&e->request); + switch (type) { + case SSH_AGENTC_REQUEST_RSA_IDENTITIES: + case SSH2_AGENTC_REQUEST_IDENTITIES: + /* send empty lists */ + no_identities(e, type); + break; + default: + /* send a fail message for all other request types */ + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_FAILURE); + } + return; + } + + debug("type %d", type); + switch (type) { + case SSH_AGENTC_LOCK: + case SSH_AGENTC_UNLOCK: + process_lock_agent(e, type == SSH_AGENTC_LOCK); + break; + /* ssh1 */ + case SSH_AGENTC_RSA_CHALLENGE: + process_authentication_challenge1(e); + break; + case SSH_AGENTC_REQUEST_RSA_IDENTITIES: + process_request_identities(e, 1); + break; + case SSH_AGENTC_ADD_RSA_IDENTITY: + case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED: + process_add_identity(e, 1); + break; + case SSH_AGENTC_REMOVE_RSA_IDENTITY: + process_remove_identity(e, 1); + break; + case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES: + process_remove_all_identities(e, 1); + break; + /* ssh2 */ + case SSH2_AGENTC_SIGN_REQUEST: + process_sign_request2(e); + break; + case SSH2_AGENTC_REQUEST_IDENTITIES: + process_request_identities(e, 2); + break; + case SSH2_AGENTC_ADD_IDENTITY: + case SSH2_AGENTC_ADD_ID_CONSTRAINED: + process_add_identity(e, 2); + break; + case SSH2_AGENTC_REMOVE_IDENTITY: + process_remove_identity(e, 2); + break; + case SSH2_AGENTC_REMOVE_ALL_IDENTITIES: + process_remove_all_identities(e, 2); + break; +#ifdef SMARTCARD + case SSH_AGENTC_ADD_SMARTCARD_KEY: + case SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED: + process_add_smartcard_key(e); + break; + case SSH_AGENTC_REMOVE_SMARTCARD_KEY: + process_remove_smartcard_key(e); + break; +#endif /* SMARTCARD */ + default: + /* Unknown message. Respond with failure. */ + error("Unknown message %d", type); + buffer_clear(&e->request); + buffer_put_int(&e->output, 1); + buffer_put_char(&e->output, SSH_AGENT_FAILURE); + break; + } +} + +static void +new_socket(sock_type type, int fd) +{ + u_int i, old_alloc, new_alloc; + + set_nonblock(fd); + + if (fd > max_fd) + max_fd = fd; + + for (i = 0; i < sockets_alloc; i++) + if (sockets[i].type == AUTH_UNUSED) { + sockets[i].fd = fd; + buffer_init(&sockets[i].input); + buffer_init(&sockets[i].output); + buffer_init(&sockets[i].request); + sockets[i].type = type; + return; + } + old_alloc = sockets_alloc; + new_alloc = sockets_alloc + 10; + if (sockets) + sockets = xrealloc(sockets, new_alloc * sizeof(sockets[0])); + else + sockets = xmalloc(new_alloc * sizeof(sockets[0])); + for (i = old_alloc; i < new_alloc; i++) + sockets[i].type = AUTH_UNUSED; + sockets_alloc = new_alloc; + sockets[old_alloc].fd = fd; + buffer_init(&sockets[old_alloc].input); + buffer_init(&sockets[old_alloc].output); + buffer_init(&sockets[old_alloc].request); + sockets[old_alloc].type = type; +} + +static int +prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, u_int *nallocp) +{ + u_int i, sz; + int n = 0; + + for (i = 0; i < sockets_alloc; i++) { + switch (sockets[i].type) { + case AUTH_SOCKET: + case AUTH_CONNECTION: + n = MAX(n, sockets[i].fd); + break; + case AUTH_UNUSED: + break; + default: + fatal("Unknown socket type %d", sockets[i].type); + break; + } + } + + sz = howmany(n+1, NFDBITS) * sizeof(fd_mask); + if (*fdrp == NULL || sz > *nallocp) { + if (*fdrp) + xfree(*fdrp); + if (*fdwp) + xfree(*fdwp); + *fdrp = xmalloc(sz); + *fdwp = xmalloc(sz); + *nallocp = sz; + } + if (n < *fdl) + debug("XXX shrink: %d < %d", n, *fdl); + *fdl = n; + memset(*fdrp, 0, sz); + memset(*fdwp, 0, sz); + + for (i = 0; i < sockets_alloc; i++) { + switch (sockets[i].type) { + case AUTH_SOCKET: + case AUTH_CONNECTION: + FD_SET(sockets[i].fd, *fdrp); + if (buffer_len(&sockets[i].output) > 0) + FD_SET(sockets[i].fd, *fdwp); + break; + default: + break; + } + } + return (1); +} + +static void +after_select(fd_set *readset, fd_set *writeset) +{ + struct sockaddr_un sunaddr; + socklen_t slen; + char buf[1024]; + int len, sock; + u_int i; + uid_t euid; + gid_t egid; + + for (i = 0; i < sockets_alloc; i++) + switch (sockets[i].type) { + case AUTH_UNUSED: + break; + case AUTH_SOCKET: + if (FD_ISSET(sockets[i].fd, readset)) { + slen = sizeof(sunaddr); + sock = accept(sockets[i].fd, + (struct sockaddr *) &sunaddr, &slen); + if (sock < 0) { + error("accept from AUTH_SOCKET: %s", + strerror(errno)); + break; + } + if (getpeereid(sock, &euid, &egid) < 0) { + error("getpeereid %d failed: %s", + sock, strerror(errno)); + close(sock); + break; + } + if ((euid != 0) && (getuid() != euid)) { + error("uid mismatch: " + "peer euid %u != uid %u", + (u_int) euid, (u_int) getuid()); + close(sock); + break; + } + new_socket(AUTH_CONNECTION, sock); + } + break; + case AUTH_CONNECTION: + if (buffer_len(&sockets[i].output) > 0 && + FD_ISSET(sockets[i].fd, writeset)) { + do { + len = write(sockets[i].fd, + buffer_ptr(&sockets[i].output), + buffer_len(&sockets[i].output)); + if (len == -1 && (errno == EAGAIN || + errno == EINTR)) + continue; + break; + } while (1); + if (len <= 0) { + close_socket(&sockets[i]); + break; + } + buffer_consume(&sockets[i].output, len); + } + if (FD_ISSET(sockets[i].fd, readset)) { + do { + len = read(sockets[i].fd, buf, sizeof(buf)); + if (len == -1 && (errno == EAGAIN || + errno == EINTR)) + continue; + break; + } while (1); + if (len <= 0) { + close_socket(&sockets[i]); + break; + } + buffer_append(&sockets[i].input, buf, len); + process_message(&sockets[i]); + } + break; + default: + fatal("Unknown type %d", sockets[i].type); + } +} + +static void +cleanup_socket(void) +{ + if (socket_name[0]) + unlink(socket_name); + if (socket_dir[0]) + rmdir(socket_dir); +} + +void +cleanup_exit(int i) +{ + cleanup_socket(); + _exit(i); +} + +static void +cleanup_handler(int sig) +{ + cleanup_socket(); + _exit(2); +} + +static void +check_parent_exists(int sig) +{ + int save_errno = errno; + + if (parent_pid != -1 && kill(parent_pid, 0) < 0) { + /* printf("Parent has died - Authentication agent exiting.\n"); */ + cleanup_handler(sig); /* safe */ + } + mysignal(SIGALRM, check_parent_exists); + alarm(10); + errno = save_errno; +} + +static void +usage(void) +{ + fprintf(stderr, "Usage: %s [options] [command [args ...]]\n", + __progname); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -c Generate C-shell commands on stdout.\n"); + fprintf(stderr, " -s Generate Bourne shell commands on stdout.\n"); + fprintf(stderr, " -k Kill the current agent.\n"); + fprintf(stderr, " -d Debug mode.\n"); + fprintf(stderr, " -a socket Bind agent socket to given name.\n"); + fprintf(stderr, " -t life Default identity lifetime (seconds).\n"); + exit(1); +} + +int +main(int ac, char **av) +{ + int c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0; + int sock, fd, ch; + u_int nalloc; + char *shell, *format, *pidstr, *agentsocket = NULL; + fd_set *readsetp = NULL, *writesetp = NULL; + struct sockaddr_un sunaddr; +#ifdef HAVE_SETRLIMIT + struct rlimit rlim; +#endif +#ifdef HAVE_CYGWIN + int prev_mask; +#endif + extern int optind; + extern char *optarg; + pid_t pid; + char pidstrbuf[1 + 3 * sizeof pid]; + + /* drop */ + setegid(getgid()); + setgid(getgid()); + +#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) + /* Disable ptrace on Linux without sgid bit */ + prctl(PR_SET_DUMPABLE, 0); +#endif + + SSLeay_add_all_algorithms(); + + __progname = ssh_get_progname(av[0]); + init_rng(); + seed_rng(); + + while ((ch = getopt(ac, av, "cdksa:t:")) != -1) { + switch (ch) { + case 'c': + if (s_flag) + usage(); + c_flag++; + break; + case 'k': + k_flag++; + break; + case 's': + if (c_flag) + usage(); + s_flag++; + break; + case 'd': + if (d_flag) + usage(); + d_flag++; + break; + case 'a': + agentsocket = optarg; + break; + case 't': + if ((lifetime = convtime(optarg)) == -1) { + fprintf(stderr, "Invalid lifetime\n"); + usage(); + } + break; + default: + usage(); + } + } + ac -= optind; + av += optind; + + if (ac > 0 && (c_flag || k_flag || s_flag || d_flag)) + usage(); + + if (ac == 0 && !c_flag && !s_flag) { + shell = getenv("SHELL"); + if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0) + c_flag = 1; + } + if (k_flag) { + pidstr = getenv(SSH_AGENTPID_ENV_NAME); + if (pidstr == NULL) { + fprintf(stderr, "%s not set, cannot kill agent\n", + SSH_AGENTPID_ENV_NAME); + exit(1); + } + pid = atoi(pidstr); + if (pid < 1) { + fprintf(stderr, "%s=\"%s\", which is not a good PID\n", + SSH_AGENTPID_ENV_NAME, pidstr); + exit(1); + } + if (kill(pid, SIGTERM) == -1) { + perror("kill"); + exit(1); + } + format = c_flag ? "unsetenv %s;\n" : "unset %s;\n"; + printf(format, SSH_AUTHSOCKET_ENV_NAME); + printf(format, SSH_AGENTPID_ENV_NAME); + printf("echo Agent pid %ld killed;\n", (long)pid); + exit(0); + } + parent_pid = getpid(); + + if (agentsocket == NULL) { + /* Create private directory for agent socket */ + strlcpy(socket_dir, "/tmp/ssh-XXXXXXXXXX", sizeof socket_dir); + if (mkdtemp(socket_dir) == NULL) { + perror("mkdtemp: private socket dir"); + exit(1); + } + snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir, + (long)parent_pid); + } else { + /* Try to use specified agent socket */ + socket_dir[0] = '\0'; + strlcpy(socket_name, agentsocket, sizeof socket_name); + } + + /* + * Create socket early so it will exist before command gets run from + * the parent. + */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + perror("socket"); + cleanup_exit(1); + } + memset(&sunaddr, 0, sizeof(sunaddr)); + sunaddr.sun_family = AF_UNIX; + strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path)); +#ifdef HAVE_CYGWIN + prev_mask = umask(0177); +#endif + if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) { + perror("bind"); +#ifdef HAVE_CYGWIN + umask(prev_mask); +#endif + cleanup_exit(1); + } +#ifdef HAVE_CYGWIN + umask(prev_mask); +#endif + if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { + perror("listen"); + cleanup_exit(1); + } + + /* + * Fork, and have the parent execute the command, if any, or present + * the socket data. The child continues as the authentication agent. + */ + if (d_flag) { + log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1); + format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; + printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, + SSH_AUTHSOCKET_ENV_NAME); + printf("echo Agent pid %ld;\n", (long)parent_pid); + goto skip; + } + pid = fork(); + if (pid == -1) { + perror("fork"); + cleanup_exit(1); + } + if (pid != 0) { /* Parent - execute the given command. */ + close(sock); + snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid); + if (ac == 0) { + format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n"; + printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name, + SSH_AUTHSOCKET_ENV_NAME); + printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf, + SSH_AGENTPID_ENV_NAME); + printf("echo Agent pid %ld;\n", (long)pid); + exit(0); + } + if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 || + setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) { + perror("setenv"); + exit(1); + } + execvp(av[0], av); + perror(av[0]); + exit(1); + } + /* child */ + log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0); + + if (setsid() == -1) { + error("setsid: %s", strerror(errno)); + cleanup_exit(1); + } + + (void)chdir("/"); + if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + /* XXX might close listen socket */ + (void)dup2(fd, STDIN_FILENO); + (void)dup2(fd, STDOUT_FILENO); + (void)dup2(fd, STDERR_FILENO); + if (fd > 2) + close(fd); + } + +#ifdef HAVE_SETRLIMIT + /* deny core dumps, since memory contains unencrypted private keys */ + rlim.rlim_cur = rlim.rlim_max = 0; + if (setrlimit(RLIMIT_CORE, &rlim) < 0) { + error("setrlimit RLIMIT_CORE: %s", strerror(errno)); + cleanup_exit(1); + } +#endif + +skip: + new_socket(AUTH_SOCKET, sock); + if (ac > 0) { + mysignal(SIGALRM, check_parent_exists); + alarm(10); + } + idtab_init(); + if (!d_flag) + signal(SIGINT, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, cleanup_handler); + signal(SIGTERM, cleanup_handler); + nalloc = 0; + + while (1) { + prepare_select(&readsetp, &writesetp, &max_fd, &nalloc); + if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + fatal("select: %s", strerror(errno)); + } + after_select(readsetp, writesetp); + } + /* NOTREACHED */ +} diff --git a/crypto/openssh-3.9p1/ssh-dss.c b/crypto/openssh-3.9p1/ssh-dss.c new file mode 100644 index 0000000000..381b7dedb0 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-dss.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh-dss.c,v 1.19 2003/11/10 16:23:41 jakob Exp $"); + +#include +#include + +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" +#include "compat.h" +#include "log.h" +#include "key.h" + +#define INTBLOB_LEN 20 +#define SIGBLOB_LEN (2*INTBLOB_LEN) + +int +ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, + const u_char *data, u_int datalen) +{ + DSA_SIG *sig; + const EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + u_char digest[EVP_MAX_MD_SIZE], sigblob[SIGBLOB_LEN]; + u_int rlen, slen, len, dlen; + Buffer b; + + if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { + error("ssh_dss_sign: no DSA key"); + return -1; + } + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, &dlen); + + sig = DSA_do_sign(digest, dlen, key->dsa); + memset(digest, 'd', sizeof(digest)); + + if (sig == NULL) { + error("ssh_dss_sign: sign failed"); + return -1; + } + + rlen = BN_num_bytes(sig->r); + slen = BN_num_bytes(sig->s); + if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { + error("bad sig size %u %u", rlen, slen); + DSA_SIG_free(sig); + return -1; + } + memset(sigblob, 0, SIGBLOB_LEN); + BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); + BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); + DSA_SIG_free(sig); + + if (datafellows & SSH_BUG_SIGBLOB) { + if (lenp != NULL) + *lenp = SIGBLOB_LEN; + if (sigp != NULL) { + *sigp = xmalloc(SIGBLOB_LEN); + memcpy(*sigp, sigblob, SIGBLOB_LEN); + } + } else { + /* ietf-drafts */ + buffer_init(&b); + buffer_put_cstring(&b, "ssh-dss"); + buffer_put_string(&b, sigblob, SIGBLOB_LEN); + len = buffer_len(&b); + if (lenp != NULL) + *lenp = len; + if (sigp != NULL) { + *sigp = xmalloc(len); + memcpy(*sigp, buffer_ptr(&b), len); + } + buffer_free(&b); + } + return 0; +} +int +ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, + const u_char *data, u_int datalen) +{ + DSA_SIG *sig; + const EVP_MD *evp_md = EVP_sha1(); + EVP_MD_CTX md; + u_char digest[EVP_MAX_MD_SIZE], *sigblob; + u_int len, dlen; + int rlen, ret; + Buffer b; + + if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) { + error("ssh_dss_verify: no DSA key"); + return -1; + } + + /* fetch signature */ + if (datafellows & SSH_BUG_SIGBLOB) { + sigblob = xmalloc(signaturelen); + memcpy(sigblob, signature, signaturelen); + len = signaturelen; + } else { + /* ietf-drafts */ + char *ktype; + buffer_init(&b); + buffer_append(&b, signature, signaturelen); + ktype = buffer_get_string(&b, NULL); + if (strcmp("ssh-dss", ktype) != 0) { + error("ssh_dss_verify: cannot handle type %s", ktype); + buffer_free(&b); + xfree(ktype); + return -1; + } + xfree(ktype); + sigblob = buffer_get_string(&b, &len); + rlen = buffer_len(&b); + buffer_free(&b); + if (rlen != 0) { + error("ssh_dss_verify: " + "remaining bytes in signature %d", rlen); + xfree(sigblob); + return -1; + } + } + + if (len != SIGBLOB_LEN) { + fatal("bad sigbloblen %u != SIGBLOB_LEN", len); + } + + /* parse signature */ + if ((sig = DSA_SIG_new()) == NULL) + fatal("ssh_dss_verify: DSA_SIG_new failed"); + if ((sig->r = BN_new()) == NULL) + fatal("ssh_dss_verify: BN_new failed"); + if ((sig->s = BN_new()) == NULL) + fatal("ssh_dss_verify: BN_new failed"); + BN_bin2bn(sigblob, INTBLOB_LEN, sig->r); + BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s); + + /* clean up */ + memset(sigblob, 0, len); + xfree(sigblob); + + /* sha1 the data */ + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, &dlen); + + ret = DSA_do_verify(digest, dlen, sig, key->dsa); + memset(digest, 'd', sizeof(digest)); + + DSA_SIG_free(sig); + + debug("ssh_dss_verify: signature %s", + ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); + return ret; +} diff --git a/crypto/openssh-3.9p1/ssh-gss.h b/crypto/openssh-3.9p1/ssh-gss.h new file mode 100644 index 0000000000..52fb49a6f3 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-gss.h @@ -0,0 +1,133 @@ +/* $OpenBSD: ssh-gss.h,v 1.5 2004/06/21 17:36:31 avsm Exp $ */ +/* + * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SSH_GSS_H +#define _SSH_GSS_H + +#ifdef GSSAPI + +#include "buffer.h" + +#ifdef HAVE_GSSAPI_H +#include +#elif defined(HAVE_GSSAPI_GSSAPI_H) +#include +#endif + +#ifdef KRB5 +# ifndef HEIMDAL +# ifdef HAVE_GSSAPI_GENERIC_H +# include +# elif defined(HAVE_GSSAPI_GSSAPI_GENERIC_H) +# include +# endif + +/* MIT Kerberos doesn't seem to define GSS_NT_HOSTBASED_SERVICE */ + +#ifndef GSS_C_NT_HOSTBASED_SERVICE +#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#endif /* GSS_C_NT_... */ +#endif /* !HEIMDAL */ +#endif /* KRB5 */ + +/* draft-ietf-secsh-gsskeyex-06 */ +#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE 60 +#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61 +#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 +#define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64 +#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 +#define SSH2_MSG_USERAUTH_GSSAPI_MIC 66 + +#define SSH_GSS_OIDTYPE 0x06 + +typedef struct { + char *filename; + char *envvar; + char *envval; + void *data; +} ssh_gssapi_ccache; + +typedef struct { + gss_buffer_desc displayname; + gss_buffer_desc exportedname; + gss_cred_id_t creds; + struct ssh_gssapi_mech_struct *mech; + ssh_gssapi_ccache store; +} ssh_gssapi_client; + +typedef struct ssh_gssapi_mech_struct { + char *enc_name; + char *name; + gss_OID_desc oid; + int (*dochild) (ssh_gssapi_client *); + int (*userok) (ssh_gssapi_client *, char *); + int (*localname) (ssh_gssapi_client *, char **); + void (*storecreds) (ssh_gssapi_client *); +} ssh_gssapi_mech; + +typedef struct { + OM_uint32 major; /* both */ + OM_uint32 minor; /* both */ + gss_ctx_id_t context; /* both */ + gss_name_t name; /* both */ + gss_OID oid; /* client */ + gss_cred_id_t creds; /* server */ + gss_name_t client; /* server */ + gss_cred_id_t client_creds; /* server */ +} Gssctxt; + +extern ssh_gssapi_mech *supported_mechs[]; + +int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); +void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); +void ssh_gssapi_set_oid(Gssctxt *, gss_OID); +void ssh_gssapi_supported_oids(gss_OID_set *); +ssh_gssapi_mech *ssh_gssapi_get_ctype(Gssctxt *); + +OM_uint32 ssh_gssapi_import_name(Gssctxt *, const char *); +OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *); +OM_uint32 ssh_gssapi_init_ctx(Gssctxt *, int, + gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); +OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *, + gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); +OM_uint32 ssh_gssapi_getclient(Gssctxt *, ssh_gssapi_client *); +void ssh_gssapi_error(Gssctxt *); +char *ssh_gssapi_last_error(Gssctxt *, OM_uint32 *, OM_uint32 *); +void ssh_gssapi_build_ctx(Gssctxt **); +void ssh_gssapi_delete_ctx(Gssctxt **); +OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); +OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); +void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *); + +/* In the server */ +int ssh_gssapi_userok(char *name); +OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); +void ssh_gssapi_do_child(char ***, u_int *); +void ssh_gssapi_cleanup_creds(void); +void ssh_gssapi_storecreds(void); + +#endif /* GSSAPI */ + +#endif /* _SSH_GSS_H */ diff --git a/crypto/openssh-3.9p1/ssh-keygen.1 b/crypto/openssh-3.9p1/ssh-keygen.1 new file mode 100644 index 0000000000..c0f24dcd0b --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-keygen.1 @@ -0,0 +1,422 @@ +.\" $OpenBSD: ssh-keygen.1,v 1.63 2004/08/13 00:01:43 jmc Exp $ +.\" +.\" -*- nroff -*- +.\" +.\" Author: Tatu Ylonen +.\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +.\" All rights reserved +.\" +.\" 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". +.\" +.\" +.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. +.\" Copyright (c) 1999 Aaron Campbell. All rights reserved. +.\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd September 25, 1999 +.Dt SSH-KEYGEN 1 +.Os +.Sh NAME +.Nm ssh-keygen +.Nd authentication key generation, management and conversion +.Sh SYNOPSIS +.Nm ssh-keygen +.Bk -words +.Op Fl q +.Op Fl b Ar bits +.Fl t Ar type +.Op Fl N Ar new_passphrase +.Op Fl C Ar comment +.Op Fl f Ar output_keyfile +.Ek +.Nm ssh-keygen +.Fl p +.Op Fl P Ar old_passphrase +.Op Fl N Ar new_passphrase +.Op Fl f Ar keyfile +.Nm ssh-keygen +.Fl i +.Op Fl f Ar input_keyfile +.Nm ssh-keygen +.Fl e +.Op Fl f Ar input_keyfile +.Nm ssh-keygen +.Fl y +.Op Fl f Ar input_keyfile +.Nm ssh-keygen +.Fl c +.Op Fl P Ar passphrase +.Op Fl C Ar comment +.Op Fl f Ar keyfile +.Nm ssh-keygen +.Fl l +.Op Fl f Ar input_keyfile +.Nm ssh-keygen +.Fl B +.Op Fl f Ar input_keyfile +.Nm ssh-keygen +.Fl D Ar reader +.Nm ssh-keygen +.Fl U Ar reader +.Op Fl f Ar input_keyfile +.Nm ssh-keygen +.Fl r Ar hostname +.Op Fl f Ar input_keyfile +.Op Fl g +.Nm ssh-keygen +.Fl G Ar output_file +.Op Fl v +.Op Fl b Ar bits +.Op Fl M Ar memory +.Op Fl S Ar start_point +.Nm ssh-keygen +.Fl T Ar output_file +.Fl f Ar input_file +.Op Fl v +.Op Fl a Ar num_trials +.Op Fl W Ar generator +.Sh DESCRIPTION +.Nm +generates, manages and converts authentication keys for +.Xr ssh 1 . +.Nm +can create RSA keys for use by SSH protocol version 1 and RSA or DSA +keys for use by SSH protocol version 2. +The type of key to be generated is specified with the +.Fl t +option. +.Pp +.Nm +is also used to generate groups for use in Diffie-Hellman group +exchange (DH-GEX). +See the +.Sx MODULI GENERATION +section for details. +.Pp +Normally each user wishing to use SSH +with RSA or DSA authentication runs this once to create the authentication +key in +.Pa $HOME/.ssh/identity , +.Pa $HOME/.ssh/id_dsa +or +.Pa $HOME/.ssh/id_rsa . +Additionally, the system administrator may use this to generate host keys, +as seen in +.Pa /etc/rc . +.Pp +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 +.Dq .pub +appended. +The program also asks for a passphrase. +The passphrase may be empty to indicate no passphrase +(host keys must have an empty passphrase), or it may be a string of +arbitrary length. +A passphrase is similar to a password, except it can be a phrase with a +series of words, punctuation, numbers, whitespace, or any string of +characters you want. +Good passphrases are 10-30 characters long, are +not simple sentences or otherwise easily guessable (English +prose has only 1-2 bits of entropy per character, and provides very bad +passphrases), and contain a mix of upper and lowercase letters, +numbers, and non-alphanumeric characters. +The passphrase can be changed later by using the +.Fl p +option. +.Pp +There is no way to recover a lost passphrase. +If the passphrase is +lost or forgotten, a new key must be generated and copied to the +corresponding public key to other machines. +.Pp +For RSA1 keys, +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 +.Dq user@host +when the key is created, but can be changed using the +.Fl c +option. +.Pp +After a key is generated, instructions below detail where the keys +should be placed to be activated. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a Ar trials +Specifies the number of primality tests to perform when screening DH-GEX +candidates using the +.Fl T +command. +.It Fl b Ar bits +Specifies the number of bits in the key to create. +Minimum is 512 bits. +Generally, 1024 bits is considered sufficient. +The default is 1024 bits. +.It Fl c +Requests changing the comment in the private and public key files. +This operation is only supported for RSA1 keys. +The program will prompt for the file containing the private keys, for +the passphrase if the key has one, and for the new comment. +.It Fl e +This option will read a private or public OpenSSH key file and +print the key in a +.Sq SECSH Public Key File Format +to stdout. +This option allows exporting keys for use by several commercial +SSH implementations. +.It Fl g +Use generic DNS format when printing fingerprint resource records using the +.Fl r +command. +.It Fl f Ar filename +Specifies the filename of the key file. +.It Fl i +This option will read an unencrypted private (or public) key file +in SSH2-compatible format and print an OpenSSH compatible private +(or public) key to stdout. +.Nm +also reads the +.Sq SECSH Public Key File Format . +This option allows importing keys from several commercial +SSH implementations. +.It Fl l +Show fingerprint of specified public key file. +Private RSA1 keys are also supported. +For RSA and DSA keys +.Nm +tries to find the matching public key file and prints its fingerprint. +.It Fl 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. +.It Fl q +Silence +.Nm ssh-keygen . +Used by +.Pa /etc/rc +when creating a new key. +.It Fl y +This option will read a private +OpenSSH format file and print an OpenSSH public key to stdout. +.It Fl t Ar type +Specifies the type of the key to create. +The possible values are +.Dq rsa1 +for protocol version 1 and +.Dq rsa +or +.Dq dsa +for protocol version 2. +.It Fl B +Show the bubblebabble digest of specified private or public key file. +.It Fl C Ar comment +Provides the new comment. +.It Fl D Ar reader +Download the RSA public key stored in the smartcard in +.Ar reader . +.It Fl G Ar output_file +Generate candidate primes for DH-GEX. +These primes must be screened for +safety (using the +.Fl T +option) before use. +.It Fl M Ar memory +Specify the amount of memory to use (in megabytes) when generating +candidate moduli for DH-GEX. +.It Fl N Ar new_passphrase +Provides the new passphrase. +.It Fl P Ar passphrase +Provides the (old) passphrase. +.It Fl S Ar start +Specify start point (in hex) when generating candidate moduli for DH-GEX. +.It Fl T Ar output_file +Test DH group exchange candidate primes (generated using the +.Fl G +option) for safety. +.It Fl W Ar generator +Specify desired generator when testing candidate moduli for DH-GEX. +.It Fl U Ar reader +Upload an existing RSA private key into the smartcard in +.Ar reader . +.It Fl v +Verbose mode. +Causes +.Nm +to print debugging messages about its progress. +This is helpful for debugging moduli generation. +Multiple +.Fl v +options increase the verbosity. +The maximum is 3. +.It Fl r Ar hostname +Print the SSHFP fingerprint resource record named +.Ar hostname +for the specified public key file. +.El +.Sh MODULI GENERATION +.Nm +may be used to generate groups for the Diffie-Hellman Group Exchange +(DH-GEX) protocol. +Generating these groups is a two-step process: first, candidate +primes are generated using a fast, but memory intensive process. +These candidate primes are then tested for suitability (a CPU-intensive +process). +.Pp +Generation of primes is performed using the +.Fl G +option. +The desired length of the primes may be specified by the +.Fl b +option. +For example: +.Pp +.Dl ssh-keygen -G moduli-2048.candidates -b 2048 +.Pp +By default, the search for primes begins at a random point in the +desired length range. +This may be overridden using the +.Fl S +option, which specifies a different start point (in hex). +.Pp +Once a set of candidates have been generated, they must be tested for +suitability. +This may be performed using the +.Fl T +option. +In this mode +.Nm +will read candidates from standard input (or a file specified using the +.Fl f +option). +For example: +.Pp +.Dl ssh-keygen -T moduli-2048 -f moduli-2048.candidates +.Pp +By default, each candidate will be subjected to 100 primality tests. +This may be overridden using the +.Fl a +option. +The DH generator value will be chosen automatically for the +prime under consideration. +If a specific generator is desired, it may be requested using the +.Fl W +option. +Valid generator values are 2, 3 and 5. +.Pp +Screened DH groups may be installed in +.Pa /etc/moduli . +It is important that this file contains moduli of a range of bit lengths and +that both ends of a connection share common moduli. +.Sh FILES +.Bl -tag -width Ds +.It Pa $HOME/.ssh/identity +Contains the protocol version 1 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 3DES. +This file is not automatically accessed by +.Nm +but it is offered as the default file for the private key. +.Xr ssh 1 +will read this file when a login attempt is made. +.It Pa $HOME/.ssh/identity.pub +Contains the protocol version 1 RSA public key for authentication. +The contents of this file should be added to +.Pa $HOME/.ssh/authorized_keys +on all machines +where the user wishes to log in using RSA authentication. +There is no need to keep the contents of this file secret. +.It Pa $HOME/.ssh/id_dsa +Contains the protocol version 2 DSA 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 3DES. +This file is not automatically accessed by +.Nm +but it is offered as the default file for the private key. +.Xr ssh 1 +will read this file when a login attempt is made. +.It Pa $HOME/.ssh/id_dsa.pub +Contains the protocol version 2 DSA public key for authentication. +The contents of this file should be added to +.Pa $HOME/.ssh/authorized_keys +on all machines +where the user wishes to log in using public key authentication. +There is no need to keep the contents of this file secret. +.It Pa $HOME/.ssh/id_rsa +Contains the protocol version 2 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 3DES. +This file is not automatically accessed by +.Nm +but it is offered as the default file for the private key. +.Xr ssh 1 +will read this file when a login attempt is made. +.It Pa $HOME/.ssh/id_rsa.pub +Contains the protocol version 2 RSA public key for authentication. +The contents of this file should be added to +.Pa $HOME/.ssh/authorized_keys +on all machines +where the user wishes to log in using public key authentication. +There is no need to keep the contents of this file secret. +.It Pa /etc/moduli +Contains Diffie-Hellman groups used for DH-GEX. +The file format is described in +.Xr moduli 5 . +.El +.Sh SEE ALSO +.Xr ssh 1 , +.Xr ssh-add 1 , +.Xr ssh-agent 1 , +.Xr moduli 5 , +.Xr sshd 8 +.Rs +.%A J. Galbraith +.%A R. Thayer +.%T "SECSH Public Key File Format" +.%N draft-ietf-secsh-publickeyfile-01.txt +.%D March 2001 +.%O work in progress material +.Re +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. diff --git a/crypto/openssh-3.9p1/ssh-keygen.c b/crypto/openssh-3.9p1/ssh-keygen.c new file mode 100644 index 0000000000..d39e7d8811 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-keygen.c @@ -0,0 +1,1133 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Identity and host key generation and maintenance. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh-keygen.c,v 1.117 2004/07/11 17:48:47 deraadt Exp $"); + +#include +#include + +#include "xmalloc.h" +#include "key.h" +#include "rsa.h" +#include "authfile.h" +#include "uuencode.h" +#include "buffer.h" +#include "bufaux.h" +#include "pathnames.h" +#include "log.h" +#include "misc.h" + +#ifdef SMARTCARD +#include "scard.h" +#endif +#include "dns.h" + +/* Number of bits in the RSA/DSA 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; + +int quiet = 0; + +/* Flag indicating that we just want to see the key fingerprint */ +int print_fingerprint = 0; +int print_bubblebabble = 0; + +/* The identity file name, given on the command line or entered by the user. */ +char identity_file[1024]; +int have_identity = 0; + +/* 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; + +/* Dump public key file in format used by real and the original SSH 2 */ +int convert_to_ssh2 = 0; +int convert_from_ssh2 = 0; +int print_public = 0; +int print_generic = 0; + +char *key_type_name = NULL; + +/* argv0 */ +extern char *__progname; + +char hostname[MAXHOSTNAMELEN]; + +/* moduli.c */ +int gen_candidates(FILE *, int, int, BIGNUM *); +int prime_test(FILE *, FILE *, u_int32_t, u_int32_t); + +static void +ask_filename(struct passwd *pw, const char *prompt) +{ + char buf[1024]; + char *name = NULL; + + if (key_type_name == NULL) + name = _PATH_SSH_CLIENT_ID_RSA; + else + switch (key_type_from_name(key_type_name)) { + case KEY_RSA1: + name = _PATH_SSH_CLIENT_IDENTITY; + break; + case KEY_DSA: + name = _PATH_SSH_CLIENT_ID_DSA; + break; + case KEY_RSA: + name = _PATH_SSH_CLIENT_ID_RSA; + break; + default: + fprintf(stderr, "bad key type"); + exit(1); + break; + } + + snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); + fprintf(stderr, "%s (%s): ", prompt, identity_file); + if (fgets(buf, sizeof(buf), stdin) == NULL) + exit(1); + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + if (strcmp(buf, "") != 0) + strlcpy(identity_file, buf, sizeof(identity_file)); + have_identity = 1; +} + +static Key * +load_identity(char *filename) +{ + char *pass; + Key *prv; + + prv = key_load_private(filename, "", NULL); + if (prv == NULL) { + if (identity_passphrase) + pass = xstrdup(identity_passphrase); + else + pass = read_passphrase("Enter passphrase: ", + RP_ALLOW_STDIN); + prv = key_load_private(filename, pass, NULL); + memset(pass, 0, strlen(pass)); + xfree(pass); + } + return prv; +} + +#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" +#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" +#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" +#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb + +static void +do_convert_to_ssh2(struct passwd *pw) +{ + Key *k; + u_int len; + u_char *blob; + struct stat st; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + if ((k = key_load_public(identity_file, NULL)) == NULL) { + if ((k = load_identity(identity_file)) == NULL) { + fprintf(stderr, "load failed\n"); + exit(1); + } + } + if (k->type == KEY_RSA1) { + fprintf(stderr, "version 1 keys are not supported\n"); + exit(1); + } + if (key_to_blob(k, &blob, &len) <= 0) { + fprintf(stderr, "key_to_blob failed\n"); + exit(1); + } + fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); + fprintf(stdout, + "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n", + key_size(k), key_type(k), + pw->pw_name, hostname); + dump_base64(stdout, blob, len); + fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); + key_free(k); + xfree(blob); + exit(0); +} + +static void +buffer_get_bignum_bits(Buffer *b, BIGNUM *value) +{ + u_int bignum_bits = buffer_get_int(b); + u_int bytes = (bignum_bits + 7) / 8; + + if (buffer_len(b) < bytes) + fatal("buffer_get_bignum_bits: input buffer too small: " + "need %d have %d", bytes, buffer_len(b)); + BN_bin2bn(buffer_ptr(b), bytes, value); + buffer_consume(b, bytes); +} + +static Key * +do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) +{ + Buffer b; + Key *key = NULL; + char *type, *cipher; + u_char *sig, data[] = "abcde12345"; + int magic, rlen, ktype, i1, i2, i3, i4; + u_int slen; + u_long e; + + buffer_init(&b); + buffer_append(&b, blob, blen); + + magic = buffer_get_int(&b); + if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { + error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); + buffer_free(&b); + return NULL; + } + i1 = buffer_get_int(&b); + type = buffer_get_string(&b, NULL); + cipher = buffer_get_string(&b, NULL); + i2 = buffer_get_int(&b); + i3 = buffer_get_int(&b); + i4 = buffer_get_int(&b); + debug("ignore (%d %d %d %d)", i1,i2,i3,i4); + if (strcmp(cipher, "none") != 0) { + error("unsupported cipher %s", cipher); + xfree(cipher); + buffer_free(&b); + xfree(type); + return NULL; + } + xfree(cipher); + + if (strstr(type, "dsa")) { + ktype = KEY_DSA; + } else if (strstr(type, "rsa")) { + ktype = KEY_RSA; + } else { + xfree(type); + return NULL; + } + key = key_new_private(ktype); + xfree(type); + + switch (key->type) { + case KEY_DSA: + buffer_get_bignum_bits(&b, key->dsa->p); + buffer_get_bignum_bits(&b, key->dsa->g); + buffer_get_bignum_bits(&b, key->dsa->q); + buffer_get_bignum_bits(&b, key->dsa->pub_key); + buffer_get_bignum_bits(&b, key->dsa->priv_key); + break; + case KEY_RSA: + e = buffer_get_char(&b); + debug("e %lx", e); + if (e < 30) { + e <<= 8; + e += buffer_get_char(&b); + debug("e %lx", e); + e <<= 8; + e += buffer_get_char(&b); + debug("e %lx", e); + } + if (!BN_set_word(key->rsa->e, e)) { + buffer_free(&b); + key_free(key); + return NULL; + } + buffer_get_bignum_bits(&b, key->rsa->d); + buffer_get_bignum_bits(&b, key->rsa->n); + buffer_get_bignum_bits(&b, key->rsa->iqmp); + buffer_get_bignum_bits(&b, key->rsa->q); + buffer_get_bignum_bits(&b, key->rsa->p); + rsa_generate_additional_parameters(key->rsa); + break; + } + rlen = buffer_len(&b); + if (rlen != 0) + error("do_convert_private_ssh2_from_blob: " + "remaining bytes in key blob %d", rlen); + buffer_free(&b); + + /* try the key */ + key_sign(key, &sig, &slen, data, sizeof(data)); + key_verify(key, sig, slen, data, sizeof(data)); + xfree(sig); + return key; +} + +static void +do_convert_from_ssh2(struct passwd *pw) +{ + Key *k; + int blen; + u_int len; + char line[1024], *p; + u_char blob[8096]; + char encoded[8096]; + struct stat st; + int escaped = 0, private = 0, ok; + FILE *fp; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + fp = fopen(identity_file, "r"); + if (fp == NULL) { + perror(identity_file); + exit(1); + } + encoded[0] = '\0'; + while (fgets(line, sizeof(line), fp)) { + if (!(p = strchr(line, '\n'))) { + fprintf(stderr, "input line too long.\n"); + exit(1); + } + if (p > line && p[-1] == '\\') + escaped++; + if (strncmp(line, "----", 4) == 0 || + strstr(line, ": ") != NULL) { + if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) + private = 1; + if (strstr(line, " END ") != NULL) { + break; + } + /* fprintf(stderr, "ignore: %s", line); */ + continue; + } + if (escaped) { + escaped--; + /* fprintf(stderr, "escaped: %s", line); */ + continue; + } + *p = '\0'; + strlcat(encoded, line, sizeof(encoded)); + } + len = strlen(encoded); + if (((len % 4) == 3) && + (encoded[len-1] == '=') && + (encoded[len-2] == '=') && + (encoded[len-3] == '=')) + encoded[len-3] = '\0'; + blen = uudecode(encoded, blob, sizeof(blob)); + if (blen < 0) { + fprintf(stderr, "uudecode failed.\n"); + exit(1); + } + k = private ? + do_convert_private_ssh2_from_blob(blob, blen) : + key_from_blob(blob, blen); + if (k == NULL) { + fprintf(stderr, "decode blob failed.\n"); + exit(1); + } + ok = private ? + (k->type == KEY_DSA ? + PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : + PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) : + key_write(k, stdout); + if (!ok) { + fprintf(stderr, "key write failed"); + exit(1); + } + key_free(k); + if (!private) + fprintf(stdout, "\n"); + fclose(fp); + exit(0); +} + +static void +do_print_public(struct passwd *pw) +{ + Key *prv; + struct stat st; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + prv = load_identity(identity_file); + if (prv == NULL) { + fprintf(stderr, "load failed\n"); + exit(1); + } + if (!key_write(prv, stdout)) + fprintf(stderr, "key_write failed"); + key_free(prv); + fprintf(stdout, "\n"); + exit(0); +} + +#ifdef SMARTCARD +static void +do_upload(struct passwd *pw, const char *sc_reader_id) +{ + Key *prv = NULL; + struct stat st; + int ret; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + prv = load_identity(identity_file); + if (prv == NULL) { + error("load failed"); + exit(1); + } + ret = sc_put_key(prv, sc_reader_id); + key_free(prv); + if (ret < 0) + exit(1); + logit("loading key done"); + exit(0); +} + +static void +do_download(struct passwd *pw, const char *sc_reader_id) +{ + Key **keys = NULL; + int i; + + keys = sc_get_keys(sc_reader_id, NULL); + if (keys == NULL) + fatal("cannot read public key from smartcard"); + for (i = 0; keys[i]; i++) { + key_write(keys[i], stdout); + key_free(keys[i]); + fprintf(stdout, "\n"); + } + xfree(keys); + exit(0); +} +#endif /* SMARTCARD */ + +static void +do_fingerprint(struct passwd *pw) +{ + FILE *f; + Key *public; + char *comment = NULL, *cp, *ep, line[16*1024], *fp; + int i, skip = 0, num = 1, invalid = 1; + enum fp_rep rep; + enum fp_type fptype; + struct stat st; + + fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; + rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + public = key_load_public(identity_file, &comment); + if (public != NULL) { + fp = key_fingerprint(public, fptype, rep); + printf("%u %s %s\n", key_size(public), fp, comment); + key_free(public); + xfree(comment); + xfree(fp); + exit(0); + } + if (comment) + xfree(comment); + + f = fopen(identity_file, "r"); + if (f != NULL) { + while (fgets(line, sizeof(line), f)) { + i = strlen(line) - 1; + if (line[i] != '\n') { + error("line %d too long: %.40s...", num, line); + skip = 1; + continue; + } + num++; + if (skip) { + skip = 0; + continue; + } + line[i] = '\0'; + + /* Skip leading whitespace, empty and comment lines. */ + for (cp = line; *cp == ' ' || *cp == '\t'; cp++) + ; + if (!*cp || *cp == '\n' || *cp == '#') + continue ; + i = strtol(cp, &ep, 10); + if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { + int quoted = 0; + comment = cp; + for (; *cp && (quoted || (*cp != ' ' && + *cp != '\t')); cp++) { + if (*cp == '\\' && cp[1] == '"') + cp++; /* Skip both */ + else if (*cp == '"') + quoted = !quoted; + } + if (!*cp) + continue; + *cp++ = '\0'; + } + ep = cp; + public = key_new(KEY_RSA1); + if (key_read(public, &cp) != 1) { + cp = ep; + key_free(public); + public = key_new(KEY_UNSPEC); + if (key_read(public, &cp) != 1) { + key_free(public); + continue; + } + } + comment = *cp ? cp : comment; + fp = key_fingerprint(public, fptype, rep); + printf("%u %s %s\n", key_size(public), fp, + comment ? comment : "no comment"); + xfree(fp); + key_free(public); + invalid = 0; + } + fclose(f); + } + if (invalid) { + printf("%s is not a public key file.\n", identity_file); + exit(1); + } + exit(0); +} + +/* + * Perform changing a passphrase. The argument is the passwd structure + * for the current user. + */ +static void +do_change_passphrase(struct passwd *pw) +{ + char *comment; + char *old_passphrase, *passphrase1, *passphrase2; + struct stat st; + Key *private; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + /* Try to load the file with empty passphrase. */ + private = key_load_private(identity_file, "", &comment); + if (private == NULL) { + if (identity_passphrase) + old_passphrase = xstrdup(identity_passphrase); + else + old_passphrase = + read_passphrase("Enter old passphrase: ", + RP_ALLOW_STDIN); + private = key_load_private(identity_file, old_passphrase, + &comment); + memset(old_passphrase, 0, strlen(old_passphrase)); + xfree(old_passphrase); + if (private == NULL) { + printf("Bad passphrase.\n"); + exit(1); + } + } + 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): ", RP_ALLOW_STDIN); + passphrase2 = read_passphrase("Enter same passphrase again: ", + RP_ALLOW_STDIN); + + /* 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 (!key_save_private(private, identity_file, passphrase1, comment)) { + printf("Saving the key failed: %s.\n", identity_file); + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + key_free(private); + xfree(comment); + exit(1); + } + /* Destroy the passphrase and the copy of the key in memory. */ + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + key_free(private); /* Destroys contents */ + xfree(comment); + + printf("Your identification has been saved with the new passphrase.\n"); + exit(0); +} + +/* + * Print the SSHFP RR. + */ +static void +do_print_resource_record(struct passwd *pw, char *hname) +{ + Key *public; + char *comment = NULL; + struct stat st; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + public = key_load_public(identity_file, &comment); + if (public != NULL) { + export_dns_rr(hname, public, stdout, print_generic); + key_free(public); + xfree(comment); + exit(0); + } + if (comment) + xfree(comment); + + printf("failed to read v2 public key from %s.\n", identity_file); + exit(1); +} + +/* + * Change the comment of a private key file. + */ +static void +do_change_comment(struct passwd *pw) +{ + char new_comment[1024], *comment, *passphrase; + Key *private; + Key *public; + struct stat st; + FILE *f; + int fd; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + private = key_load_private(identity_file, "", &comment); + if (private == NULL) { + if (identity_passphrase) + passphrase = xstrdup(identity_passphrase); + else if (identity_new_passphrase) + passphrase = xstrdup(identity_new_passphrase); + else + passphrase = read_passphrase("Enter passphrase: ", + RP_ALLOW_STDIN); + /* Try to load using the passphrase. */ + private = key_load_private(identity_file, passphrase, &comment); + if (private == NULL) { + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + printf("Bad passphrase.\n"); + exit(1); + } + } else { + passphrase = xstrdup(""); + } + if (private->type != KEY_RSA1) { + fprintf(stderr, "Comments are only supported for RSA1 keys.\n"); + key_free(private); + exit(1); + } + printf("Key now has comment '%s'\n", comment); + + if (identity_comment) { + strlcpy(new_comment, identity_comment, sizeof(new_comment)); + } else { + printf("Enter new comment: "); + fflush(stdout); + if (!fgets(new_comment, sizeof(new_comment), stdin)) { + memset(passphrase, 0, strlen(passphrase)); + key_free(private); + exit(1); + } + if (strchr(new_comment, '\n')) + *strchr(new_comment, '\n') = 0; + } + + /* Save the file using the new passphrase. */ + if (!key_save_private(private, identity_file, passphrase, new_comment)) { + printf("Saving the key failed: %s.\n", identity_file); + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + key_free(private); + xfree(comment); + exit(1); + } + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + public = key_from_private(private); + key_free(private); + + strlcat(identity_file, ".pub", sizeof(identity_file)); + fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + printf("Could not save your public key in %s\n", identity_file); + exit(1); + } + f = fdopen(fd, "w"); + if (f == NULL) { + printf("fdopen %s failed", identity_file); + exit(1); + } + if (!key_write(public, f)) + fprintf(stderr, "write key failed"); + key_free(public); + fprintf(f, " %s\n", new_comment); + fclose(f); + + xfree(comment); + + printf("The comment in your key file has been changed.\n"); + exit(0); +} + +static void +usage(void) +{ + fprintf(stderr, "Usage: %s [options]\n", __progname); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -b bits Number of bits in the key to create.\n"); + fprintf(stderr, " -c Change comment in private and public key files.\n"); + fprintf(stderr, " -e Convert OpenSSH to IETF SECSH key file.\n"); + fprintf(stderr, " -f filename Filename of the key file.\n"); + fprintf(stderr, " -g Use generic DNS resource record format.\n"); + fprintf(stderr, " -i Convert IETF SECSH to OpenSSH key file.\n"); + fprintf(stderr, " -l Show fingerprint of key file.\n"); + fprintf(stderr, " -p Change passphrase of private key file.\n"); + fprintf(stderr, " -q Quiet.\n"); + fprintf(stderr, " -y Read private key file and print public key.\n"); + fprintf(stderr, " -t type Specify type of key to create.\n"); + fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); + fprintf(stderr, " -C comment Provide new comment.\n"); + fprintf(stderr, " -N phrase Provide new passphrase.\n"); + fprintf(stderr, " -P phrase Provide old passphrase.\n"); + fprintf(stderr, " -r hostname Print DNS resource record.\n"); +#ifdef SMARTCARD + fprintf(stderr, " -D reader Download public key from smartcard.\n"); + fprintf(stderr, " -U reader Upload private key to smartcard.\n"); +#endif /* SMARTCARD */ + + fprintf(stderr, " -G file Generate candidates for DH-GEX moduli\n"); + fprintf(stderr, " -T file Screen candidates for DH-GEX moduli\n"); + + exit(1); +} + +/* + * Main program for key management. + */ +int +main(int ac, char **av) +{ + char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; + char out_file[MAXPATHLEN], *reader_id = NULL; + char *resource_record_hostname = NULL; + Key *private, *public; + struct passwd *pw; + struct stat st; + int opt, type, fd, download = 0, memory = 0; + int generator_wanted = 0, trials = 100; + int do_gen_candidates = 0, do_screen_candidates = 0; + int log_level = SYSLOG_LEVEL_INFO; + BIGNUM *start = NULL; + FILE *f; + + extern int optind; + extern char *optarg; + + __progname = ssh_get_progname(av[0]); + + SSLeay_add_all_algorithms(); + log_init(av[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); + + init_rng(); + seed_rng(); + + /* we need this for the home * directory. */ + pw = getpwuid(getuid()); + if (!pw) { + printf("You don't exist, go away!\n"); + exit(1); + } + if (gethostname(hostname, sizeof(hostname)) < 0) { + perror("gethostname"); + exit(1); + } + + while ((opt = getopt(ac, av, + "degiqpclBRvxXyb:f:t:U:D:P:N:C:r:g:T:G:M:S:a:W:")) != -1) { + switch (opt) { + case 'b': + bits = atoi(optarg); + if (bits < 512 || bits > 32768) { + printf("Bits has bad value.\n"); + exit(1); + } + break; + case 'l': + print_fingerprint = 1; + break; + case 'B': + print_bubblebabble = 1; + break; + case 'p': + change_passphrase = 1; + break; + case 'c': + change_comment = 1; + break; + case 'f': + strlcpy(identity_file, optarg, sizeof(identity_file)); + have_identity = 1; + break; + case 'g': + print_generic = 1; + break; + case 'P': + identity_passphrase = optarg; + break; + case 'N': + identity_new_passphrase = optarg; + break; + case 'C': + identity_comment = optarg; + break; + case 'q': + quiet = 1; + break; + case 'R': + /* unused */ + exit(0); + break; + case 'e': + case 'x': + /* export key */ + convert_to_ssh2 = 1; + break; + case 'i': + case 'X': + /* import key */ + convert_from_ssh2 = 1; + break; + case 'y': + print_public = 1; + break; + case 'd': + key_type_name = "dsa"; + break; + case 't': + key_type_name = optarg; + break; + case 'D': + download = 1; + case 'U': + reader_id = optarg; + break; + case 'v': + if (log_level == SYSLOG_LEVEL_INFO) + log_level = SYSLOG_LEVEL_DEBUG1; + else { + if (log_level >= SYSLOG_LEVEL_DEBUG1 && + log_level < SYSLOG_LEVEL_DEBUG3) + log_level++; + } + break; + case 'r': + resource_record_hostname = optarg; + break; + case 'W': + generator_wanted = atoi(optarg); + if (generator_wanted < 1) + fatal("Desired generator has bad value."); + break; + case 'a': + trials = atoi(optarg); + break; + case 'M': + memory = atoi(optarg); + break; + case 'G': + do_gen_candidates = 1; + strlcpy(out_file, optarg, sizeof(out_file)); + break; + case 'T': + do_screen_candidates = 1; + strlcpy(out_file, optarg, sizeof(out_file)); + break; + case 'S': + /* XXX - also compare length against bits */ + if (BN_hex2bn(&start, optarg) == 0) + fatal("Invalid start point."); + break; + case '?': + default: + usage(); + } + } + + /* reinit */ + log_init(av[0], log_level, SYSLOG_FACILITY_USER, 1); + + if (optind < ac) { + printf("Too many arguments.\n"); + usage(); + } + if (change_passphrase && change_comment) { + printf("Can only have one of -p and -c.\n"); + usage(); + } + if (print_fingerprint || print_bubblebabble) + do_fingerprint(pw); + if (change_passphrase) + do_change_passphrase(pw); + if (change_comment) + do_change_comment(pw); + if (convert_to_ssh2) + do_convert_to_ssh2(pw); + if (convert_from_ssh2) + do_convert_from_ssh2(pw); + if (print_public) + do_print_public(pw); + if (resource_record_hostname != NULL) { + do_print_resource_record(pw, resource_record_hostname); + } + if (reader_id != NULL) { +#ifdef SMARTCARD + if (download) + do_download(pw, reader_id); + else + do_upload(pw, reader_id); +#else /* SMARTCARD */ + fatal("no support for smartcards."); +#endif /* SMARTCARD */ + } + + if (do_gen_candidates) { + FILE *out = fopen(out_file, "w"); + + if (out == NULL) { + error("Couldn't open modulus candidate file \"%s\": %s", + out_file, strerror(errno)); + return (1); + } + if (gen_candidates(out, memory, bits, start) != 0) + fatal("modulus candidate generation failed\n"); + + return (0); + } + + if (do_screen_candidates) { + FILE *in; + FILE *out = fopen(out_file, "w"); + + if (have_identity && strcmp(identity_file, "-") != 0) { + if ((in = fopen(identity_file, "r")) == NULL) { + fatal("Couldn't open modulus candidate " + "file \"%s\": %s", identity_file, + strerror(errno)); + } + } else + in = stdin; + + if (out == NULL) { + fatal("Couldn't open moduli file \"%s\": %s", + out_file, strerror(errno)); + } + if (prime_test(in, out, trials, generator_wanted) != 0) + fatal("modulus screening failed\n"); + return (0); + } + + arc4random_stir(); + + if (key_type_name == NULL) { + printf("You must specify a key type (-t).\n"); + usage(); + } + type = key_type_from_name(key_type_name); + if (type == KEY_UNSPEC) { + fprintf(stderr, "unknown key type %s\n", key_type_name); + exit(1); + } + if (!quiet) + printf("Generating public/private %s key pair.\n", key_type_name); + private = key_generate(type, bits); + if (private == NULL) { + fprintf(stderr, "key_generate failed"); + exit(1); + } + public = key_from_private(private); + + if (!have_identity) + ask_filename(pw, "Enter file in which to save the key"); + + /* Create ~/.ssh directory if it doesn\'t already exist. */ + snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); + if (strstr(identity_file, dotsshdir) != NULL && + stat(dotsshdir, &st) < 0) { + if (mkdir(dotsshdir, 0700) < 0) + error("Could not create directory '%s'.", dotsshdir); + else if (!quiet) + printf("Created directory '%s'.\n", dotsshdir); + } + /* If the file already exists, ask the user to confirm. */ + if (stat(identity_file, &st) >= 0) { + char yesno[3]; + printf("%s already exists.\n", identity_file); + printf("Overwrite (y/n)? "); + fflush(stdout); + if (fgets(yesno, sizeof(yesno), stdin) == NULL) + exit(1); + if (yesno[0] != 'y' && yesno[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): ", RP_ALLOW_STDIN); + passphrase2 = read_passphrase("Enter same passphrase again: ", + RP_ALLOW_STDIN); + 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); + } + + if (identity_comment) { + strlcpy(comment, identity_comment, sizeof(comment)); + } else { + /* Create default commend field for the passphrase. */ + snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); + } + + /* Save the key with the given passphrase and comment. */ + if (!key_save_private(private, identity_file, passphrase1, comment)) { + printf("Saving the key failed: %s.\n", identity_file); + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + exit(1); + } + /* Clear the passphrase. */ + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + + /* Clear the private key and the random number generator. */ + key_free(private); + arc4random_stir(); + + if (!quiet) + printf("Your identification has been saved in %s.\n", identity_file); + + strlcat(identity_file, ".pub", sizeof(identity_file)); + fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + printf("Could not save your public key in %s\n", identity_file); + exit(1); + } + f = fdopen(fd, "w"); + if (f == NULL) { + printf("fdopen %s failed", identity_file); + exit(1); + } + if (!key_write(public, f)) + fprintf(stderr, "write key failed"); + fprintf(f, " %s\n", comment); + fclose(f); + + if (!quiet) { + char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); + printf("Your public key has been saved in %s.\n", + identity_file); + printf("The key fingerprint is:\n"); + printf("%s %s\n", fp, comment); + xfree(fp); + } + + key_free(public); + exit(0); +} diff --git a/crypto/openssh-3.9p1/ssh-keyscan.1 b/crypto/openssh-3.9p1/ssh-keyscan.1 new file mode 100644 index 0000000000..9efcf52137 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-keyscan.1 @@ -0,0 +1,159 @@ +.\" $OpenBSD: ssh-keyscan.1,v 1.18 2004/07/12 23:34:25 brad Exp $ +.\" +.\" Copyright 1995, 1996 by David Mazieres . +.\" +.\" Modification and redistribution in source and binary forms is +.\" permitted provided that due credit is given to the author and the +.\" OpenBSD project by leaving this copyright notice intact. +.\" +.Dd January 1, 1996 +.Dt SSH-KEYSCAN 1 +.Os +.Sh NAME +.Nm ssh-keyscan +.Nd gather ssh public keys +.Sh SYNOPSIS +.Nm ssh-keyscan +.Bk -words +.Op Fl v46 +.Op Fl p Ar port +.Op Fl T Ar timeout +.Op Fl t Ar type +.Op Fl f Ar file +.Op Ar host | addrlist namelist +.Op Ar ... +.Ek +.Sh DESCRIPTION +.Nm +is a utility for gathering the public ssh host keys of a number of +hosts. +It was designed to aid in building and verifying +.Pa ssh_known_hosts +files. +.Nm +provides a minimal interface suitable for use by shell and perl +scripts. +.Pp +.Nm +uses non-blocking socket I/O to contact as many hosts as possible in +parallel, so it is very efficient. +The keys from a domain of 1,000 +hosts can be collected in tens of seconds, even when some of those +hosts are down or do not run ssh. +For scanning, one does not need +login access to the machines that are being scanned, nor does the +scanning process involve any encryption. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl p Ar port +Port to connect to on the remote host. +.It Fl T Ar timeout +Set the timeout for connection attempts. +If +.Pa timeout +seconds have elapsed since a connection was initiated to a host or since the +last time anything was read from that host, then the connection is +closed and the host in question considered unavailable. +Default is 5 seconds. +.It Fl t Ar type +Specifies the type of the key to fetch from the scanned hosts. +The possible values are +.Dq rsa1 +for protocol version 1 and +.Dq rsa +or +.Dq dsa +for protocol version 2. +Multiple values may be specified by separating them with commas. +The default is +.Dq rsa1 . +.It Fl f Ar filename +Read hosts or +.Pa addrlist namelist +pairs from this file, one per line. +If +.Pa - +is supplied instead of a filename, +.Nm +will read hosts or +.Pa addrlist namelist +pairs from the standard input. +.It Fl v +Verbose mode. +Causes +.Nm +to print debugging messages about its progress. +.It Fl 4 +Forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +Forces +.Nm +to use IPv6 addresses only. +.El +.Sh SECURITY +If a ssh_known_hosts file is constructed using +.Nm +without verifying the keys, users will be vulnerable to +.Em man in the middle +attacks. +On the other hand, if the security model allows such a risk, +.Nm +can help in the detection of tampered keyfiles or man in the middle +attacks which have begun after the ssh_known_hosts file was created. +.Sh FILES +.Pa Input format: +.Bd -literal +1.2.3.4,1.2.4.4 name.my.domain,name,n.my.domain,n,1.2.3.4,1.2.4.4 +.Ed +.Pp +.Pa Output format for rsa1 keys: +.Bd -literal +host-or-namelist bits exponent modulus +.Ed +.Pp +.Pa Output format for rsa and dsa keys: +.Bd -literal +host-or-namelist keytype base64-encoded-key +.Ed +.Pp +Where +.Pa keytype +is either +.Dq ssh-rsa +or +.Dq ssh-dss . +.Pp +.Pa /etc/ssh/ssh_known_hosts +.Sh EXAMPLES +Print the +.Pa rsa1 +host key for machine +.Pa hostname : +.Bd -literal +$ ssh-keyscan hostname +.Ed +.Pp +Find all hosts from the file +.Pa ssh_hosts +which have new or different keys from those in the sorted file +.Pa ssh_known_hosts : +.Bd -literal +$ ssh-keyscan -t rsa,dsa -f ssh_hosts | \e + sort -u - ssh_known_hosts | diff ssh_known_hosts - +.Ed +.Sh SEE ALSO +.Xr ssh 1 , +.Xr sshd 8 +.Sh AUTHORS +.An David Mazieres Aq dm@lcs.mit.edu +wrote the initial version, and +.An Wayne Davison Aq wayned@users.sourceforge.net +added support for protocol version 2. +.Sh BUGS +It generates "Connection closed by remote host" messages on the consoles +of all the machines it scans if the server is older than version 2.9. +This is because it opens a connection to the ssh port, reads the public +key, and drops the connection as soon as it gets the key. diff --git a/crypto/openssh-3.9p1/ssh-keyscan.c b/crypto/openssh-3.9p1/ssh-keyscan.c new file mode 100644 index 0000000000..3cb52ac2e9 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-keyscan.c @@ -0,0 +1,809 @@ +/* + * Copyright 1995, 1996 by David Mazieres . + * + * Modification and redistribution in source and binary forms is + * permitted provided that due credit is given to the author and the + * OpenBSD project by leaving this copyright notice intact. + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh-keyscan.c,v 1.50 2004/08/11 21:44:32 avsm Exp $"); + +#include "openbsd-compat/sys-queue.h" + +#include + +#include +#include "xmalloc.h" +#include "ssh.h" +#include "ssh1.h" +#include "key.h" +#include "kex.h" +#include "compat.h" +#include "myproposal.h" +#include "packet.h" +#include "dispatch.h" +#include "buffer.h" +#include "bufaux.h" +#include "log.h" +#include "atomicio.h" +#include "misc.h" + +/* Flag indicating whether IPv4 or IPv6. This can be set on the command line. + Default value is AF_UNSPEC means both IPv4 and IPv6. */ +int IPv4or6 = AF_UNSPEC; + +int ssh_port = SSH_DEFAULT_PORT; + +#define KT_RSA1 1 +#define KT_DSA 2 +#define KT_RSA 4 + +int get_keytypes = KT_RSA1; /* Get only RSA1 keys by default */ + +#define MAXMAXFD 256 + +/* The number of seconds after which to give up on a TCP connection */ +int timeout = 5; + +int maxfd; +#define MAXCON (maxfd - 10) + +extern char *__progname; +fd_set *read_wait; +size_t read_wait_size; +int ncon; +int nonfatal_fatal = 0; +jmp_buf kexjmp; +Key *kexjmp_key; + +/* + * Keep a connection structure for each file descriptor. The state + * associated with file descriptor n is held in fdcon[n]. + */ +typedef struct Connection { + u_char c_status; /* State of connection on this file desc. */ +#define CS_UNUSED 0 /* File descriptor unused */ +#define CS_CON 1 /* Waiting to connect/read greeting */ +#define CS_SIZE 2 /* Waiting to read initial packet size */ +#define CS_KEYS 3 /* Waiting to read public key packet */ + int c_fd; /* Quick lookup: c->c_fd == c - fdcon */ + int c_plen; /* Packet length field for ssh packet */ + int c_len; /* Total bytes which must be read. */ + int c_off; /* Length of data read so far. */ + int c_keytype; /* Only one of KT_RSA1, KT_DSA, or KT_RSA */ + char *c_namebase; /* Address to free for c_name and c_namelist */ + char *c_name; /* Hostname of connection for errors */ + char *c_namelist; /* Pointer to other possible addresses */ + char *c_output_name; /* Hostname of connection for output */ + char *c_data; /* Data read from this fd */ + Kex *c_kex; /* The key-exchange struct for ssh2 */ + struct timeval c_tv; /* Time at which connection gets aborted */ + TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ +} con; + +TAILQ_HEAD(conlist, Connection) tq; /* Timeout Queue */ +con *fdcon; + +/* + * This is just a wrapper around fgets() to make it usable. + */ + +/* Stress-test. Increase this later. */ +#define LINEBUF_SIZE 16 + +typedef struct { + char *buf; + u_int size; + int lineno; + const char *filename; + FILE *stream; + void (*errfun) (const char *,...); +} Linebuf; + +static Linebuf * +Linebuf_alloc(const char *filename, void (*errfun) (const char *,...)) +{ + Linebuf *lb; + + if (!(lb = malloc(sizeof(*lb)))) { + if (errfun) + (*errfun) ("linebuf (%s): malloc failed\n", + filename ? filename : "(stdin)"); + return (NULL); + } + if (filename) { + lb->filename = filename; + if (!(lb->stream = fopen(filename, "r"))) { + xfree(lb); + if (errfun) + (*errfun) ("%s: %s\n", filename, strerror(errno)); + return (NULL); + } + } else { + lb->filename = "(stdin)"; + lb->stream = stdin; + } + + if (!(lb->buf = malloc(lb->size = LINEBUF_SIZE))) { + if (errfun) + (*errfun) ("linebuf (%s): malloc failed\n", lb->filename); + xfree(lb); + return (NULL); + } + lb->errfun = errfun; + lb->lineno = 0; + return (lb); +} + +static void +Linebuf_free(Linebuf * lb) +{ + fclose(lb->stream); + xfree(lb->buf); + xfree(lb); +} + +#if 0 +static void +Linebuf_restart(Linebuf * lb) +{ + clearerr(lb->stream); + rewind(lb->stream); + lb->lineno = 0; +} + +static int +Linebuf_lineno(Linebuf * lb) +{ + return (lb->lineno); +} +#endif + +static char * +Linebuf_getline(Linebuf * lb) +{ + int n = 0; + void *p; + + lb->lineno++; + for (;;) { + /* Read a line */ + if (!fgets(&lb->buf[n], lb->size - n, lb->stream)) { + if (ferror(lb->stream) && lb->errfun) + (*lb->errfun)("%s: %s\n", lb->filename, + strerror(errno)); + return (NULL); + } + n = strlen(lb->buf); + + /* Return it or an error if it fits */ + if (n > 0 && lb->buf[n - 1] == '\n') { + lb->buf[n - 1] = '\0'; + return (lb->buf); + } + if (n != lb->size - 1) { + if (lb->errfun) + (*lb->errfun)("%s: skipping incomplete last line\n", + lb->filename); + return (NULL); + } + /* Double the buffer if we need more space */ + lb->size *= 2; + if ((p = realloc(lb->buf, lb->size)) == NULL) { + lb->size /= 2; + if (lb->errfun) + (*lb->errfun)("linebuf (%s): realloc failed\n", + lb->filename); + return (NULL); + } + lb->buf = p; + } +} + +static int +fdlim_get(int hard) +{ +#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) + struct rlimit rlfd; + + if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) + return (-1); + if ((hard ? rlfd.rlim_max : rlfd.rlim_cur) == RLIM_INFINITY) + return SSH_SYSFDMAX; + else + return hard ? rlfd.rlim_max : rlfd.rlim_cur; +#else + return SSH_SYSFDMAX; +#endif +} + +static int +fdlim_set(int lim) +{ +#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) + struct rlimit rlfd; +#endif + + if (lim <= 0) + return (-1); +#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE) + if (getrlimit(RLIMIT_NOFILE, &rlfd) < 0) + return (-1); + rlfd.rlim_cur = lim; + if (setrlimit(RLIMIT_NOFILE, &rlfd) < 0) + return (-1); +#elif defined (HAVE_SETDTABLESIZE) + setdtablesize(lim); +#endif + return (0); +} + +/* + * This is an strsep function that returns a null field for adjacent + * separators. This is the same as the 4.4BSD strsep, but different from the + * one in the GNU libc. + */ +static char * +xstrsep(char **str, const char *delim) +{ + char *s, *e; + + if (!**str) + return (NULL); + + s = *str; + e = s + strcspn(s, delim); + + if (*e != '\0') + *e++ = '\0'; + *str = e; + + return (s); +} + +/* + * Get the next non-null token (like GNU strsep). Strsep() will return a + * null token for two adjacent separators, so we may have to loop. + */ +static char * +strnnsep(char **stringp, char *delim) +{ + char *tok; + + do { + tok = xstrsep(stringp, delim); + } while (tok && *tok == '\0'); + return (tok); +} + +static Key * +keygrab_ssh1(con *c) +{ + static Key *rsa; + static Buffer msg; + + if (rsa == NULL) { + buffer_init(&msg); + rsa = key_new(KEY_RSA1); + } + buffer_append(&msg, c->c_data, c->c_plen); + buffer_consume(&msg, 8 - (c->c_plen & 7)); /* padding */ + if (buffer_get_char(&msg) != (int) SSH_SMSG_PUBLIC_KEY) { + error("%s: invalid packet type", c->c_name); + buffer_clear(&msg); + return NULL; + } + buffer_consume(&msg, 8); /* cookie */ + + /* server key */ + (void) buffer_get_int(&msg); + buffer_get_bignum(&msg, rsa->rsa->e); + buffer_get_bignum(&msg, rsa->rsa->n); + + /* host key */ + (void) buffer_get_int(&msg); + buffer_get_bignum(&msg, rsa->rsa->e); + buffer_get_bignum(&msg, rsa->rsa->n); + + buffer_clear(&msg); + + return (rsa); +} + +static int +hostjump(Key *hostkey) +{ + kexjmp_key = hostkey; + longjmp(kexjmp, 1); +} + +static int +ssh2_capable(int remote_major, int remote_minor) +{ + switch (remote_major) { + case 1: + if (remote_minor == 99) + return 1; + break; + case 2: + return 1; + default: + break; + } + return 0; +} + +static Key * +keygrab_ssh2(con *c) +{ + int j; + + packet_set_connection(c->c_fd, c->c_fd); + enable_compat20(); + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA? + "ssh-dss": "ssh-rsa"; + c->c_kex = kex_setup(myproposal); + c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; + c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; + c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; + c->c_kex->verify_host_key = hostjump; + + if (!(j = setjmp(kexjmp))) { + nonfatal_fatal = 1; + dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, c->c_kex); + fprintf(stderr, "Impossible! dispatch_run() returned!\n"); + exit(1); + } + nonfatal_fatal = 0; + xfree(c->c_kex); + c->c_kex = NULL; + packet_close(); + + return j < 0? NULL : kexjmp_key; +} + +static void +keyprint(con *c, Key *key) +{ + if (!key) + return; + + fprintf(stdout, "%s ", c->c_output_name ? c->c_output_name : c->c_name); + key_write(key, stdout); + fputs("\n", stdout); +} + +static int +tcpconnect(char *host) +{ + struct addrinfo hints, *ai, *aitop; + char strport[NI_MAXSERV]; + int gaierr, s = -1; + + snprintf(strport, sizeof strport, "%d", ssh_port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = IPv4or6; + hints.ai_socktype = SOCK_STREAM; + if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) + fatal("getaddrinfo %s: %s", host, gai_strerror(gaierr)); + for (ai = aitop; ai; ai = ai->ai_next) { + s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (s < 0) { + error("socket: %s", strerror(errno)); + continue; + } + if (set_nonblock(s) == -1) + fatal("%s: set_nonblock(%d)", __func__, s); + if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0 && + errno != EINPROGRESS) + error("connect (`%s'): %s", host, strerror(errno)); + else + break; + close(s); + s = -1; + } + freeaddrinfo(aitop); + return s; +} + +static int +conalloc(char *iname, char *oname, int keytype) +{ + char *namebase, *name, *namelist; + int s; + + namebase = namelist = xstrdup(iname); + + do { + name = xstrsep(&namelist, ","); + if (!name) { + xfree(namebase); + return (-1); + } + } while ((s = tcpconnect(name)) < 0); + + if (s >= maxfd) + fatal("conalloc: fdno %d too high", s); + if (fdcon[s].c_status) + fatal("conalloc: attempt to reuse fdno %d", s); + + fdcon[s].c_fd = s; + fdcon[s].c_status = CS_CON; + fdcon[s].c_namebase = namebase; + fdcon[s].c_name = name; + fdcon[s].c_namelist = namelist; + fdcon[s].c_output_name = xstrdup(oname); + fdcon[s].c_data = (char *) &fdcon[s].c_plen; + fdcon[s].c_len = 4; + fdcon[s].c_off = 0; + fdcon[s].c_keytype = keytype; + gettimeofday(&fdcon[s].c_tv, NULL); + fdcon[s].c_tv.tv_sec += timeout; + TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); + FD_SET(s, read_wait); + ncon++; + return (s); +} + +static void +confree(int s) +{ + if (s >= maxfd || fdcon[s].c_status == CS_UNUSED) + fatal("confree: attempt to free bad fdno %d", s); + close(s); + xfree(fdcon[s].c_namebase); + xfree(fdcon[s].c_output_name); + if (fdcon[s].c_status == CS_KEYS) + xfree(fdcon[s].c_data); + fdcon[s].c_status = CS_UNUSED; + fdcon[s].c_keytype = 0; + TAILQ_REMOVE(&tq, &fdcon[s], c_link); + FD_CLR(s, read_wait); + ncon--; +} + +static void +contouch(int s) +{ + TAILQ_REMOVE(&tq, &fdcon[s], c_link); + gettimeofday(&fdcon[s].c_tv, NULL); + fdcon[s].c_tv.tv_sec += timeout; + TAILQ_INSERT_TAIL(&tq, &fdcon[s], c_link); +} + +static int +conrecycle(int s) +{ + con *c = &fdcon[s]; + int ret; + + ret = conalloc(c->c_namelist, c->c_output_name, c->c_keytype); + confree(s); + return (ret); +} + +static void +congreet(int s) +{ + int remote_major = 0, remote_minor = 0, n = 0; + char buf[256], *cp; + char remote_version[sizeof buf]; + size_t bufsiz; + con *c = &fdcon[s]; + + bufsiz = sizeof(buf); + cp = buf; + while (bufsiz-- && (n = atomicio(read, s, cp, 1)) == 1 && *cp != '\n') { + if (*cp == '\r') + *cp = '\n'; + cp++; + } + if (n < 0) { + if (errno != ECONNREFUSED) + error("read (%s): %s", c->c_name, strerror(errno)); + conrecycle(s); + return; + } + if (n == 0) { + error("%s: Connection closed by remote host", c->c_name); + conrecycle(s); + return; + } + if (*cp != '\n' && *cp != '\r') { + error("%s: bad greeting", c->c_name); + confree(s); + return; + } + *cp = '\0'; + if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", + &remote_major, &remote_minor, remote_version) == 3) + compat_datafellows(remote_version); + else + datafellows = 0; + if (c->c_keytype != KT_RSA1) { + if (!ssh2_capable(remote_major, remote_minor)) { + debug("%s doesn't support ssh2", c->c_name); + confree(s); + return; + } + } else if (remote_major != 1) { + debug("%s doesn't support ssh1", c->c_name); + confree(s); + return; + } + fprintf(stderr, "# %s %s\n", c->c_name, chop(buf)); + n = snprintf(buf, sizeof buf, "SSH-%d.%d-OpenSSH-keyscan\r\n", + c->c_keytype == KT_RSA1? PROTOCOL_MAJOR_1 : PROTOCOL_MAJOR_2, + c->c_keytype == KT_RSA1? PROTOCOL_MINOR_1 : PROTOCOL_MINOR_2); + if (atomicio(vwrite, s, buf, n) != n) { + error("write (%s): %s", c->c_name, strerror(errno)); + confree(s); + return; + } + if (c->c_keytype != KT_RSA1) { + keyprint(c, keygrab_ssh2(c)); + confree(s); + return; + } + c->c_status = CS_SIZE; + contouch(s); +} + +static void +conread(int s) +{ + con *c = &fdcon[s]; + int n; + + if (c->c_status == CS_CON) { + congreet(s); + return; + } + n = atomicio(read, s, c->c_data + c->c_off, c->c_len - c->c_off); + if (n < 0) { + error("read (%s): %s", c->c_name, strerror(errno)); + confree(s); + return; + } + c->c_off += n; + + if (c->c_off == c->c_len) + switch (c->c_status) { + case CS_SIZE: + c->c_plen = htonl(c->c_plen); + c->c_len = c->c_plen + 8 - (c->c_plen & 7); + c->c_off = 0; + c->c_data = xmalloc(c->c_len); + c->c_status = CS_KEYS; + break; + case CS_KEYS: + keyprint(c, keygrab_ssh1(c)); + confree(s); + return; + break; + default: + fatal("conread: invalid status %d", c->c_status); + break; + } + + contouch(s); +} + +static void +conloop(void) +{ + struct timeval seltime, now; + fd_set *r, *e; + con *c; + int i; + + gettimeofday(&now, NULL); + c = TAILQ_FIRST(&tq); + + if (c && (c->c_tv.tv_sec > now.tv_sec || + (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec > now.tv_usec))) { + seltime = c->c_tv; + seltime.tv_sec -= now.tv_sec; + seltime.tv_usec -= now.tv_usec; + if (seltime.tv_usec < 0) { + seltime.tv_usec += 1000000; + seltime.tv_sec--; + } + } else + seltime.tv_sec = seltime.tv_usec = 0; + + r = xmalloc(read_wait_size); + memcpy(r, read_wait, read_wait_size); + e = xmalloc(read_wait_size); + memcpy(e, read_wait, read_wait_size); + + while (select(maxfd, r, NULL, e, &seltime) == -1 && + (errno == EAGAIN || errno == EINTR)) + ; + + for (i = 0; i < maxfd; i++) { + if (FD_ISSET(i, e)) { + error("%s: exception!", fdcon[i].c_name); + confree(i); + } else if (FD_ISSET(i, r)) + conread(i); + } + xfree(r); + xfree(e); + + c = TAILQ_FIRST(&tq); + while (c && (c->c_tv.tv_sec < now.tv_sec || + (c->c_tv.tv_sec == now.tv_sec && c->c_tv.tv_usec < now.tv_usec))) { + int s = c->c_fd; + + c = TAILQ_NEXT(c, c_link); + conrecycle(s); + } +} + +static void +do_host(char *host) +{ + char *name = strnnsep(&host, " \t\n"); + int j; + + if (name == NULL) + return; + for (j = KT_RSA1; j <= KT_RSA; j *= 2) { + if (get_keytypes & j) { + while (ncon >= MAXCON) + conloop(); + conalloc(name, *host ? host : name, j); + } + } +} + +void +fatal(const char *fmt,...) +{ + va_list args; + + va_start(args, fmt); + do_log(SYSLOG_LEVEL_FATAL, fmt, args); + va_end(args); + if (nonfatal_fatal) + longjmp(kexjmp, -1); + else + exit(255); +} + +static void +usage(void) +{ + fprintf(stderr, "usage: %s [-v46] [-p port] [-T timeout] [-t type] [-f file]\n" + "\t\t [host | addrlist namelist] [...]\n", + __progname); + exit(1); +} + +int +main(int argc, char **argv) +{ + int debug_flag = 0, log_level = SYSLOG_LEVEL_INFO; + int opt, fopt_count = 0; + char *tname; + + extern int optind; + extern char *optarg; + + __progname = ssh_get_progname(argv[0]); + init_rng(); + seed_rng(); + TAILQ_INIT(&tq); + + if (argc <= 1) + usage(); + + while ((opt = getopt(argc, argv, "v46p:T:t:f:")) != -1) { + switch (opt) { + case 'p': + ssh_port = a2port(optarg); + if (ssh_port == 0) { + fprintf(stderr, "Bad port '%s'\n", optarg); + exit(1); + } + break; + case 'T': + timeout = convtime(optarg); + if (timeout == -1 || timeout == 0) { + fprintf(stderr, "Bad timeout '%s'\n", optarg); + usage(); + } + break; + case 'v': + if (!debug_flag) { + debug_flag = 1; + log_level = SYSLOG_LEVEL_DEBUG1; + } + else if (log_level < SYSLOG_LEVEL_DEBUG3) + log_level++; + else + fatal("Too high debugging level."); + break; + case 'f': + if (strcmp(optarg, "-") == 0) + optarg = NULL; + argv[fopt_count++] = optarg; + break; + case 't': + get_keytypes = 0; + tname = strtok(optarg, ","); + while (tname) { + int type = key_type_from_name(tname); + switch (type) { + case KEY_RSA1: + get_keytypes |= KT_RSA1; + break; + case KEY_DSA: + get_keytypes |= KT_DSA; + break; + case KEY_RSA: + get_keytypes |= KT_RSA; + break; + case KEY_UNSPEC: + fatal("unknown key type %s", tname); + } + tname = strtok(NULL, ","); + } + break; + case '4': + IPv4or6 = AF_INET; + break; + case '6': + IPv4or6 = AF_INET6; + break; + case '?': + default: + usage(); + } + } + if (optind == argc && !fopt_count) + usage(); + + log_init("ssh-keyscan", log_level, SYSLOG_FACILITY_USER, 1); + + maxfd = fdlim_get(1); + if (maxfd < 0) + fatal("%s: fdlim_get: bad value", __progname); + if (maxfd > MAXMAXFD) + maxfd = MAXMAXFD; + if (MAXCON <= 0) + fatal("%s: not enough file descriptors", __progname); + if (maxfd > fdlim_get(0)) + fdlim_set(maxfd); + fdcon = xmalloc(maxfd * sizeof(con)); + memset(fdcon, 0, maxfd * sizeof(con)); + + read_wait_size = howmany(maxfd, NFDBITS) * sizeof(fd_mask); + read_wait = xmalloc(read_wait_size); + memset(read_wait, 0, read_wait_size); + + if (fopt_count) { + Linebuf *lb; + char *line; + int j; + + for (j = 0; j < fopt_count; j++) { + lb = Linebuf_alloc(argv[j], error); + if (!lb) + continue; + while ((line = Linebuf_getline(lb)) != NULL) + do_host(line); + Linebuf_free(lb); + } + } + + while (optind < argc) + do_host(argv[optind++]); + + while (ncon > 0) + conloop(); + + return (0); +} diff --git a/crypto/openssh-3.9p1/ssh-keysign.8 b/crypto/openssh-3.9p1/ssh-keysign.8 new file mode 100644 index 0000000000..a17e8d5cf2 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-keysign.8 @@ -0,0 +1,82 @@ +.\" $OpenBSD: ssh-keysign.8,v 1.7 2003/06/10 09:12:11 jmc Exp $ +.\" +.\" Copyright (c) 2002 Markus Friedl. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd May 24, 2002 +.Dt SSH-KEYSIGN 8 +.Os +.Sh NAME +.Nm ssh-keysign +.Nd ssh helper program for hostbased authentication +.Sh SYNOPSIS +.Nm +.Sh DESCRIPTION +.Nm +is used by +.Xr ssh 1 +to access the local host keys and generate the digital signature +required during hostbased authentication with SSH protocol version 2. +.Pp +.Nm +is disabled by default and can only be enabled in the +global client configuration file +.Pa /etc/ssh/ssh_config +by setting +.Cm EnableSSHKeysign +to +.Dq yes . +.Pp +.Nm +is not intended to be invoked by the user, but from +.Xr ssh 1 . +See +.Xr ssh 1 +and +.Xr sshd 8 +for more information about hostbased authentication. +.Sh FILES +.Bl -tag -width Ds +.It Pa /etc/ssh/ssh_config +Controls whether +.Nm +is enabled. +.It Pa /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_rsa_key +These files contain the private parts of the host keys used to +generate the digital signature. +They should be owned by root, readable only by root, and not +accessible to others. +Since they are readable only by root, +.Nm +must be set-uid root if hostbased authentication is used. +.El +.Sh SEE ALSO +.Xr ssh 1 , +.Xr ssh-keygen 1 , +.Xr ssh_config 5 , +.Xr sshd 8 +.Sh HISTORY +.Nm +first appeared in +.Ox 3.2 . +.Sh AUTHORS +.An Markus Friedl Aq markus@openbsd.org diff --git a/crypto/openssh-3.9p1/ssh-keysign.c b/crypto/openssh-3.9p1/ssh-keysign.c new file mode 100644 index 0000000000..517655790c --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-keysign.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2002 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "includes.h" +RCSID("$OpenBSD: ssh-keysign.c,v 1.16 2004/04/18 23:10:26 djm Exp $"); + +#include +#include +#include + +#include "log.h" +#include "key.h" +#include "ssh.h" +#include "ssh2.h" +#include "misc.h" +#include "xmalloc.h" +#include "buffer.h" +#include "bufaux.h" +#include "authfile.h" +#include "msg.h" +#include "canohost.h" +#include "pathnames.h" +#include "readconf.h" +#include "uidswap.h" + +/* XXX readconf.c needs these */ +uid_t original_real_uid; + +extern char *__progname; + +static int +valid_request(struct passwd *pw, char *host, Key **ret, u_char *data, + u_int datalen) +{ + Buffer b; + Key *key = NULL; + u_char *pkblob; + u_int blen, len; + char *pkalg, *p; + int pktype, fail; + + fail = 0; + + buffer_init(&b); + buffer_append(&b, data, datalen); + + /* session id, currently limited to SHA1 (20 bytes) */ + p = buffer_get_string(&b, &len); + if (len != 20) + fail++; + xfree(p); + + if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) + fail++; + + /* server user */ + buffer_skip_string(&b); + + /* service */ + p = buffer_get_string(&b, NULL); + if (strcmp("ssh-connection", p) != 0) + fail++; + xfree(p); + + /* method */ + p = buffer_get_string(&b, NULL); + if (strcmp("hostbased", p) != 0) + fail++; + xfree(p); + + /* pubkey */ + pkalg = buffer_get_string(&b, NULL); + pkblob = buffer_get_string(&b, &blen); + + pktype = key_type_from_name(pkalg); + if (pktype == KEY_UNSPEC) + fail++; + else if ((key = key_from_blob(pkblob, blen)) == NULL) + fail++; + else if (key->type != pktype) + fail++; + xfree(pkalg); + xfree(pkblob); + + /* client host name, handle trailing dot */ + p = buffer_get_string(&b, &len); + debug2("valid_request: check expect chost %s got %s", host, p); + if (strlen(host) != len - 1) + fail++; + else if (p[len - 1] != '.') + fail++; + else if (strncasecmp(host, p, len - 1) != 0) + fail++; + xfree(p); + + /* local user */ + p = buffer_get_string(&b, NULL); + + if (strcmp(pw->pw_name, p) != 0) + fail++; + xfree(p); + + /* end of message */ + if (buffer_len(&b) != 0) + fail++; + buffer_free(&b); + + debug3("valid_request: fail %d", fail); + + if (fail && key != NULL) + key_free(key); + else + *ret = key; + + return (fail ? -1 : 0); +} + +int +main(int argc, char **argv) +{ + Buffer b; + Options options; + Key *keys[2], *key; + struct passwd *pw; + int key_fd[2], i, found, version = 2, fd; + u_char *signature, *data; + char *host; + u_int slen, dlen; + u_int32_t rnd[256]; + + key_fd[0] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY); + key_fd[1] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY); + + if ((pw = getpwuid(getuid())) == NULL) + fatal("getpwuid failed"); + pw = pwcopy(pw); + + permanently_set_uid(pw); + + init_rng(); + seed_rng(); + arc4random_stir(); + +#ifdef DEBUG_SSH_KEYSIGN + log_init("ssh-keysign", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 0); +#endif + + /* verify that ssh-keysign is enabled by the admin */ + original_real_uid = getuid(); /* XXX readconf.c needs this */ + initialize_options(&options); + (void)read_config_file(_PATH_HOST_CONFIG_FILE, "", &options, 0); + fill_default_options(&options); + if (options.enable_ssh_keysign != 1) + fatal("ssh-keysign not enabled in %s", + _PATH_HOST_CONFIG_FILE); + + if (key_fd[0] == -1 && key_fd[1] == -1) + fatal("could not open any host key"); + + SSLeay_add_all_algorithms(); + for (i = 0; i < 256; i++) + rnd[i] = arc4random(); + RAND_seed(rnd, sizeof(rnd)); + + found = 0; + for (i = 0; i < 2; i++) { + keys[i] = NULL; + if (key_fd[i] == -1) + continue; + keys[i] = key_load_private_pem(key_fd[i], KEY_UNSPEC, + NULL, NULL); + close(key_fd[i]); + if (keys[i] != NULL) + found = 1; + } + if (!found) + fatal("no hostkey found"); + + buffer_init(&b); + if (ssh_msg_recv(STDIN_FILENO, &b) < 0) + fatal("ssh_msg_recv failed"); + if (buffer_get_char(&b) != version) + fatal("bad version"); + fd = buffer_get_int(&b); + if ((fd == STDIN_FILENO) || (fd == STDOUT_FILENO)) + fatal("bad fd"); + if ((host = get_local_name(fd)) == NULL) + fatal("cannot get sockname for fd"); + + data = buffer_get_string(&b, &dlen); + if (valid_request(pw, host, &key, data, dlen) < 0) + fatal("not a valid request"); + xfree(host); + + found = 0; + for (i = 0; i < 2; i++) { + if (keys[i] != NULL && + key_equal(key, keys[i])) { + found = 1; + break; + } + } + if (!found) + fatal("no matching hostkey found"); + + if (key_sign(keys[i], &signature, &slen, data, dlen) != 0) + fatal("key_sign failed"); + xfree(data); + + /* send reply */ + buffer_clear(&b); + buffer_put_string(&b, signature, slen); + if (ssh_msg_send(STDOUT_FILENO, version, &b) == -1) + fatal("ssh_msg_send failed"); + + return (0); +} diff --git a/crypto/openssh-3.9p1/ssh-rsa.c b/crypto/openssh-3.9p1/ssh-rsa.c new file mode 100644 index 0000000000..6e3be0a7ec --- /dev/null +++ b/crypto/openssh-3.9p1/ssh-rsa.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2000, 2003 Markus Friedl + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "includes.h" +RCSID("$OpenBSD: ssh-rsa.c,v 1.31 2003/11/10 16:23:41 jakob Exp $"); + +#include +#include + +#include "xmalloc.h" +#include "log.h" +#include "buffer.h" +#include "bufaux.h" +#include "key.h" +#include "compat.h" +#include "ssh.h" + +static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); + +/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ +int +ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, + const u_char *data, u_int datalen) +{ + const EVP_MD *evp_md; + EVP_MD_CTX md; + u_char digest[EVP_MAX_MD_SIZE], *sig; + u_int slen, dlen, len; + int ok, nid; + Buffer b; + + if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + error("ssh_rsa_sign: no RSA key"); + return -1; + } + nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; + if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { + error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid); + return -1; + } + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, &dlen); + + slen = RSA_size(key->rsa); + sig = xmalloc(slen); + + ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); + memset(digest, 'd', sizeof(digest)); + + if (ok != 1) { + int ecode = ERR_get_error(); + error("ssh_rsa_sign: RSA_sign failed: %s", + ERR_error_string(ecode, NULL)); + xfree(sig); + return -1; + } + if (len < slen) { + u_int diff = slen - len; + debug("slen %u > len %u", slen, len); + memmove(sig + diff, sig, len); + memset(sig, 0, diff); + } else if (len > slen) { + error("ssh_rsa_sign: slen %u slen2 %u", slen, len); + xfree(sig); + return -1; + } + /* encode signature */ + buffer_init(&b); + buffer_put_cstring(&b, "ssh-rsa"); + buffer_put_string(&b, sig, slen); + len = buffer_len(&b); + if (lenp != NULL) + *lenp = len; + if (sigp != NULL) { + *sigp = xmalloc(len); + memcpy(*sigp, buffer_ptr(&b), len); + } + buffer_free(&b); + memset(sig, 's', slen); + xfree(sig); + + return 0; +} + +int +ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, + const u_char *data, u_int datalen) +{ + Buffer b; + const EVP_MD *evp_md; + EVP_MD_CTX md; + char *ktype; + u_char digest[EVP_MAX_MD_SIZE], *sigblob; + u_int len, dlen, modlen; + int rlen, ret, nid; + + if (key == NULL || key->type != KEY_RSA || key->rsa == NULL) { + error("ssh_rsa_verify: no RSA key"); + return -1; + } + if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits", + BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); + return -1; + } + buffer_init(&b); + buffer_append(&b, signature, signaturelen); + ktype = buffer_get_string(&b, NULL); + if (strcmp("ssh-rsa", ktype) != 0) { + error("ssh_rsa_verify: cannot handle type %s", ktype); + buffer_free(&b); + xfree(ktype); + return -1; + } + xfree(ktype); + sigblob = buffer_get_string(&b, &len); + rlen = buffer_len(&b); + buffer_free(&b); + if (rlen != 0) { + error("ssh_rsa_verify: remaining bytes in signature %d", rlen); + xfree(sigblob); + return -1; + } + /* RSA_verify expects a signature of RSA_size */ + modlen = RSA_size(key->rsa); + if (len > modlen) { + error("ssh_rsa_verify: len %u > modlen %u", len, modlen); + xfree(sigblob); + return -1; + } else if (len < modlen) { + u_int diff = modlen - len; + debug("ssh_rsa_verify: add padding: modlen %u > len %u", + modlen, len); + sigblob = xrealloc(sigblob, modlen); + memmove(sigblob + diff, sigblob, len); + memset(sigblob, 0, diff); + len = modlen; + } + nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; + if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { + error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid); + xfree(sigblob); + return -1; + } + EVP_DigestInit(&md, evp_md); + EVP_DigestUpdate(&md, data, datalen); + EVP_DigestFinal(&md, digest, &dlen); + + ret = openssh_RSA_verify(nid, digest, dlen, sigblob, len, key->rsa); + memset(digest, 'd', sizeof(digest)); + memset(sigblob, 's', len); + xfree(sigblob); + debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : ""); + return ret; +} + +/* + * See: + * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn + */ +/* + * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) + * oiw(14) secsig(3) algorithms(2) 26 } + */ +static const u_char id_sha1[] = { + 0x30, 0x21, /* type Sequence, length 0x21 (33) */ + 0x30, 0x09, /* type Sequence, length 0x09 */ + 0x06, 0x05, /* type OID, length 0x05 */ + 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ + 0x05, 0x00, /* NULL */ + 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ +}; +/* + * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) + * rsadsi(113549) digestAlgorithm(2) 5 } + */ +static const u_char id_md5[] = { + 0x30, 0x20, /* type Sequence, length 0x20 (32) */ + 0x30, 0x0c, /* type Sequence, length 0x09 */ + 0x06, 0x08, /* type OID, length 0x05 */ + 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */ + 0x05, 0x00, /* NULL */ + 0x04, 0x10 /* Octet string, length 0x10 (16), followed by md5 hash */ +}; + +static int +openssh_RSA_verify(int type, u_char *hash, u_int hashlen, + u_char *sigbuf, u_int siglen, RSA *rsa) +{ + u_int ret, rsasize, oidlen = 0, hlen = 0; + int len; + const u_char *oid = NULL; + u_char *decrypted = NULL; + + ret = 0; + switch (type) { + case NID_sha1: + oid = id_sha1; + oidlen = sizeof(id_sha1); + hlen = 20; + break; + case NID_md5: + oid = id_md5; + oidlen = sizeof(id_md5); + hlen = 16; + break; + default: + goto done; + break; + } + if (hashlen != hlen) { + error("bad hashlen"); + goto done; + } + rsasize = RSA_size(rsa); + if (siglen == 0 || siglen > rsasize) { + error("bad siglen"); + goto done; + } + decrypted = xmalloc(rsasize); + if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, + RSA_PKCS1_PADDING)) < 0) { + error("RSA_public_decrypt failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto done; + } + if (len != hlen + oidlen) { + error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); + goto done; + } + if (memcmp(decrypted, oid, oidlen) != 0) { + error("oid mismatch"); + goto done; + } + if (memcmp(decrypted + oidlen, hash, hlen) != 0) { + error("hash mismatch"); + goto done; + } + ret = 1; +done: + if (decrypted) + xfree(decrypted); + return ret; +} diff --git a/crypto/openssh-3.9p1/ssh.1 b/crypto/openssh-3.9p1/ssh.1 new file mode 100644 index 0000000000..0ff77ea296 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh.1 @@ -0,0 +1,1134 @@ +.\" -*- nroff -*- +.\" +.\" Author: Tatu Ylonen +.\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +.\" All rights reserved +.\" +.\" 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". +.\" +.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. +.\" Copyright (c) 1999 Aaron Campbell. All rights reserved. +.\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $OpenBSD: ssh.1,v 1.194 2004/08/12 21:41:13 jakob Exp $ +.Dd September 25, 1999 +.Dt SSH 1 +.Os +.Sh NAME +.Nm ssh +.Nd OpenSSH SSH client (remote login program) +.Sh SYNOPSIS +.Nm ssh +.Op Fl 1246AaCfgkMNnqsTtVvXxY +.Op Fl b Ar bind_address +.Op Fl c Ar cipher_spec +.Bk -words +.Op Fl D Ar port +.Op Fl e Ar escape_char +.Op Fl F Ar configfile +.Op Fl i Ar identity_file +.Oo Fl L Xo +.Sm off +.Ar port : +.Ar host : +.Ar hostport +.Sm on +.Xc +.Oc +.Ek +.Op Fl l Ar login_name +.Op Fl m Ar mac_spec +.Op Fl o Ar option +.Bk -words +.Op Fl p Ar port +.Ek +.Oo Fl R Xo +.Sm off +.Ar port : +.Ar host : +.Ar hostport +.Sm on +.Xc +.Oc +.Op Fl S Ar ctl +.Oo Ar user Ns @ Oc Ns Ar hostname +.Op Ar command +.Sh DESCRIPTION +.Nm +(SSH client) is a program for logging into a remote machine and for +executing commands on 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. +.Pp +.Nm +connects and logs into the specified +.Ar hostname +(with optional +.Ar user +name). +The user must prove +his/her identity to the remote machine using one of several methods +depending on the protocol version used. +.Pp +If +.Ar command +is specified, +.Ar command +is executed on the remote host instead of a login shell. +.Ss SSH protocol version 1 +First, if the machine the user logs in from is listed in +.Pa /etc/hosts.equiv +or +.Pa /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 +.Pa .rhosts +or +.Pa .shosts +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. +.Pp +The second authentication method is the +.Em rhosts +or +.Em hosts.equiv +method combined with RSA-based host authentication. +It means that if the login would be permitted by +.Pa $HOME/.rhosts , +.Pa $HOME/.shosts , +.Pa /etc/hosts.equiv , +or +.Pa /etc/shosts.equiv , +and if additionally the server can verify the client's +host key (see +.Pa /etc/ssh/ssh_known_hosts +and +.Pa $HOME/.ssh/known_hosts +in the +.Sx FILES +section), only then is login permitted. +This authentication method closes security holes due to IP +spoofing, DNS spoofing and routing spoofing. +[Note to the administrator: +.Pa /etc/hosts.equiv , +.Pa $HOME/.rhosts , +and the rlogin/rsh protocol in general, are inherently insecure and should be +disabled if security is desired.] +.Pp +As a third authentication method, +.Nm +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. +.Pp +The file +.Pa $HOME/.ssh/authorized_keys +lists the public keys that are permitted for logging in. +When the user logs in, the +.Nm +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 +.Nm +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. +.Pp +.Nm +implements the RSA authentication protocol automatically. +The user creates his/her RSA key pair by running +.Xr ssh-keygen 1 . +This stores the private key in +.Pa $HOME/.ssh/identity +and stores the public key in +.Pa $HOME/.ssh/identity.pub +in the user's home directory. +The user should then copy the +.Pa identity.pub +to +.Pa $HOME/.ssh/authorized_keys +in his/her home directory on the remote machine (the +.Pa authorized_keys +file corresponds to the conventional +.Pa $HOME/.rhosts +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 +.Em rhosts +authentication. +.Pp +The most convenient way to use RSA authentication may be with an +authentication agent. +See +.Xr ssh-agent 1 +for more information. +.Pp +If other authentication methods fail, +.Nm +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. +.Ss SSH protocol version 2 +When a user connects using protocol version 2, +similar authentication methods are available. +Using the default values for +.Cm PreferredAuthentications , +the client will try to authenticate first using the hostbased method; +if this method fails, public key authentication is attempted, +and finally if this method fails, keyboard-interactive and +password authentication are tried. +.Pp +The public key method is similar to RSA authentication described +in the previous section and allows the RSA or DSA algorithm to be used: +The client uses his private key, +.Pa $HOME/.ssh/id_dsa +or +.Pa $HOME/.ssh/id_rsa , +to sign the session identifier and sends the result to the server. +The server checks whether the matching public key is listed in +.Pa $HOME/.ssh/authorized_keys +and grants access if both the key is found and the signature is correct. +The session identifier is derived from a shared Diffie-Hellman value +and is only known to the client and the server. +.Pp +If public key authentication fails or is not available, a password +can be sent encrypted to the remote host to prove the user's identity. +.Pp +Additionally, +.Nm +supports hostbased or challenge response authentication. +.Pp +Protocol 2 provides additional mechanisms for confidentiality +(the traffic is encrypted using AES, 3DES, Blowfish, CAST128 or Arcfour) +and integrity (hmac-md5, hmac-sha1, hmac-ripemd160). +Note that protocol 1 lacks a strong mechanism for ensuring the +integrity of the connection. +.Ss Login session and remote execution +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. +.Pp +If a pseudo-terminal has been allocated (normal login session), the +user may use the escape characters noted below. +.Pp +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 +.Dq none +will also make the session transparent even if a tty is used. +.Pp +The session terminates when the command or shell on the remote +machine exits and all X11 and TCP/IP connections have been closed. +The exit status of the remote program is returned as the exit status of +.Nm ssh . +.Ss Escape Characters +When a pseudo-terminal has been requested, +.Nm +supports a number of functions through the use of an escape character. +.Pp +A single tilde character can be sent as +.Ic ~~ +or by following the tilde by a character other than those described below. +The escape character must always follow a newline to be interpreted as +special. +The escape character can be changed in configuration files using the +.Cm EscapeChar +configuration directive or on the command line by the +.Fl e +option. +.Pp +The supported escapes (assuming the default +.Ql ~ ) +are: +.Bl -tag -width Ds +.It Cm ~. +Disconnect. +.It Cm ~^Z +Background +.Nm ssh . +.It Cm ~# +List forwarded connections. +.It Cm ~& +Background +.Nm +at logout when waiting for forwarded connection / X11 sessions to terminate. +.It Cm ~? +Display a list of escape characters. +.It Cm ~B +Send a BREAK to the remote system +(only useful for SSH protocol version 2 and if the peer supports it). +.It Cm ~C +Open command line. +Currently this allows the addition of port forwardings using the +.Fl L +and +.Fl R +options (see below). +It also allows the cancellation of existing remote port-forwardings +using +.Fl KR Ar hostport . +Basic help is available, using the +.Fl h +option. +.It Cm ~R +Request rekeying of the connection +(only useful for SSH protocol version 2 and if the peer supports it). +.El +.Ss X11 and TCP forwarding +If the +.Cm ForwardX11 +variable is set to +.Dq yes +(or see the description of the +.Fl X +and +.Fl x +options described later) +and the user is using X11 (the +.Ev DISPLAY +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 +.Ev DISPLAY . +Forwarding of X11 connections can be +configured on the command line or in configuration files. +.Pp +The +.Ev DISPLAY +value set by +.Nm +will point to the server machine, but with a display number greater than zero. +This is normal, and happens because +.Nm +creates a +.Dq proxy +X server on the server machine for forwarding the +connections over the encrypted channel. +.Pp +.Nm +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). +.Pp +If the +.Cm ForwardAgent +variable is set to +.Dq yes +(or see the description of the +.Fl A +and +.Fl a +options described later) and +the user is using an authentication agent, the connection to the agent +is automatically forwarded to the remote side. +.Pp +Forwarding of arbitrary TCP/IP connections over the secure channel can +be specified either on the 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 through firewalls. +.Ss Server authentication +.Nm +automatically maintains and checks a database containing +identifications for all hosts it has ever been used with. +Host keys are stored in +.Pa $HOME/.ssh/known_hosts +in the user's home directory. +Additionally, the file +.Pa /etc/ssh/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, +.Nm +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 +.Cm StrictHostKeyChecking +option can be used to prevent logins to machines whose +host key is not known or has changed. +.Pp +.Nm +can be configured to verify host identification using fingerprint resource +records (SSHFP) published in DNS. +The +.Cm VerifyHostKeyDNS +option can be used to control how DNS lookups are performed. +SSHFP resource records can be generated using +.Xr ssh-keygen 1 . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 1 +Forces +.Nm +to try protocol version 1 only. +.It Fl 2 +Forces +.Nm +to try protocol version 2 only. +.It Fl 4 +Forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +Forces +.Nm +to use IPv6 addresses only. +.It Fl A +Enables forwarding of the authentication agent connection. +This can also be specified on a per-host basis in a configuration file. +.Pp +Agent forwarding should be enabled with caution. +Users with the ability to bypass file permissions on the remote host +(for the agent's Unix-domain socket) +can access the local agent through the forwarded connection. +An attacker cannot obtain key material from the agent, +however they can perform operations on the keys that enable them to +authenticate using the identities loaded into the agent. +.It Fl a +Disables forwarding of the authentication agent connection. +.It Fl b Ar bind_address +Specify the interface to transmit from on machines with multiple +interfaces or aliased addresses. +.It Fl 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 +.Xr gzip 1 , +and the +.Dq level +can be controlled by the +.Cm CompressionLevel +option for protocol version 1. +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 +.Cm Compression +option. +.It Fl c Ar cipher_spec +Selects the cipher specification for encrypting the session. +.Pp +Protocol version 1 allows specification of a single cipher. +The suported values are +.Dq 3des , +.Dq blowfish +and +.Dq des . +.Ar 3des +(triple-des) is an encrypt-decrypt-encrypt triple with three different keys. +It is believed to be secure. +.Ar blowfish +is a fast block cipher; it appears very secure and is much faster than +.Ar 3des . +.Ar des +is only supported in the +.Nm +client for interoperability with legacy protocol 1 implementations +that do not support the +.Ar 3des +cipher. +Its use is strongly discouraged due to cryptographic weaknesses. +The default is +.Dq 3des . +.Pp +For protocol version 2 +.Ar cipher_spec +is a comma-separated list of ciphers +listed in order of preference. +The supported ciphers are +.Dq 3des-cbc , +.Dq aes128-cbc , +.Dq aes192-cbc , +.Dq aes256-cbc , +.Dq aes128-ctr , +.Dq aes192-ctr , +.Dq aes256-ctr , +.Dq arcfour , +.Dq blowfish-cbc , +and +.Dq cast128-cbc . +The default is +.Bd -literal + ``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour, + aes192-cbc,aes256-cbc'' +.Ed +.It Fl D Ar port +Specifies a local +.Dq dynamic +application-level port forwarding. +This works by allocating a socket to listen to +.Ar port +on the local side, and whenever a connection is made to this port, the +connection is forwarded over the secure channel, and the application +protocol is then used to determine where to connect to from the +remote machine. +Currently the SOCKS4 and SOCKS5 protocols are supported, and +.Nm +will act as a SOCKS server. +Only root can forward privileged ports. +Dynamic port forwardings can also be specified in the configuration file. +.It Fl e Ar ch | ^ch | none +Sets the escape character for sessions with a pty (default: +.Ql ~ ) . +The escape character is only recognized at the beginning of a line. +The escape character followed by a dot +.Pq Ql \&. +closes the connection; +followed by control-Z suspends the connection; +and followed by itself sends the escape character once. +Setting the character to +.Dq none +disables any escapes and makes the session fully transparent. +.It Fl F Ar configfile +Specifies an alternative per-user configuration file. +If a configuration file is given on the command line, +the system-wide configuration file +.Pq Pa /etc/ssh/ssh_config +will be ignored. +The default for the per-user configuration file is +.Pa $HOME/.ssh/config . +.It Fl f +Requests +.Nm +to go to background just before command execution. +This is useful if +.Nm +is going to ask for passwords or passphrases, but the user +wants it in the background. +This implies +.Fl n . +The recommended way to start X11 programs at a remote site is with +something like +.Ic ssh -f host xterm . +.It Fl g +Allows remote hosts to connect to local forwarded ports. +.It Fl I Ar smartcard_device +Specifies which smartcard device to use. +The argument is the device +.Nm +should use to communicate with a smartcard used for storing the user's +private RSA key. +.It Fl i Ar identity_file +Selects a file from which the identity (private key) for +RSA or DSA authentication is read. +The default is +.Pa $HOME/.ssh/identity +for protocol version 1, and +.Pa $HOME/.ssh/id_rsa +and +.Pa $HOME/.ssh/id_dsa +for protocol version 2. +Identity files may also be specified on +a per-host basis in the configuration file. +It is possible to have multiple +.Fl i +options (and multiple identities specified in +configuration files). +.It Fl k +Disables forwarding (delegation) of GSSAPI credentials to the server. +.It Fl L Xo +.Sm off +.Ar port : host : hostport +.Sm on +.Xc +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 +.Ar 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 +.Ar host +port +.Ar hostport +from the remote machine. +Port forwardings can also be specified in the configuration file. +Only root can forward privileged ports. +IPv6 addresses can be specified with an alternative syntax: +.Sm off +.Xo +.Ar port No / Ar host No / +.Ar hostport . +.Xc +.Sm on +.It Fl l Ar login_name +Specifies the user to log in as on the remote machine. +This also may be specified on a per-host basis in the configuration file. +.It Fl M +Places the +.Nm +client into +.Dq master +mode for connection sharing. +Refer to the description of +.Cm ControlMaster +in +.Xr ssh_config 5 +for details. +.It Fl m Ar mac_spec +Additionally, for protocol version 2 a comma-separated list of MAC +(message authentication code) algorithms can +be specified in order of preference. +See the +.Cm MACs +keyword for more information. +.It Fl N +Do not execute a remote command. +This is useful for just forwarding ports +(protocol version 2 only). +.It Fl n +Redirects stdin from +.Pa /dev/null +(actually, prevents reading from stdin). +This must be used when +.Nm +is run in the background. +A common trick is to use this to run X11 programs on a remote machine. +For example, +.Ic 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 +.Nm +program will be put in the background. +(This does not work if +.Nm +needs to ask for a password or passphrase; see also the +.Fl f +option.) +.It Fl o Ar option +Can be used to give options in the format used in the configuration file. +This is useful for specifying options for which there is no separate +command-line flag. +For full details of the options listed below, and their possible values, see +.Xr ssh_config 5 . +.Pp +.Bl -tag -width Ds -offset indent -compact +.It AddressFamily +.It BatchMode +.It BindAddress +.It ChallengeResponseAuthentication +.It CheckHostIP +.It Cipher +.It Ciphers +.It ClearAllForwardings +.It Compression +.It CompressionLevel +.It ConnectionAttempts +.It ConnectTimeout +.It ControlMaster +.It ControlPath +.It DynamicForward +.It EscapeChar +.It ForwardAgent +.It ForwardX11 +.It ForwardX11Trusted +.It GatewayPorts +.It GlobalKnownHostsFile +.It GSSAPIAuthentication +.It GSSAPIDelegateCredentials +.It Host +.It HostbasedAuthentication +.It HostKeyAlgorithms +.It HostKeyAlias +.It HostName +.It IdentityFile +.It IdentitiesOnly +.It LocalForward +.It LogLevel +.It MACs +.It NoHostAuthenticationForLocalhost +.It NumberOfPasswordPrompts +.It PasswordAuthentication +.It Port +.It PreferredAuthentications +.It Protocol +.It ProxyCommand +.It PubkeyAuthentication +.It RemoteForward +.It RhostsRSAAuthentication +.It RSAAuthentication +.It SendEnv +.It ServerAliveInterval +.It ServerAliveCountMax +.It SmartcardDevice +.It StrictHostKeyChecking +.It TCPKeepAlive +.It UsePrivilegedPort +.It User +.It UserKnownHostsFile +.It VerifyHostKeyDNS +.It XAuthLocation +.El +.It Fl p Ar port +Port to connect to on the remote host. +This can be specified on a +per-host basis in the configuration file. +.It Fl q +Quiet mode. +Causes all warning and diagnostic messages to be suppressed. +.It Fl R Xo +.Sm off +.Ar port : host : hostport +.Sm on +.Xc +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 +.Ar 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 +.Ar host +port +.Ar 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. +IPv6 addresses can be specified with an alternative syntax: +.Sm off +.Xo +.Ar port No / Ar host No / +.Ar hostport . +.Xc +.Sm on +.It Fl S Ar ctl +Specifies the location of a control socket for connection sharing. +Refer to the description of +.Cm ControlPath +and +.Cm ControlMaster +in +.Xr ssh_config 5 +for details. +.It Fl s +May be used to request invocation of a subsystem on the remote system. +Subsystems are a feature of the SSH2 protocol which facilitate the use +of SSH as a secure transport for other applications (eg.\& +.Xr sftp 1 ) . +The subsystem is specified as the remote command. +.It Fl T +Disable pseudo-tty allocation. +.It Fl t +Force pseudo-tty allocation. +This can be used to execute arbitrary +screen-based programs on a remote machine, which can be very useful, +e.g., when implementing menu services. +Multiple +.Fl t +options force tty allocation, even if +.Nm +has no local tty. +.It Fl V +Display the version number and exit. +.It Fl v +Verbose mode. +Causes +.Nm +to print debugging messages about its progress. +This is helpful in +debugging connection, authentication, and configuration problems. +Multiple +.Fl v +options increase the verbosity. +The maximum is 3. +.It Fl X +Enables X11 forwarding. +This can also be specified on a per-host basis in a configuration file. +.Pp +X11 forwarding should be enabled with caution. +Users with the ability to bypass file permissions on the remote host +(for the user's X authorization database) +can access the local X11 display through the forwarded connection. +An attacker may then be able to perform activities such as keystroke monitoring. +.It Fl x +Disables X11 forwarding. +.It Fl Y +Enables trusted X11 forwarding. +.El +.Sh CONFIGURATION FILES +.Nm +may additionally obtain configuration data from +a per-user configuration file and a system-wide configuration file. +The file format and configuration options are described in +.Xr ssh_config 5 . +.Sh ENVIRONMENT +.Nm +will normally set the following environment variables: +.Bl -tag -width LOGNAME +.It Ev DISPLAY +The +.Ev DISPLAY +variable indicates the location of the X11 server. +It is automatically set by +.Nm +to point to a value of the form +.Dq hostname:n +where hostname indicates +the host where the shell runs, and n is an integer \*(Ge 1. +.Nm +uses this special value to forward X11 connections over the secure +channel. +The user should normally not set +.Ev DISPLAY +explicitly, as that +will render the X11 connection insecure (and will require the user to +manually copy any required authorization cookies). +.It Ev HOME +Set to the path of the user's home directory. +.It Ev LOGNAME +Synonym for +.Ev USER ; +set for compatibility with systems that use this variable. +.It Ev MAIL +Set to the path of the user's mailbox. +.It Ev PATH +Set to the default +.Ev PATH , +as specified when compiling +.Nm ssh . +.It Ev SSH_ASKPASS +If +.Nm +needs a passphrase, it will read the passphrase from the current +terminal if it was run from a terminal. +If +.Nm +does not have a terminal associated with it but +.Ev DISPLAY +and +.Ev SSH_ASKPASS +are set, it will execute the program specified by +.Ev SSH_ASKPASS +and open an X11 window to read the passphrase. +This is particularly useful when calling +.Nm +from a +.Pa .Xsession +or related script. +(Note that on some machines it +may be necessary to redirect the input from +.Pa /dev/null +to make this work.) +.It Ev SSH_AUTH_SOCK +Identifies the path of a unix-domain socket used to communicate with the +agent. +.It Ev SSH_CONNECTION +Identifies the client and server ends of the connection. +The variable contains +four space-separated values: client ip-address, client port number, +server ip-address and server port number. +.It Ev SSH_ORIGINAL_COMMAND +The variable contains the original command line if a forced command +is executed. +It can be used to extract the original arguments. +.It Ev 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. +.It Ev TZ +The timezone variable is set to indicate the present timezone if it +was set when the daemon was started (i.e., the daemon passes the value +on to new connections). +.It Ev USER +Set to the name of the user logging in. +.El +.Pp +Additionally, +.Nm +reads +.Pa $HOME/.ssh/environment , +and adds lines of the format +.Dq VARNAME=value +to the environment if the file exists and if users are allowed to +change their environment. +For more information, see the +.Cm PermitUserEnvironment +option in +.Xr sshd_config 5 . +.Sh FILES +.Bl -tag -width Ds +.It Pa $HOME/.ssh/known_hosts +Records host keys for all hosts the user has logged into that are not +in +.Pa /etc/ssh/ssh_known_hosts . +See +.Xr sshd 8 . +.It Pa $HOME/.ssh/identity, $HOME/.ssh/id_dsa, $HOME/.ssh/id_rsa +Contains the authentication identity of the user. +They are for protocol 1 RSA, protocol 2 DSA, and protocol 2 RSA, respectively. +These files +contain sensitive data and should be readable by the user but not +accessible by others (read/write/execute). +Note that +.Nm +ignores a private key file if it is 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 3DES. +.It Pa $HOME/.ssh/identity.pub, $HOME/.ssh/id_dsa.pub, $HOME/.ssh/id_rsa.pub +Contains the public key for authentication (public part of the +identity file in human-readable form). +The contents of the +.Pa $HOME/.ssh/identity.pub +file should be added to the file +.Pa $HOME/.ssh/authorized_keys +on all machines +where the user wishes to log in using protocol version 1 RSA authentication. +The contents of the +.Pa $HOME/.ssh/id_dsa.pub +and +.Pa $HOME/.ssh/id_rsa.pub +file should be added to +.Pa $HOME/.ssh/authorized_keys +on all machines +where the user wishes to log in using protocol version 2 DSA/RSA authentication. +These files are not +sensitive and can (but need not) be readable by anyone. +These files are +never used automatically and are not necessary; they are only provided for +the convenience of the user. +.It Pa $HOME/.ssh/config +This is the per-user configuration file. +The file format and configuration options are described in +.Xr ssh_config 5 . +Because of the potential for abuse, this file must have strict permissions: +read/write for the user, and not accessible by others. +.It Pa $HOME/.ssh/authorized_keys +Lists the public keys (RSA/DSA) that can be used for logging in as this user. +The format of this file is described in the +.Xr sshd 8 +manual page. +In the simplest form the format is the same as the +.Pa .pub +identity files. +This file is not highly sensitive, but the recommended +permissions are read/write for the user, and not accessible by others. +.It Pa /etc/ssh/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, public key 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 in the +.Xr sshd 8 +manual page. +.Pp +The canonical system name (as returned by name servers) is used by +.Xr sshd 8 +to verify the client host when logging in; other names are needed because +.Nm +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. +.It Pa /etc/ssh/ssh_config +Systemwide configuration file. +The file format and configuration options are described in +.Xr ssh_config 5 . +.It Pa /etc/ssh/ssh_host_key, /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_rsa_key +These three files contain the private parts of the host keys +and are used for +.Cm RhostsRSAAuthentication +and +.Cm HostbasedAuthentication . +If the protocol version 1 +.Cm RhostsRSAAuthentication +method is used, +.Nm +must be setuid root, since the host key is readable only by root. +For protocol version 2, +.Nm +uses +.Xr ssh-keysign 8 +to access the host keys for +.Cm HostbasedAuthentication . +This eliminates the requirement that +.Nm +be setuid root when that authentication method is used. +By default +.Nm +is not setuid root. +.It Pa $HOME/.rhosts +This file is used in +.Em rhosts +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. +On some machines this file may need to be +world-readable if the user's home directory is on a NFS partition, +because +.Xr sshd 8 +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. +.Pp +Note that by default +.Xr sshd 8 +will be installed so that it requires successful RSA host +authentication before permitting +.Em rhosts +authentication. +If the server machine does not have the client's host key in +.Pa /etc/ssh/ssh_known_hosts , +it can be stored in +.Pa $HOME/.ssh/known_hosts . +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 to +.Pa $HOME/.ssh/known_hosts . +.It Pa $HOME/.shosts +This file is used exactly the same way as +.Pa .rhosts . +The purpose for +having this file is to be able to use rhosts authentication with +.Nm +without permitting login with +.Xr rlogin +or +.Xr rsh 1 . +.It Pa /etc/hosts.equiv +This file is used during +.Em rhosts +authentication. +It contains +canonical hosts names, one per line (the full format is described in the +.Xr sshd 8 +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. +.It Pa /etc/shosts.equiv +This file is processed exactly as +.Pa /etc/hosts.equiv . +This file may be useful to permit logins using +.Nm +but not using rsh/rlogin. +.It Pa /etc/ssh/sshrc +Commands in this file are executed by +.Nm +when the user logs in just before the user's shell (or command) is started. +See the +.Xr sshd 8 +manual page for more information. +.It Pa $HOME/.ssh/rc +Commands in this file are executed by +.Nm +when the user logs in just before the user's shell (or command) is +started. +See the +.Xr sshd 8 +manual page for more information. +.It Pa $HOME/.ssh/environment +Contains additional definitions for environment variables, see section +.Sx ENVIRONMENT +above. +.El +.Sh DIAGNOSTICS +.Nm +exits with the exit status of the remote command or with 255 +if an error occurred. +.Sh SEE ALSO +.Xr gzip 1 , +.Xr rsh 1 , +.Xr scp 1 , +.Xr sftp 1 , +.Xr ssh-add 1 , +.Xr ssh-agent 1 , +.Xr ssh-keygen 1 , +.Xr telnet 1 , +.Xr hosts.equiv 5 , +.Xr ssh_config 5 , +.Xr ssh-keysign 8 , +.Xr sshd 8 +.Rs +.%A T. Ylonen +.%A T. Kivinen +.%A M. Saarinen +.%A T. Rinne +.%A S. Lehtinen +.%T "SSH Protocol Architecture" +.%N draft-ietf-secsh-architecture-12.txt +.%D January 2002 +.%O work in progress material +.Re +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. diff --git a/crypto/openssh-3.9p1/ssh.c b/crypto/openssh-3.9p1/ssh.c new file mode 100644 index 0000000000..1419f98749 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh.c @@ -0,0 +1,1360 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * 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. + * + * 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". + * + * Copyright (c) 1999 Niels Provos. All rights reserved. + * Copyright (c) 2000, 2001, 2002, 2003 Markus Friedl. All rights reserved. + * + * Modified to work with SSL by Niels Provos + * in Canada (German citizen). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: ssh.c,v 1.224 2004/07/28 09:40:29 markus Exp $"); + +#include +#include + +#include "ssh.h" +#include "ssh1.h" +#include "ssh2.h" +#include "compat.h" +#include "cipher.h" +#include "xmalloc.h" +#include "packet.h" +#include "buffer.h" +#include "bufaux.h" +#include "channels.h" +#include "key.h" +#include "authfd.h" +#include "authfile.h" +#include "pathnames.h" +#include "dispatch.h" +#include "clientloop.h" +#include "log.h" +#include "readconf.h" +#include "sshconnect.h" +#include "misc.h" +#include "kex.h" +#include "mac.h" +#include "sshpty.h" +#include "match.h" +#include "msg.h" +#include "monitor_fdpass.h" +#include "uidswap.h" + +#ifdef SMARTCARD +#include "scard.h" +#endif + +extern char *__progname; + +/* Flag indicating whether debug mode is on. This can be set on the command line. */ +int debug_flag = 0; + +/* Flag indicating whether a tty should be allocated */ +int tty_flag = 0; +int no_tty_flag = 0; +int force_tty_flag = 0; + +/* don't exec a shell */ +int no_shell_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 passphrase 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; + +/* optional user configfile */ +char *config = NULL; + +/* + * 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; + +/* socket address the host resolves to */ +struct sockaddr_storage hostaddr; + +/* Private host keys. */ +Sensitive sensitive_data; + +/* Original real UID. */ +uid_t original_real_uid; +uid_t original_effective_uid; + +/* command to be executed */ +Buffer command; + +/* Should we execute a command or invoke a subsystem? */ +int subsystem_flag = 0; + +/* # of replies received for global requests */ +static int client_global_request_id = 0; + +/* pid of proxycommand child process */ +pid_t proxy_command_pid = 0; + +/* fd to control socket */ +int control_fd = -1; + +/* Only used in control client mode */ +volatile sig_atomic_t control_client_terminate = 0; +u_int control_server_pid = 0; + +/* Prints a help message to the user. This function never returns. */ + +static void +usage(void) +{ + fprintf(stderr, +"usage: ssh [-1246AaCfghkMNnqsTtVvXxY] [-b bind_address] [-c cipher_spec]\n" +" [-D port] [-e escape_char] [-F configfile] [-i identity_file]\n" +" [-L port:host:hostport] [-l login_name] [-m mac_spec] [-o option]\n" +" [-p port] [-R port:host:hostport] [-S ctl] [user@]hostname [command]\n" + ); + exit(1); +} + +static int ssh_session(void); +static int ssh_session2(void); +static void load_public_identity_files(void); +static void control_client(const char *path); + +/* + * Main program for the ssh client. + */ +int +main(int ac, char **av) +{ + int i, opt, exit_status; + u_short fwd_port, fwd_host_port; + char sfwd_port[6], sfwd_host_port[6]; + char *p, *cp, *line, buf[256]; + struct stat st; + struct passwd *pw; + int dummy; + extern int optind, optreset; + extern char *optarg; + + __progname = ssh_get_progname(av[0]); + init_rng(); + + /* + * 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(); + + /* + * 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). + */ + PRIV_END; + +#ifdef HAVE_SETRLIMIT + /* If we are installed setuid root be careful to not drop core. */ + if (original_real_uid != original_effective_uid) { + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 0; + if (setrlimit(RLIMIT_CORE, &rlim) < 0) + fatal("setrlimit failed: %.100s", strerror(errno)); + } +#endif + /* Get user data. */ + pw = getpwuid(original_real_uid); + if (!pw) { + logit("You don't exist, go away!"); + exit(1); + } + /* Take a copy of the returned structure. */ + pw = pwcopy(pw); + + /* + * 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); + + /* Initialize option structure to indicate that no values have been set. */ + initialize_options(&options); + + /* Parse command-line arguments. */ + host = NULL; + +again: + while ((opt = getopt(ac, av, + "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:MNPR:S:TVXY")) != -1) { + switch (opt) { + case '1': + options.protocol = SSH_PROTO_1; + break; + case '2': + options.protocol = SSH_PROTO_2; + break; + case '4': + options.address_family = AF_INET; + break; + case '6': + options.address_family = AF_INET6; + break; + 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 'Y': + options.forward_x11 = 1; + options.forward_x11_trusted = 1; + break; + case 'g': + options.gateway_ports = 1; + break; + case 'P': /* deprecated */ + options.use_privileged_port = 0; + break; + case 'a': + options.forward_agent = 0; + break; + case 'A': + options.forward_agent = 1; + break; + case 'k': + options.gss_deleg_creds = 0; + 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 'I': +#ifdef SMARTCARD + options.smartcard_device = xstrdup(optarg); +#else + fprintf(stderr, "no support for smartcards.\n"); +#endif + break; + case 't': + if (tty_flag) + force_tty_flag = 1; + tty_flag = 1; + break; + case 'v': + if (debug_flag == 0) { + debug_flag = 1; + options.log_level = SYSLOG_LEVEL_DEBUG1; + } else { + if (options.log_level < SYSLOG_LEVEL_DEBUG3) + options.log_level++; + break; + } + /* fallthrough */ + case 'V': + fprintf(stderr, "%s, %s\n", + SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); + if (opt == 'V') + exit(0); + break; + case 'q': + options.log_level = SYSLOG_LEVEL_QUIET; + break; + case 'e': + if (optarg[0] == '^' && optarg[2] == 0 && + (u_char) optarg[1] >= 64 && + (u_char) optarg[1] < 128) + options.escape_char = (u_char) optarg[1] & 31; + else if (strlen(optarg) == 1) + options.escape_char = (u_char) optarg[0]; + else if (strcmp(optarg, "none") == 0) + options.escape_char = SSH_ESCAPECHAR_NONE; + else { + fprintf(stderr, "Bad escape character '%s'.\n", + optarg); + exit(1); + } + break; + case 'c': + if (ciphers_valid(optarg)) { + /* SSH2 only */ + options.ciphers = xstrdup(optarg); + options.cipher = SSH_CIPHER_INVALID; + } else { + /* SSH1 only */ + options.cipher = cipher_number(optarg); + if (options.cipher == -1) { + fprintf(stderr, + "Unknown cipher type '%s'\n", + optarg); + exit(1); + } + if (options.cipher == SSH_CIPHER_3DES) + options.ciphers = "3des-cbc"; + else if (options.cipher == SSH_CIPHER_BLOWFISH) + options.ciphers = "blowfish-cbc"; + else + options.ciphers = (char *)-1; + } + break; + case 'm': + if (mac_valid(optarg)) + options.macs = xstrdup(optarg); + else { + fprintf(stderr, "Unknown mac type '%s'\n", + optarg); + exit(1); + } + break; + case 'M': + options.control_master = + (options.control_master >= 1) ? 2 : 1; + break; + case 'p': + options.port = a2port(optarg); + if (options.port == 0) { + fprintf(stderr, "Bad port '%s'\n", optarg); + exit(1); + } + break; + case 'l': + options.user = optarg; + break; + + case 'L': + case 'R': + if (sscanf(optarg, "%5[0123456789]:%255[^:]:%5[0123456789]", + sfwd_port, buf, sfwd_host_port) != 3 && + sscanf(optarg, "%5[0123456789]/%255[^/]/%5[0123456789]", + sfwd_port, buf, sfwd_host_port) != 3) { + fprintf(stderr, + "Bad forwarding specification '%s'\n", + optarg); + usage(); + /* NOTREACHED */ + } + if ((fwd_port = a2port(sfwd_port)) == 0 || + (fwd_host_port = a2port(sfwd_host_port)) == 0) { + fprintf(stderr, + "Bad forwarding port(s) '%s'\n", optarg); + exit(1); + } + if (opt == 'L') + add_local_forward(&options, fwd_port, buf, + fwd_host_port); + else if (opt == 'R') + add_remote_forward(&options, fwd_port, buf, + fwd_host_port); + break; + + case 'D': + fwd_port = a2port(optarg); + if (fwd_port == 0) { + fprintf(stderr, "Bad dynamic port '%s'\n", + optarg); + exit(1); + } + add_local_forward(&options, fwd_port, "socks", 0); + break; + + case 'C': + options.compression = 1; + break; + case 'N': + no_shell_flag = 1; + no_tty_flag = 1; + break; + case 'T': + no_tty_flag = 1; + break; + case 'o': + dummy = 1; + line = xstrdup(optarg); + if (process_config_line(&options, host ? host : "", + line, "command-line", 0, &dummy) != 0) + exit(1); + xfree(line); + break; + case 's': + subsystem_flag = 1; + break; + case 'S': + if (options.control_path != NULL) + free(options.control_path); + options.control_path = xstrdup(optarg); + break; + case 'b': + options.bind_address = optarg; + break; + case 'F': + config = optarg; + break; + default: + usage(); + } + } + + ac -= optind; + av += optind; + + if (ac > 0 && !host && **av != '-') { + if (strrchr(*av, '@')) { + p = xstrdup(*av); + cp = strrchr(p, '@'); + if (cp == NULL || cp == p) + usage(); + options.user = p; + *cp = '\0'; + host = ++cp; + } else + host = *av; + if (ac > 1) { + optind = optreset = 1; + goto again; + } + ac--, av++; + } + + /* Check that we got a host name. */ + if (!host) + usage(); + + SSLeay_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* 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 (!ac) { + /* No command specified - execute shell on a tty. */ + tty_flag = 1; + if (subsystem_flag) { + fprintf(stderr, + "You must specify a subsystem to invoke.\n"); + usage(); + } + } else { + /* A command has been specified. Store it into the buffer. */ + for (i = 0; i < ac; i++) { + if (i) + 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 && !no_shell_flag) + 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; + + /* Force no tty */ + if (no_tty_flag) + tty_flag = 0; + /* Do not allocate a tty if stdin is not a tty. */ + if (!isatty(fileno(stdin)) && !force_tty_flag) { + if (tty_flag) + logit("Pseudo-terminal will not be allocated because stdin is not a terminal."); + tty_flag = 0; + } + + /* + * Initialize "log" output. Since we are the client all output + * actually goes to stderr. + */ + log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, + SYSLOG_FACILITY_USER, 1); + + /* + * Read per-user configuration file. Ignore the system wide config + * file if the user specifies a config file on the command line. + */ + if (config != NULL) { + if (!read_config_file(config, host, &options, 0)) + fatal("Can't open user config file %.100s: " + "%.100s", config, strerror(errno)); + } else { + snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, + _PATH_SSH_USER_CONFFILE); + (void)read_config_file(buf, host, &options, 1); + + /* Read systemwide configuration file after use config. */ + (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, + &options, 0); + } + + /* Fill configuration defaults. */ + fill_default_options(&options); + + channel_set_af(options.address_family); + + /* reinit */ + log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1); + + seed_rng(); + + if (options.user == NULL) + options.user = xstrdup(pw->pw_name); + + if (options.hostname != NULL) + host = options.hostname; + + /* force lowercase for hostkey matching */ + if (options.host_key_alias != NULL) { + for (p = options.host_key_alias; *p; p++) + if (isupper(*p)) + *p = tolower(*p); + } + + if (options.proxy_command != NULL && + strcmp(options.proxy_command, "none") == 0) + options.proxy_command = NULL; + + if (options.control_path != NULL) { + options.control_path = tilde_expand_filename( + options.control_path, original_real_uid); + } + if (options.control_path != NULL && options.control_master == 0) + control_client(options.control_path); /* This doesn't return */ + + /* Open a connection to the remote host. */ + if (ssh_connect(host, &hostaddr, options.port, + options.address_family, options.connection_attempts, +#ifdef HAVE_CYGWIN + options.use_privileged_port, +#else + original_effective_uid == 0 && options.use_privileged_port, +#endif + options.proxy_command) != 0) + exit(1); + + /* + * 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 we cannot access the private keys, load the public keys + * instead and try to execute the ssh-keysign helper instead. + */ + sensitive_data.nkeys = 0; + sensitive_data.keys = NULL; + sensitive_data.external_keysign = 0; + if (options.rhosts_rsa_authentication || + options.hostbased_authentication) { + sensitive_data.nkeys = 3; + sensitive_data.keys = xmalloc(sensitive_data.nkeys * + sizeof(Key)); + + PRIV_START; + sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, + _PATH_HOST_KEY_FILE, "", NULL); + sensitive_data.keys[1] = key_load_private_type(KEY_DSA, + _PATH_HOST_DSA_KEY_FILE, "", NULL); + sensitive_data.keys[2] = key_load_private_type(KEY_RSA, + _PATH_HOST_RSA_KEY_FILE, "", NULL); + PRIV_END; + + if (options.hostbased_authentication == 1 && + sensitive_data.keys[0] == NULL && + sensitive_data.keys[1] == NULL && + sensitive_data.keys[2] == NULL) { + sensitive_data.keys[1] = key_load_public( + _PATH_HOST_DSA_KEY_FILE, NULL); + sensitive_data.keys[2] = key_load_public( + _PATH_HOST_RSA_KEY_FILE, NULL); + sensitive_data.external_keysign = 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. + */ + if (original_effective_uid == 0) { + PRIV_START; + permanently_set_uid(pw); + } + + /* + * Now that we are back to our own permissions, create ~/.ssh + * directory if it doesn\'t already exist. + */ + snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); + if (stat(buf, &st) < 0) + if (mkdir(buf, 0700) < 0) + error("Could not create directory '%.200s'.", buf); + + /* load options.identity_files */ + load_public_identity_files(); + + /* Expand ~ in known host file names. */ + /* XXX mem-leaks: */ + options.system_hostfile = + tilde_expand_filename(options.system_hostfile, original_real_uid); + options.user_hostfile = + tilde_expand_filename(options.user_hostfile, original_real_uid); + options.system_hostfile2 = + tilde_expand_filename(options.system_hostfile2, original_real_uid); + options.user_hostfile2 = + tilde_expand_filename(options.user_hostfile2, original_real_uid); + + signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ + + /* Log into the remote system. This never returns if the login fails. */ + ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw); + + /* We no longer need the private host keys. Clear them now. */ + if (sensitive_data.nkeys != 0) { + for (i = 0; i < sensitive_data.nkeys; i++) { + if (sensitive_data.keys[i] != NULL) { + /* Destroys contents safely */ + debug3("clear hostkey %d", i); + key_free(sensitive_data.keys[i]); + sensitive_data.keys[i] = NULL; + } + } + xfree(sensitive_data.keys); + } + for (i = 0; i < options.num_identity_files; i++) { + if (options.identity_files[i]) { + xfree(options.identity_files[i]); + options.identity_files[i] = NULL; + } + if (options.identity_keys[i]) { + key_free(options.identity_keys[i]); + options.identity_keys[i] = NULL; + } + } + + exit_status = compat20 ? ssh_session2() : ssh_session(); + packet_close(); + + if (options.control_path != NULL && control_fd != -1) + unlink(options.control_path); + + /* + * Send SIGHUP to proxy command if used. We don't wait() in + * case it hangs and instead rely on init to reap the child + */ + if (proxy_command_pid > 1) + kill(proxy_command_pid, SIGHUP); + + return exit_status; +} + +#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" + +static void +x11_get_proto(char **_proto, char **_data) +{ + char cmd[1024]; + char line[512]; + char xdisplay[512]; + static char proto[512], data[512]; + FILE *f; + int got_data = 0, generated = 0, do_unlink = 0, i; + char *display, *xauthdir, *xauthfile; + struct stat st; + + xauthdir = xauthfile = NULL; + *_proto = proto; + *_data = data; + proto[0] = data[0] = '\0'; + + if (!options.xauth_location || + (stat(options.xauth_location, &st) == -1)) { + debug("No xauth program."); + } else { + if ((display = getenv("DISPLAY")) == NULL) { + debug("x11_get_proto: DISPLAY not set"); + return; + } + /* + * Handle FamilyLocal case where $DISPLAY does + * not match an authorization entry. For this we + * just try "xauth list unix:displaynum.screennum". + * XXX: "localhost" match to determine FamilyLocal + * is not perfect. + */ + if (strncmp(display, "localhost:", 10) == 0) { + snprintf(xdisplay, sizeof(xdisplay), "unix:%s", + display + 10); + display = xdisplay; + } + if (options.forward_x11_trusted == 0) { + xauthdir = xmalloc(MAXPATHLEN); + xauthfile = xmalloc(MAXPATHLEN); + strlcpy(xauthdir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN); + if (mkdtemp(xauthdir) != NULL) { + do_unlink = 1; + snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile", + xauthdir); + snprintf(cmd, sizeof(cmd), + "%s -f %s generate %s " SSH_X11_PROTO + " untrusted timeout 1200 2>" _PATH_DEVNULL, + options.xauth_location, xauthfile, display); + debug2("x11_get_proto: %s", cmd); + if (system(cmd) == 0) + generated = 1; + } + } + snprintf(cmd, sizeof(cmd), + "%s %s%s list %s . 2>" _PATH_DEVNULL, + options.xauth_location, + generated ? "-f " : "" , + generated ? xauthfile : "", + display); + debug2("x11_get_proto: %s", cmd); + f = popen(cmd, "r"); + if (f && fgets(line, sizeof(line), f) && + sscanf(line, "%*s %511s %511s", proto, data) == 2) + got_data = 1; + if (f) + pclose(f); + } + + if (do_unlink) { + unlink(xauthfile); + rmdir(xauthdir); + } + if (xauthdir) + xfree(xauthdir); + if (xauthfile) + xfree(xauthfile); + + /* + * 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) { + u_int32_t rnd = 0; + + logit("Warning: No xauth data; " + "using fake authentication data for X11 forwarding."); + strlcpy(proto, SSH_X11_PROTO, sizeof proto); + for (i = 0; i < 16; i++) { + if (i % 4 == 0) + rnd = arc4random(); + snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", + rnd & 0xff); + rnd >>= 8; + } + } +} + +static void +ssh_init_forwarding(void) +{ + int success = 0; + int i; + + /* 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); + success += channel_setup_local_fwd_listener( + options.local_forwards[i].port, + options.local_forwards[i].host, + options.local_forwards[i].host_port, + options.gateway_ports); + } + if (i > 0 && success == 0) + error("Could not request local forwarding."); + + /* 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); + } +} + +static void +check_agent_present(void) +{ + if (options.forward_agent) { + /* Clear agent forwarding if we don\'t have an agent. */ + if (!ssh_agent_present()) + options.forward_agent = 0; + } +} + +static int +ssh_session(void) +{ + int type; + int interactive = 0; + int have_tty = 0; + struct winsize ws; + char *cp; + + /* 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(); + if (type == SSH_SMSG_SUCCESS) + packet_start_compression(options.compression_level); + else if (type == SSH_SMSG_FAILURE) + logit("Warning: Remote host refused compression."); + else + packet_disconnect("Protocol error waiting for compression response."); + } + /* 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_cstring(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), NULL); + + /* Send the packet, and wait for it to leave. */ + packet_send(); + packet_write_wait(); + + /* Read response from the server. */ + type = packet_read(); + if (type == SSH_SMSG_SUCCESS) { + interactive = 1; + have_tty = 1; + } else if (type == SSH_SMSG_FAILURE) + logit("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 *proto, *data; + /* Get reasonable local authentication information. */ + x11_get_proto(&proto, &data); + /* Request forwarding with authentication spoofing. */ + debug("Requesting X11 forwarding with authentication spoofing."); + x11_request_forwarding_with_spoofing(0, proto, data); + + /* Read response from the server. */ + type = packet_read(); + if (type == SSH_SMSG_SUCCESS) { + interactive = 1; + } else if (type == SSH_SMSG_FAILURE) { + logit("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); + + /* Request authentication agent forwarding if appropriate. */ + check_agent_present(); + + if (options.forward_agent) { + debug("Requesting authentication agent forwarding."); + auth_request_forwarding(); + + /* Read response from the server. */ + type = packet_read(); + packet_check_eom(); + if (type != SSH_SMSG_SUCCESS) + logit("Warning: Remote host denied authentication agent forwarding."); + } + + /* Initiate port forwardings. */ + ssh_init_forwarding(); + + /* If requested, let ssh continue in the background. */ + if (fork_after_authentication_flag) + if (daemon(1, 1) < 0) + fatal("daemon() failed: %.200s", strerror(errno)); + + /* + * 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, (u_char *)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. */ + return client_loop(have_tty, tty_flag ? + options.escape_char : SSH_ESCAPECHAR_NONE, 0); +} + +static void +ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt) +{ + int id, len; + + id = packet_get_int(); + len = buffer_len(&command); + if (len > 900) + len = 900; + packet_check_eom(); + if (type == SSH2_MSG_CHANNEL_FAILURE) + fatal("Request for subsystem '%.*s' failed on channel %d", + len, (u_char *)buffer_ptr(&command), id); +} + +void +client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) +{ + int i; + + i = client_global_request_id++; + if (i >= options.num_remote_forwards) + return; + debug("remote forward %s for: listen %d, connect %s:%d", + type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", + options.remote_forwards[i].port, + options.remote_forwards[i].host, + options.remote_forwards[i].host_port); + if (type == SSH2_MSG_REQUEST_FAILURE) + logit("Warning: remote port forwarding failed for listen port %d", + options.remote_forwards[i].port); +} + +static void +ssh_control_listener(void) +{ + struct sockaddr_un addr; + mode_t old_umask; + int addr_len; + + if (options.control_path == NULL || options.control_master <= 0) + return; + + memset(&addr, '\0', sizeof(addr)); + addr.sun_family = AF_UNIX; + addr_len = offsetof(struct sockaddr_un, sun_path) + + strlen(options.control_path) + 1; + + if (strlcpy(addr.sun_path, options.control_path, + sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) + fatal("ControlPath too long"); + + if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + fatal("%s socket(): %s\n", __func__, strerror(errno)); + + old_umask = umask(0177); + if (bind(control_fd, (struct sockaddr*)&addr, addr_len) == -1) { + control_fd = -1; + if (errno == EINVAL) + fatal("ControlSocket %s already exists", + options.control_path); + else + fatal("%s bind(): %s\n", __func__, strerror(errno)); + } + umask(old_umask); + + if (listen(control_fd, 64) == -1) + fatal("%s listen(): %s\n", __func__, strerror(errno)); + + set_nonblock(control_fd); +} + +/* request pty/x11/agent/tcpfwd/shell for channel */ +static void +ssh_session2_setup(int id, void *arg) +{ + extern char **environ; + + int interactive = tty_flag; + if (options.forward_x11 && getenv("DISPLAY") != NULL) { + char *proto, *data; + /* Get reasonable local authentication information. */ + x11_get_proto(&proto, &data); + /* Request forwarding with authentication spoofing. */ + debug("Requesting X11 forwarding with authentication spoofing."); + x11_request_forwarding_with_spoofing(id, proto, data); + interactive = 1; + /* XXX wait for reply */ + } + + check_agent_present(); + if (options.forward_agent) { + debug("Requesting authentication agent forwarding."); + channel_request_start(id, "auth-agent-req@openssh.com", 0); + packet_send(); + } + + client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"), + NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply); + + packet_set_interactive(interactive); +} + +/* open new channel for a session */ +static int +ssh_session2_open(void) +{ + Channel *c; + int window, packetmax, in, out, err; + + if (stdin_null_flag) { + in = open(_PATH_DEVNULL, O_RDONLY); + } else { + in = dup(STDIN_FILENO); + } + out = dup(STDOUT_FILENO); + err = dup(STDERR_FILENO); + + if (in < 0 || out < 0 || err < 0) + fatal("dup() in/out/err failed"); + + /* enable nonblocking unless tty */ + if (!isatty(in)) + set_nonblock(in); + if (!isatty(out)) + set_nonblock(out); + if (!isatty(err)) + set_nonblock(err); + + window = CHAN_SES_WINDOW_DEFAULT; + packetmax = CHAN_SES_PACKET_DEFAULT; + if (tty_flag) { + window >>= 1; + packetmax >>= 1; + } + c = channel_new( + "session", SSH_CHANNEL_OPENING, in, out, err, + window, packetmax, CHAN_EXTENDED_WRITE, + "client-session", /*nonblock*/0); + + debug3("ssh_session2_open: channel_new: %d", c->self); + + channel_send_open(c->self); + if (!no_shell_flag) + channel_register_confirm(c->self, ssh_session2_setup, NULL); + + return c->self; +} + +static int +ssh_session2(void) +{ + int id = -1; + + /* XXX should be pre-session */ + ssh_init_forwarding(); + ssh_control_listener(); + + if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) + id = ssh_session2_open(); + + /* If requested, let ssh continue in the background. */ + if (fork_after_authentication_flag) + if (daemon(1, 1) < 0) + fatal("daemon() failed: %.200s", strerror(errno)); + + return client_loop(tty_flag, tty_flag ? + options.escape_char : SSH_ESCAPECHAR_NONE, id); +} + +static void +load_public_identity_files(void) +{ + char *filename; + int i = 0; + Key *public; +#ifdef SMARTCARD + Key **keys; + + if (options.smartcard_device != NULL && + options.num_identity_files < SSH_MAX_IDENTITY_FILES && + (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL ) { + int count = 0; + for (i = 0; keys[i] != NULL; i++) { + count++; + memmove(&options.identity_files[1], &options.identity_files[0], + sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); + memmove(&options.identity_keys[1], &options.identity_keys[0], + sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); + options.num_identity_files++; + options.identity_keys[0] = keys[i]; + options.identity_files[0] = sc_get_key_label(keys[i]); + } + if (options.num_identity_files > SSH_MAX_IDENTITY_FILES) + options.num_identity_files = SSH_MAX_IDENTITY_FILES; + i = count; + xfree(keys); + } +#endif /* SMARTCARD */ + for (; i < options.num_identity_files; i++) { + filename = tilde_expand_filename(options.identity_files[i], + original_real_uid); + public = key_load_public(filename, NULL); + debug("identity file %s type %d", filename, + public ? public->type : -1); + xfree(options.identity_files[i]); + options.identity_files[i] = filename; + options.identity_keys[i] = public; + } +} + +static void +control_client_sighandler(int signo) +{ + control_client_terminate = signo; +} + +static void +control_client_sigrelay(int signo) +{ + if (control_server_pid > 1) + kill(control_server_pid, signo); +} + +static int +env_permitted(char *env) +{ + int i; + char name[1024], *cp; + + strlcpy(name, env, sizeof(name)); + if ((cp = strchr(name, '=')) == NULL) + return (0); + + *cp = '\0'; + + for (i = 0; i < options.num_send_env; i++) + if (match_pattern(name, options.send_env[i])) + return (1); + + return (0); +} + +static void +control_client(const char *path) +{ + struct sockaddr_un addr; + int i, r, sock, exitval, num_env, addr_len; + Buffer m; + char *cp; + extern char **environ; + + memset(&addr, '\0', sizeof(addr)); + addr.sun_family = AF_UNIX; + addr_len = offsetof(struct sockaddr_un, sun_path) + + strlen(path) + 1; + + if (strlcpy(addr.sun_path, path, + sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) + fatal("ControlPath too long"); + + if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + fatal("%s socket(): %s", __func__, strerror(errno)); + + if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) + fatal("Couldn't connect to %s: %s", path, strerror(errno)); + + if ((cp = getenv("TERM")) == NULL) + cp = ""; + + buffer_init(&m); + + /* Get PID of controlee */ + if (ssh_msg_recv(sock, &m) == -1) + fatal("%s: msg_recv", __func__); + if (buffer_get_char(&m) != 0) + fatal("%s: wrong version", __func__); + /* Connection allowed? */ + if (buffer_get_int(&m) != 1) + fatal("Connection to master denied"); + control_server_pid = buffer_get_int(&m); + + buffer_clear(&m); + buffer_put_int(&m, tty_flag); + buffer_put_int(&m, subsystem_flag); + buffer_put_cstring(&m, cp); + + buffer_append(&command, "\0", 1); + buffer_put_cstring(&m, buffer_ptr(&command)); + + if (options.num_send_env == 0 || environ == NULL) { + buffer_put_int(&m, 0); + } else { + /* Pass environment */ + num_env = 0; + for (i = 0; environ[i] != NULL; i++) + if (env_permitted(environ[i])) + num_env++; /* Count */ + + buffer_put_int(&m, num_env); + + for (i = 0; environ[i] != NULL && num_env >= 0; i++) + if (env_permitted(environ[i])) { + num_env--; + buffer_put_cstring(&m, environ[i]); + } + } + + if (ssh_msg_send(sock, /* version */0, &m) == -1) + fatal("%s: msg_send", __func__); + + mm_send_fd(sock, STDIN_FILENO); + mm_send_fd(sock, STDOUT_FILENO); + mm_send_fd(sock, STDERR_FILENO); + + /* Wait for reply, so master has a chance to gather ttymodes */ + buffer_clear(&m); + if (ssh_msg_recv(sock, &m) == -1) + fatal("%s: msg_recv", __func__); + if (buffer_get_char(&m) != 0) + fatal("%s: master returned error", __func__); + buffer_free(&m); + + signal(SIGINT, control_client_sighandler); + signal(SIGTERM, control_client_sighandler); + signal(SIGWINCH, control_client_sigrelay); + + if (tty_flag) + enter_raw_mode(); + + /* Stick around until the controlee closes the client_fd */ + exitval = 0; + for (;!control_client_terminate;) { + r = read(sock, &exitval, sizeof(exitval)); + if (r == 0) { + debug2("Received EOF from master"); + break; + } + if (r > 0) + debug2("Received exit status from master %d", exitval); + if (r == -1 && errno != EINTR) + fatal("%s: read %s", __func__, strerror(errno)); + } + + if (control_client_terminate) + debug2("Exiting on signal %d", control_client_terminate); + + close(sock); + + leave_raw_mode(); + + if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET) + fprintf(stderr, "Connection to master closed.\r\n"); + + exit(exitval); +} diff --git a/crypto/openssh-3.9p1/ssh.h b/crypto/openssh-3.9p1/ssh.h new file mode 100644 index 0000000000..a3b2ebbb56 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh.h @@ -0,0 +1,109 @@ +/* $OpenBSD: ssh.h,v 1.75 2003/12/02 17:01:15 markus Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#ifndef SSH_H +#define SSH_H + +#include /* For struct sockaddr_in */ +#include /* For struct pw */ +#include /* For va_list */ +#include /* For LOG_AUTH and friends */ +#include /* For struct sockaddr_storage */ +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +/* 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 incompatibility + * that prevents communication. + * + * Minor protocol version. Different version indicates minor incompatibility + * that does not prevent interoperation. + */ +#define PROTOCOL_MAJOR_1 1 +#define PROTOCOL_MINOR_1 5 + +/* We support both SSH1 and SSH2 */ +#define PROTOCOL_MAJOR_2 2 +#define PROTOCOL_MINOR_2 0 + +/* + * Name for the service. The port named by this service overrides the + * default port if present. + */ +#define SSH_SERVICE_NAME "ssh" + +/* + * Name of the environment variable containing the process ID of the + * authentication agent. + */ +#define SSH_AGENTPID_ENV_NAME "SSH_AGENT_PID" + +/* + * Name of the environment variable containing the pathname of the + * authentication socket. + */ +#define SSH_AUTHSOCKET_ENV_NAME "SSH_AUTH_SOCK" + +/* + * Environment variable for overwriting the default location of askpass + */ +#define SSH_ASKPASS_ENV "SSH_ASKPASS" + +/* + * 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 + +/* Used to identify ``EscapeChar none'' */ +#define SSH_ESCAPECHAR_NONE -2 + +/* + * unprivileged user when UsePrivilegeSeparation=yes; + * sshd will change its privileges to this user and its + * primary group. + */ +#ifndef SSH_PRIVSEP_USER +#define SSH_PRIVSEP_USER "sshd" +#endif + +/* Minimum modulus size (n) for RSA keys. */ +#define SSH_RSA_MINIMUM_MODULUS_SIZE 768 + +/* Listen backlog for sshd, ssh-agent and forwarding sockets */ +#define SSH_LISTEN_BACKLOG 128 + +#endif /* SSH_H */ diff --git a/crypto/openssh-3.9p1/ssh1.h b/crypto/openssh-3.9p1/ssh1.h new file mode 100644 index 0000000000..cc7fbc8b00 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh1.h @@ -0,0 +1,89 @@ +/* $OpenBSD: ssh1.h,v 1.4 2004/07/11 17:48:47 deraadt Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +/* + * 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 (BIGNUM) */ +#define SSH_CMSG_USER 4 /* user (string) */ +#define SSH_CMSG_AUTH_RHOSTS 5 /* user (string) */ +#define SSH_CMSG_AUTH_RSA 6 /* modulus (BIGNUM) */ +#define SSH_SMSG_AUTH_RSA_CHALLENGE 7 /* int (BIGNUM) */ +#define SSH_CMSG_AUTH_RSA_RESPONSE 8 /* int (BIGNUM) */ +#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_MAX_PACKET_SIZE 38 /* size 4k-1024k (int) */ +#define SSH_CMSG_AUTH_TIS 39 /* we use this for s/key */ +#define SSH_SMSG_AUTH_TIS_CHALLENGE 40 /* challenge (string) */ +#define SSH_CMSG_AUTH_TIS_RESPONSE 41 /* response (string) */ +#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) */ + +/* protocol version 1.5 overloads some version 1.3 message types */ +#define SSH_MSG_CHANNEL_INPUT_EOF SSH_MSG_CHANNEL_CLOSE +#define SSH_MSG_CHANNEL_OUTPUT_CLOSE SSH_MSG_CHANNEL_CLOSE_CONFIRMATION + +/* + * 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 +#define SSH_AUTH_TIS 5 +#define SSH_AUTH_KERBEROS 6 +#define SSH_PASS_KERBEROS_TGT 7 + /* 8 to 15 are reserved */ +#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 */ diff --git a/crypto/openssh-3.9p1/ssh2.h b/crypto/openssh-3.9p1/ssh2.h new file mode 100644 index 0000000000..fb491c9185 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh2.h @@ -0,0 +1,161 @@ +/* $OpenBSD: ssh2.h,v 1.9 2003/05/14 00:52:59 markus Exp $ */ + +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * draft-ietf-secsh-architecture-05.txt + * + * Transport layer protocol: + * + * 1-19 Transport layer generic (e.g. disconnect, ignore, debug, + * etc) + * 20-29 Algorithm negotiation + * 30-49 Key exchange method specific (numbers can be reused for + * different authentication methods) + * + * User authentication protocol: + * + * 50-59 User authentication generic + * 60-79 User authentication method specific (numbers can be reused + * for different authentication methods) + * + * Connection protocol: + * + * 80-89 Connection protocol generic + * 90-127 Channel related messages + * + * Reserved for client protocols: + * + * 128-191 Reserved + * + * Local extensions: + * + * 192-255 Local extensions + */ + +/* ranges */ + +#define SSH2_MSG_TRANSPORT_MIN 1 +#define SSH2_MSG_TRANSPORT_MAX 49 +#define SSH2_MSG_USERAUTH_MIN 50 +#define SSH2_MSG_USERAUTH_MAX 79 +#define SSH2_MSG_USERAUTH_PER_METHOD_MIN 60 +#define SSH2_MSG_USERAUTH_PER_METHOD_MAX SSH2_MSG_USERAUTH_MAX +#define SSH2_MSG_CONNECTION_MIN 80 +#define SSH2_MSG_CONNECTION_MAX 127 +#define SSH2_MSG_RESERVED_MIN 128 +#define SSH2_MSG_RESERVED_MAX 191 +#define SSH2_MSG_LOCAL_MIN 192 +#define SSH2_MSG_LOCAL_MAX 255 +#define SSH2_MSG_MIN 1 +#define SSH2_MSG_MAX 255 + +/* transport layer: generic */ + +#define SSH2_MSG_DISCONNECT 1 +#define SSH2_MSG_IGNORE 2 +#define SSH2_MSG_UNIMPLEMENTED 3 +#define SSH2_MSG_DEBUG 4 +#define SSH2_MSG_SERVICE_REQUEST 5 +#define SSH2_MSG_SERVICE_ACCEPT 6 + +/* transport layer: alg negotiation */ + +#define SSH2_MSG_KEXINIT 20 +#define SSH2_MSG_NEWKEYS 21 + +/* transport layer: kex specific messages, can be reused */ + +#define SSH2_MSG_KEXDH_INIT 30 +#define SSH2_MSG_KEXDH_REPLY 31 + +/* dh-group-exchange */ +#define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30 +#define SSH2_MSG_KEX_DH_GEX_GROUP 31 +#define SSH2_MSG_KEX_DH_GEX_INIT 32 +#define SSH2_MSG_KEX_DH_GEX_REPLY 33 +#define SSH2_MSG_KEX_DH_GEX_REQUEST 34 + +/* user authentication: generic */ + +#define SSH2_MSG_USERAUTH_REQUEST 50 +#define SSH2_MSG_USERAUTH_FAILURE 51 +#define SSH2_MSG_USERAUTH_SUCCESS 52 +#define SSH2_MSG_USERAUTH_BANNER 53 + +/* user authentication: method specific, can be reused */ + +#define SSH2_MSG_USERAUTH_PK_OK 60 +#define SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60 +#define SSH2_MSG_USERAUTH_INFO_REQUEST 60 +#define SSH2_MSG_USERAUTH_INFO_RESPONSE 61 + +/* connection protocol: generic */ + +#define SSH2_MSG_GLOBAL_REQUEST 80 +#define SSH2_MSG_REQUEST_SUCCESS 81 +#define SSH2_MSG_REQUEST_FAILURE 82 + +/* channel related messages */ + +#define SSH2_MSG_CHANNEL_OPEN 90 +#define SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91 +#define SSH2_MSG_CHANNEL_OPEN_FAILURE 92 +#define SSH2_MSG_CHANNEL_WINDOW_ADJUST 93 +#define SSH2_MSG_CHANNEL_DATA 94 +#define SSH2_MSG_CHANNEL_EXTENDED_DATA 95 +#define SSH2_MSG_CHANNEL_EOF 96 +#define SSH2_MSG_CHANNEL_CLOSE 97 +#define SSH2_MSG_CHANNEL_REQUEST 98 +#define SSH2_MSG_CHANNEL_SUCCESS 99 +#define SSH2_MSG_CHANNEL_FAILURE 100 + +/* disconnect reason code */ + +#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 +#define SSH2_DISCONNECT_PROTOCOL_ERROR 2 +#define SSH2_DISCONNECT_KEY_EXCHANGE_FAILED 3 +#define SSH2_DISCONNECT_HOST_AUTHENTICATION_FAILED 4 +#define SSH2_DISCONNECT_RESERVED 4 +#define SSH2_DISCONNECT_MAC_ERROR 5 +#define SSH2_DISCONNECT_COMPRESSION_ERROR 6 +#define SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE 7 +#define SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 +#define SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 +#define SSH2_DISCONNECT_CONNECTION_LOST 10 +#define SSH2_DISCONNECT_BY_APPLICATION 11 +#define SSH2_DISCONNECT_TOO_MANY_CONNECTIONS 12 +#define SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER 13 +#define SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 +#define SSH2_DISCONNECT_ILLEGAL_USER_NAME 15 + +/* misc */ + +#define SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED 1 +#define SSH2_OPEN_CONNECT_FAILED 2 +#define SSH2_OPEN_UNKNOWN_CHANNEL_TYPE 3 +#define SSH2_OPEN_RESOURCE_SHORTAGE 4 + +#define SSH2_EXTENDED_DATA_STDERR 1 diff --git a/crypto/openssh-3.9p1/ssh_config b/crypto/openssh-3.9p1/ssh_config new file mode 100644 index 0000000000..2692e89137 --- /dev/null +++ b/crypto/openssh-3.9p1/ssh_config @@ -0,0 +1,37 @@ +# $OpenBSD: ssh_config,v 1.19 2003/08/13 08:46:31 markus Exp $ + +# This is the ssh client system-wide configuration file. See +# ssh_config(5) for more information. 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 no +# ForwardX11 no +# RhostsRSAAuthentication no +# RSAAuthentication yes +# PasswordAuthentication yes +# HostbasedAuthentication no +# BatchMode no +# CheckHostIP yes +# AddressFamily any +# ConnectTimeout 0 +# StrictHostKeyChecking ask +# IdentityFile ~/.ssh/identity +# IdentityFile ~/.ssh/id_rsa +# IdentityFile ~/.ssh/id_dsa +# Port 22 +# Protocol 2,1 +# Cipher 3des +# Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc +# EscapeChar ~ diff --git a/crypto/openssh-3.9p1/ssh_config.5 b/crypto/openssh-3.9p1/ssh_config.5 new file mode 100644 index 0000000000..0e1a031e5d --- /dev/null +++ b/crypto/openssh-3.9p1/ssh_config.5 @@ -0,0 +1,815 @@ +.\" -*- nroff -*- +.\" +.\" Author: Tatu Ylonen +.\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +.\" All rights reserved +.\" +.\" 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". +.\" +.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. +.\" Copyright (c) 1999 Aaron Campbell. All rights reserved. +.\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $OpenBSD: ssh_config.5,v 1.38 2004/06/26 09:11:14 jmc Exp $ +.Dd September 25, 1999 +.Dt SSH_CONFIG 5 +.Os +.Sh NAME +.Nm ssh_config +.Nd OpenSSH SSH client configuration files +.Sh SYNOPSIS +.Bl -tag -width Ds -compact +.It Pa $HOME/.ssh/config +.It Pa /etc/ssh/ssh_config +.El +.Sh DESCRIPTION +.Nm ssh +obtains configuration data from the following sources in +the following order: +.Bl -enum -offset indent -compact +.It +command-line options +.It +user's configuration file +.Pq Pa $HOME/.ssh/config +.It +system-wide configuration file +.Pq Pa /etc/ssh/ssh_config +.El +.Pp +For each parameter, the first obtained value +will be used. +The configuration files contain sections bracketed by +.Dq 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. +.Pp +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. +.Pp +The configuration file has the following format: +.Pp +Empty lines and lines starting with +.Ql # +are comments. +.Pp +Otherwise a line is of the format +.Dq keyword arguments . +Configuration options may be separated by whitespace or +optional whitespace and exactly one +.Ql = ; +the latter format is useful to avoid the need to quote whitespace +when specifying configuration options using the +.Nm ssh , +.Nm scp +and +.Nm sftp +.Fl o +option. +.Pp +The possible +keywords and their meanings are as follows (note that +keywords are case-insensitive and arguments are case-sensitive): +.Bl -tag -width Ds +.It Cm Host +Restricts the following declarations (up to the next +.Cm Host +keyword) to be only for those hosts that match one of the patterns +given after the keyword. +.Ql \&* +and +.Ql \&? +can be used as wildcards in the +patterns. +A single +.Ql \&* +as a pattern can be used to provide global +defaults for all hosts. +The host is the +.Ar hostname +argument given on the command line (i.e., the name is not converted to +a canonicalized host name before matching). +.It Cm AddressFamily +Specifies which address family to use when connecting. +Valid arguments are +.Dq any , +.Dq inet +(Use IPv4 only) or +.Dq inet6 +(Use IPv6 only.) +.It Cm BatchMode +If set to +.Dq yes , +passphrase/password querying will be disabled. +This option is useful in scripts and other batch jobs where no user +is present to supply the password. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +.It Cm BindAddress +Specify the interface to transmit from on machines with multiple +interfaces or aliased addresses. +Note that this option does not work if +.Cm UsePrivilegedPort +is set to +.Dq yes . +.It Cm ChallengeResponseAuthentication +Specifies whether to use challenge response authentication. +The argument to this keyword must be +.Dq yes +or +.Dq no . +The default is +.Dq yes . +.It Cm CheckHostIP +If this flag is set to +.Dq yes , +ssh will additionally check the host IP address in the +.Pa known_hosts +file. +This allows ssh to detect if a host key changed due to DNS spoofing. +If the option is set to +.Dq no , +the check will not be executed. +The default is +.Dq yes . +.It Cm Cipher +Specifies the cipher to use for encrypting the session +in protocol version 1. +Currently, +.Dq blowfish , +.Dq 3des , +and +.Dq des +are supported. +.Ar des +is only supported in the +.Nm ssh +client for interoperability with legacy protocol 1 implementations +that do not support the +.Ar 3des +cipher. +Its use is strongly discouraged due to cryptographic weaknesses. +The default is +.Dq 3des . +.It Cm Ciphers +Specifies the ciphers allowed for protocol version 2 +in order of preference. +Multiple ciphers must be comma-separated. +The supported ciphers are +.Dq 3des-cbc , +.Dq aes128-cbc , +.Dq aes192-cbc , +.Dq aes256-cbc , +.Dq aes128-ctr , +.Dq aes192-ctr , +.Dq aes256-ctr , +.Dq arcfour , +.Dq blowfish-cbc , +and +.Dq cast128-cbc . +The default is +.Bd -literal + ``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour, + aes192-cbc,aes256-cbc'' +.Ed +.It Cm ClearAllForwardings +Specifies that all local, remote and dynamic port forwardings +specified in the configuration files or on the command line be +cleared. +This option is primarily useful when used from the +.Nm ssh +command line to clear port forwardings set in +configuration files, and is automatically set by +.Xr scp 1 +and +.Xr sftp 1 . +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +.It Cm Compression +Specifies whether to use compression. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +.It Cm CompressionLevel +Specifies the compression level to use if compression is enabled. +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 +.Xr gzip 1 . +Note that this option applies to protocol version 1 only. +.It Cm ConnectionAttempts +Specifies the number of tries (one per second) to make before exiting. +The argument must be an integer. +This may be useful in scripts if the connection sometimes fails. +The default is 1. +.It Cm ConnectTimeout +Specifies the timeout (in seconds) used when connecting to the ssh +server, instead of using the default system TCP timeout. +This value is used only when the target is down or really unreachable, +not when it refuses the connection. +.It Cm ControlMaster +Enables the sharing of multiple sessions over a single network connection. +When set to +.Dq yes +.Nm ssh +will listen for connections on a control socket specified using the +.Cm ControlPath +argument. +Additional sessions can connect to this socket using the same +.Cm ControlPath +with +.Cm ControlMaster +set to +.Dq no +(the default). +These sessions will reuse the master instance's network connection rather +than initiating new ones. +Setting this to +.Dq ask +will cause +.Nm ssh +to listen for control connections, but require confirmation using the +.Ev SSH_ASKPASS +program before they are accepted (see +.Xr ssh-add 1 +for details). +.It Cm ControlPath +Specify the path to the control socket used for connection sharing. +See +.Cm ControlMaster +above. +.It Cm DynamicForward +Specifies that a TCP/IP port on the local machine be forwarded +over the secure channel, and the application +protocol is then used to determine where to connect to from the +remote machine. +The argument must be a port number. +Currently the SOCKS4 and SOCKS5 protocols are supported, and +.Nm ssh +will act as a SOCKS server. +Multiple forwardings may be specified, and +additional forwardings can be given on the command line. +Only the superuser can forward privileged ports. +.It Cm EnableSSHKeysign +Setting this option to +.Dq yes +in the global client configuration file +.Pa /etc/ssh/ssh_config +enables the use of the helper program +.Xr ssh-keysign 8 +during +.Cm HostbasedAuthentication . +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +This option should be placed in the non-hostspecific section. +See +.Xr ssh-keysign 8 +for more information. +.It Cm EscapeChar +Sets the escape character (default: +.Ql ~ ) . +The escape character can also +be set on the command line. +The argument should be a single character, +.Ql ^ +followed by a letter, or +.Dq none +to disable the escape +character entirely (making the connection transparent for binary +data). +.It Cm ForwardAgent +Specifies whether the connection to the authentication agent (if any) +will be forwarded to the remote machine. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +.Pp +Agent forwarding should be enabled with caution. +Users with the ability to bypass file permissions on the remote host +(for the agent's Unix-domain socket) +can access the local agent through the forwarded connection. +An attacker cannot obtain key material from the agent, +however they can perform operations on the keys that enable them to +authenticate using the identities loaded into the agent. +.It Cm ForwardX11 +Specifies whether X11 connections will be automatically redirected +over the secure channel and +.Ev DISPLAY +set. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +.Pp +X11 forwarding should be enabled with caution. +Users with the ability to bypass file permissions on the remote host +(for the user's X11 authorization database) +can access the local X11 display through the forwarded connection. +An attacker may then be able to perform activities such as keystroke monitoring +if the +.Cm ForwardX11Trusted +option is also enabled. +.It Cm ForwardX11Trusted +If this option is set to +.Dq yes +then remote X11 clients will have full access to the original X11 display. +If this option is set to +.Dq no +then remote X11 clients will be considered untrusted and prevented +from stealing or tampering with data belonging to trusted X11 +clients. +.Pp +The default is +.Dq no . +.Pp +See the X11 SECURITY extension specification for full details on +the restrictions imposed on untrusted clients. +.It Cm GatewayPorts +Specifies whether remote hosts are allowed to connect to local +forwarded ports. +By default, +.Nm ssh +binds local port forwardings to the loopback address. +This prevents other remote hosts from connecting to forwarded ports. +.Cm GatewayPorts +can be used to specify that +.Nm ssh +should bind local port forwardings to the wildcard address, +thus allowing remote hosts to connect to forwarded ports. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +.It Cm GlobalKnownHostsFile +Specifies a file to use for the global +host key database instead of +.Pa /etc/ssh/ssh_known_hosts . +.It Cm GSSAPIAuthentication +Specifies whether user authentication based on GSSAPI is allowed. +The default is +.Dq no . +Note that this option applies to protocol version 2 only. +.It Cm GSSAPIDelegateCredentials +Forward (delegate) credentials to the server. +The default is +.Dq no . +Note that this option applies to protocol version 2 only. +.It Cm HostbasedAuthentication +Specifies whether to try rhosts based authentication with public key +authentication. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +This option applies to protocol version 2 only and +is similar to +.Cm RhostsRSAAuthentication . +.It Cm HostKeyAlgorithms +Specifies the protocol version 2 host key algorithms +that the client wants to use in order of preference. +The default for this option is: +.Dq ssh-rsa,ssh-dss . +.It Cm HostKeyAlias +Specifies an alias that should be used instead of the +real host name when looking up or saving the host key +in the host key database files. +This option is useful for tunneling ssh connections +or for multiple servers running on a single host. +.It Cm HostName +Specifies the real host name to log into. +This can be used to specify nicknames 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 +.Cm HostName +specifications). +.It Cm IdentityFile +Specifies a file from which the user's RSA or DSA authentication identity +is read. +The default is +.Pa $HOME/.ssh/identity +for protocol version 1, and +.Pa $HOME/.ssh/id_rsa +and +.Pa $HOME/.ssh/id_dsa +for protocol version 2. +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. +.It Cm IdentitiesOnly +Specifies that +.Nm ssh +should only use the authentication identity files configured in the +.Nm +files, +even if the +.Nm ssh-agent +offers more identities. +The argument to this keyword must be +.Dq yes +or +.Dq no . +This option is intented for situations where +.Nm ssh-agent +offers many different identities. +The default is +.Dq no . +.It Cm LocalForward +Specifies that a TCP/IP port on the local machine be forwarded over +the secure channel to the specified host and port from the remote machine. +The first argument must be a port number, and the second must be +.Ar host:port . +IPv6 addresses can be specified with an alternative syntax: +.Ar host/port . +Multiple forwardings may be specified, and additional +forwardings can be given on the command line. +Only the superuser can forward privileged ports. +.It Cm LogLevel +Gives the verbosity level that is used when logging messages from +.Nm ssh . +The possible values are: +QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2 and DEBUG3. +The default is INFO. +DEBUG and DEBUG1 are equivalent. +DEBUG2 and DEBUG3 each specify higher levels of verbose output. +.It Cm MACs +Specifies the MAC (message authentication code) algorithms +in order of preference. +The MAC algorithm is used in protocol version 2 +for data integrity protection. +Multiple algorithms must be comma-separated. +The default is +.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 . +.It Cm NoHostAuthenticationForLocalhost +This option can be used if the home directory is shared across machines. +In this case localhost will refer to a different machine on each of +the machines and the user will get many warnings about changed host keys. +However, this option disables host authentication for localhost. +The argument to this keyword must be +.Dq yes +or +.Dq no . +The default is to check the host key for localhost. +.It Cm NumberOfPasswordPrompts +Specifies the number of password prompts before giving up. +The argument to this keyword must be an integer. +Default is 3. +.It Cm PasswordAuthentication +Specifies whether to use password authentication. +The argument to this keyword must be +.Dq yes +or +.Dq no . +The default is +.Dq yes . +.It Cm Port +Specifies the port number to connect on the remote host. +Default is 22. +.It Cm PreferredAuthentications +Specifies the order in which the client should try protocol 2 +authentication methods. +This allows a client to prefer one method (e.g. +.Cm keyboard-interactive ) +over another method (e.g. +.Cm password ) +The default for this option is: +.Dq hostbased,publickey,keyboard-interactive,password . +.It Cm Protocol +Specifies the protocol versions +.Nm ssh +should support in order of preference. +The possible values are +.Dq 1 +and +.Dq 2 . +Multiple versions must be comma-separated. +The default is +.Dq 2,1 . +This means that +.Nm ssh +tries version 2 and falls back to version 1 +if version 2 is not available. +.It Cm 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 +.Pa /bin/sh . +In the command string, +.Ql %h +will be substituted by the host name to +connect and +.Ql %p +by the port. +The command can be basically anything, +and should read from its standard input and write to its standard output. +It should eventually connect an +.Xr sshd 8 +server running on some machine, or execute +.Ic 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). +Setting the command to +.Dq none +disables this option entirely. +Note that +.Cm CheckHostIP +is not available for connects with a proxy command. +.Pp +.It Cm PubkeyAuthentication +Specifies whether to try public key authentication. +The argument to this keyword must be +.Dq yes +or +.Dq no . +The default is +.Dq yes . +This option applies to protocol version 2 only. +.It Cm RemoteForward +Specifies that a TCP/IP port on the remote machine be forwarded over +the secure channel to the specified host and port from the local machine. +The first argument must be a port number, and the second must be +.Ar host:port . +IPv6 addresses can be specified with an alternative syntax: +.Ar host/port . +Multiple forwardings may be specified, and additional +forwardings can be given on the command line. +Only the superuser can forward privileged ports. +.It Cm RhostsRSAAuthentication +Specifies whether to try rhosts based authentication with RSA host +authentication. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +This option applies to protocol version 1 only and requires +.Nm ssh +to be setuid root. +.It Cm RSAAuthentication +Specifies whether to try RSA authentication. +The argument to this keyword must be +.Dq yes +or +.Dq no . +RSA authentication will only be +attempted if the identity file exists, or an authentication agent is +running. +The default is +.Dq yes . +Note that this option applies to protocol version 1 only. +.It Cm SendEnv +Specifies what variables from the local +.Xr environ 7 +should be sent to the server. +Note that environment passing is only supported for protocol 2, the +server must also support it, and the server must be configured to +accept these environment variables. +Refer to +.Cm AcceptEnv +in +.Xr sshd_config 5 +for how to configure the server. +Variables are specified by name, which may contain the wildcard characters +.Ql \&* +and +.Ql \&? . +Multiple environment variables may be separated by whitespace or spread +across multiple +.Cm SendEnv +directives. +The default is not to send any environment variables. +.It Cm ServerAliveInterval +Sets a timeout interval in seconds after which if no data has been received +from the server, +.Nm ssh +will send a message through the encrypted +channel to request a response from the server. +The default +is 0, indicating that these messages will not be sent to the server. +This option applies to protocol version 2 only. +.It Cm ServerAliveCountMax +Sets the number of server alive messages (see above) which may be +sent without +.Nm ssh +receiving any messages back from the server. +If this threshold is reached while server alive messages are being sent, +.Nm ssh +will disconnect from the server, terminating the session. +It is important to note that the use of server alive messages is very +different from +.Cm TCPKeepAlive +(below). +The server alive messages are sent through the encrypted channel +and therefore will not be spoofable. +The TCP keepalive option enabled by +.Cm TCPKeepAlive +is spoofable. +The server alive mechanism is valuable when the client or +server depend on knowing when a connection has become inactive. +.Pp +The default value is 3. +If, for example, +.Cm ServerAliveInterval +(above) is set to 15, and +.Cm ServerAliveCountMax +is left at the default, if the server becomes unresponsive ssh +will disconnect after approximately 45 seconds. +.It Cm SmartcardDevice +Specifies which smartcard device to use. +The argument to this keyword is the device +.Nm ssh +should use to communicate with a smartcard used for storing the user's +private RSA key. +By default, no device is specified and smartcard support is not activated. +.It Cm StrictHostKeyChecking +If this flag is set to +.Dq yes , +.Nm ssh +will never automatically add host keys to the +.Pa $HOME/.ssh/known_hosts +file, and refuses to connect to hosts whose host key has changed. +This provides maximum protection against trojan horse attacks, +however, can be annoying when the +.Pa /etc/ssh/ssh_known_hosts +file is poorly maintained, or connections to new hosts are +frequently made. +This option forces the user to manually +add all new hosts. +If this flag is set to +.Dq no , +.Nm ssh +will automatically add new host keys to the +user known hosts files. +If this flag is set to +.Dq ask , +new host keys +will be added to the user known host files only after the user +has confirmed that is what they really want to do, and +.Nm ssh +will refuse to connect to hosts whose host key has changed. +The host keys of +known hosts will be verified automatically in all cases. +The argument must be +.Dq yes , +.Dq no +or +.Dq ask . +The default is +.Dq ask . +.It Cm TCPKeepAlive +Specifies whether the system should send TCP 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. +.Pp +The default is +.Dq yes +(to send TCP keepalive messages), 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. +.Pp +To disable TCP keepalive messages, the value should be set to +.Dq no . +.It Cm UsePrivilegedPort +Specifies whether to use a privileged port for outgoing connections. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +If set to +.Dq yes +.Nm ssh +must be setuid root. +Note that this option must be set to +.Dq yes +for +.Cm RhostsRSAAuthentication +with older servers. +.It Cm User +Specifies the user to log in as. +This can be useful when a different user name is used on different machines. +This saves the trouble of +having to remember to give the user name on the command line. +.It Cm UserKnownHostsFile +Specifies a file to use for the user +host key database instead of +.Pa $HOME/.ssh/known_hosts . +.It Cm VerifyHostKeyDNS +Specifies whether to verify the remote key using DNS and SSHFP resource +records. +If this option is set to +.Dq yes , +the client will implicitly trust keys that match a secure fingerprint +from DNS. +Insecure fingerprints will be handled as if this option was set to +.Dq ask . +If this option is set to +.Dq ask , +information on fingerprint match will be displayed, but the user will still +need to confirm new host keys according to the +.Cm StrictHostKeyChecking +option. +The argument must be +.Dq yes , +.Dq no +or +.Dq ask . +The default is +.Dq no . +Note that this option applies to protocol version 2 only. +.It Cm XAuthLocation +Specifies the full pathname of the +.Xr xauth 1 +program. +The default is +.Pa /usr/X11R6/bin/xauth . +.El +.Sh FILES +.Bl -tag -width Ds +.It Pa $HOME/.ssh/config +This is the per-user configuration file. +The format of this file is described above. +This file is used by the +.Nm ssh +client. +Because of the potential for abuse, this file must have strict permissions: +read/write for the user, and not accessible by others. +.It Pa /etc/ssh/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. +.El +.Sh SEE ALSO +.Xr ssh 1 +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. diff --git a/crypto/openssh-3.9p1/sshconnect.c b/crypto/openssh-3.9p1/sshconnect.c new file mode 100644 index 0000000000..11008e544f --- /dev/null +++ b/crypto/openssh-3.9p1/sshconnect.c @@ -0,0 +1,1061 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Code to connect to a remote host, and to perform the client side of the + * login (authentication) dialog. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: sshconnect.c,v 1.158 2004/06/21 17:36:31 avsm Exp $"); + +#include + +#include "ssh.h" +#include "xmalloc.h" +#include "rsa.h" +#include "buffer.h" +#include "packet.h" +#include "uidswap.h" +#include "compat.h" +#include "key.h" +#include "sshconnect.h" +#include "hostfile.h" +#include "log.h" +#include "readconf.h" +#include "atomicio.h" +#include "misc.h" + +#include "dns.h" + +char *client_version_string = NULL; +char *server_version_string = NULL; + +int matching_host_key_dns = 0; + +/* import */ +extern Options options; +extern char *__progname; +extern uid_t original_real_uid; +extern uid_t original_effective_uid; +extern pid_t proxy_command_pid; + +#ifndef INET6_ADDRSTRLEN /* for non IPv6 machines */ +#define INET6_ADDRSTRLEN 46 +#endif + +static int show_other_keys(const char *, Key *); +static void warn_changed_key(Key *); + +/* + * Connect to the given ssh server using a proxy command. + */ +static int +ssh_proxy_connect(const char *host, u_short port, const char *proxy_command) +{ + Buffer command; + const char *cp; + char *command_string; + int pin[2], pout[2]; + pid_t pid; + char strport[NI_MAXSERV]; + + /* Convert the port number into a string. */ + snprintf(strport, sizeof strport, "%hu", port); + + /* + * Build the final command string in the buffer by making the + * appropriate substitutions to the given proxy command. + * + * Use "exec" to avoid "sh -c" processes on some platforms + * (e.g. Solaris) + */ + buffer_init(&command); + buffer_append(&command, "exec ", 5); + + 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, strport, strlen(strport)); + 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. */ + seteuid(original_real_uid); + setuid(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"); + /* Cannot be 1 because pin allocated two descriptors. */ + close(pout[1]); + + /* Stderr is left as it is so that error messages get + printed on the user's terminal. */ + argv[0] = _PATH_BSHELL; + argv[1] = "-c"; + argv[2] = command_string; + argv[3] = NULL; + + /* Execute the proxy command. Note that we gave up any + extra privileges above. */ + execv(argv[0], argv); + perror(argv[0]); + exit(1); + } + /* Parent. */ + if (pid < 0) + fatal("fork failed: %.100s", strerror(errno)); + else + proxy_command_pid = pid; /* save pid to clean up later */ + + /* 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]); + + /* Indicate OK return */ + return 0; +} + +/* + * Creates a (possibly privileged) socket for use as the ssh connection. + */ +static int +ssh_create_socket(int privileged, struct addrinfo *ai) +{ + int sock, gaierr; + struct addrinfo hints, *res; + + /* + * If we are running as root and want to connect to a privileged + * port, bind our own socket to a privileged port. + */ + if (privileged) { + int p = IPPORT_RESERVED - 1; + PRIV_START; + sock = rresvport_af(&p, ai->ai_family); + PRIV_END; + if (sock < 0) + error("rresvport: af=%d %.100s", ai->ai_family, + strerror(errno)); + else + debug("Allocated local port %d.", p); + return sock; + } + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) + error("socket: %.100s", strerror(errno)); + + /* Bind the socket to an alternative local IP address */ + if (options.bind_address == NULL) + return sock; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ai->ai_family; + hints.ai_socktype = ai->ai_socktype; + hints.ai_protocol = ai->ai_protocol; + hints.ai_flags = AI_PASSIVE; + gaierr = getaddrinfo(options.bind_address, "0", &hints, &res); + if (gaierr) { + error("getaddrinfo: %s: %s", options.bind_address, + gai_strerror(gaierr)); + close(sock); + return -1; + } + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { + error("bind: %s: %s", options.bind_address, strerror(errno)); + close(sock); + freeaddrinfo(res); + return -1; + } + freeaddrinfo(res); + return sock; +} + +static int +timeout_connect(int sockfd, const struct sockaddr *serv_addr, + socklen_t addrlen, int timeout) +{ + fd_set *fdset; + struct timeval tv; + socklen_t optlen; + int fdsetsz, optval, rc, result = -1; + + if (timeout <= 0) + return (connect(sockfd, serv_addr, addrlen)); + + set_nonblock(sockfd); + rc = connect(sockfd, serv_addr, addrlen); + if (rc == 0) { + unset_nonblock(sockfd); + return (0); + } + if (errno != EINPROGRESS) + return (-1); + + fdsetsz = howmany(sockfd + 1, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)xmalloc(fdsetsz); + + memset(fdset, 0, fdsetsz); + FD_SET(sockfd, fdset); + tv.tv_sec = timeout; + tv.tv_usec = 0; + + for(;;) { + rc = select(sockfd + 1, NULL, fdset, NULL, &tv); + if (rc != -1 || errno != EINTR) + break; + } + + switch(rc) { + case 0: + /* Timed out */ + errno = ETIMEDOUT; + break; + case -1: + /* Select error */ + debug("select: %s", strerror(errno)); + break; + case 1: + /* Completed or failed */ + optval = 0; + optlen = sizeof(optval); + if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, + &optlen) == -1) { + debug("getsockopt: %s", strerror(errno)); + break; + } + if (optval != 0) { + errno = optval; + break; + } + result = 0; + unset_nonblock(sockfd); + break; + default: + /* Should not occur */ + fatal("Bogus return (%d) from select()", rc); + } + + xfree(fdset); + return (result); +} + +/* + * Opens a TCP/IP connection to the remote server on the given host. + * The address of the remote host will be returned in hostaddr. + * If port is 0, the default port will be used. If needpriv is true, + * a privileged port will be allocated to make the connection. + * This requires super-user privileges if needpriv is true. + * 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. + * Return values: + * 0 for OK + * ECONNREFUSED if we got a "Connection Refused" by the peer on any address + * ECONNABORTED if we failed without a "Connection refused" + * Suitable error messages for the connection failure will already have been + * printed. + */ +int +ssh_connect(const char *host, struct sockaddr_storage * hostaddr, + u_short port, int family, int connection_attempts, + int needpriv, const char *proxy_command) +{ + int gaierr; + int on = 1; + int sock = -1, attempt; + char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + struct addrinfo hints, *ai, *aitop; + struct servent *sp; + /* + * Did we get only other errors than "Connection refused" (which + * should block fallback to rsh and similar), or did we get at least + * one "Connection refused"? + */ + int full_failure = 1; + + debug2("ssh_connect: needpriv %d", needpriv); + + /* 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, proxy_command); + + /* No proxy command. */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + snprintf(strport, sizeof strport, "%u", port); + if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) + fatal("%s: %.100s: %s", __progname, host, + gai_strerror(gaierr)); + + /* + * 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; ;) { + if (attempt > 0) + debug("Trying again..."); + + /* Loop through addresses for this host, and try each one in + sequence until the connection succeeds. */ + for (ai = aitop; ai; ai = ai->ai_next) { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + continue; + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, + ntop, sizeof(ntop), strport, sizeof(strport), + NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + error("ssh_connect: getnameinfo failed"); + continue; + } + debug("Connecting to %.200s [%.100s] port %s.", + host, ntop, strport); + + /* Create a socket for connecting. */ + sock = ssh_create_socket(needpriv, ai); + if (sock < 0) + /* Any error is already output */ + continue; + + if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, + options.connection_timeout) >= 0) { + /* Successful connection. */ + memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); + break; + } else { + if (errno == ECONNREFUSED) + full_failure = 0; + debug("connect to address %s port %s: %s", + ntop, strport, strerror(errno)); + /* + * Close the failed socket; there appear to + * be some problems when reusing a socket for + * which connect() has already returned an + * error. + */ + close(sock); + } + } + if (ai) + break; /* Successful connection. */ + + attempt++; + if (attempt >= connection_attempts) + break; + /* Sleep a moment before retrying. */ + sleep(1); + } + + freeaddrinfo(aitop); + + /* Return failure if we didn't get a successful connection. */ + if (attempt >= connection_attempts) { + logit("ssh: connect to host %s port %s: %s", + host, strport, strerror(errno)); + return full_failure ? ECONNABORTED : ECONNREFUSED; + } + + debug("Connection established."); + + /* Set SO_KEEPALIVE if requested. */ + if (options.tcp_keep_alive && + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, + sizeof(on)) < 0) + error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); + + /* Set the connection. */ + packet_set_connection(sock, sock); + + return 0; +} + +/* + * Waits for the server identification string, and sends our own + * identification string. + */ +static void +ssh_exchange_identification(void) +{ + char buf[256], remote_version[256]; /* must be same size! */ + int remote_major, remote_minor, i, mismatch; + int connection_in = packet_get_connection_in(); + int connection_out = packet_get_connection_out(); + int minor1 = PROTOCOL_MINOR_1; + + /* Read other side\'s version identification. */ + for (;;) { + for (i = 0; i < sizeof(buf) - 1; i++) { + int len = atomicio(read, connection_in, &buf[i], 1); + if (len < 0) + fatal("ssh_exchange_identification: read: %.100s", strerror(errno)); + if (len != 1) + fatal("ssh_exchange_identification: Connection closed by remote host"); + if (buf[i] == '\r') { + buf[i] = '\n'; + buf[i + 1] = 0; + continue; /**XXX wait for \n */ + } + if (buf[i] == '\n') { + buf[i + 1] = 0; + break; + } + } + buf[sizeof(buf) - 1] = 0; + if (strncmp(buf, "SSH-", 4) == 0) + break; + debug("ssh_exchange_identification: %s", buf); + } + server_version_string = xstrdup(buf); + + /* + * Check that the versions match. In future this might accept + * several versions and set appropriate flags to handle them. + */ + if (sscanf(server_version_string, "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); + + compat_datafellows(remote_version); + mismatch = 0; + + switch (remote_major) { + case 1: + if (remote_minor == 99 && + (options.protocol & SSH_PROTO_2) && + !(options.protocol & SSH_PROTO_1_PREFERRED)) { + enable_compat20(); + break; + } + if (!(options.protocol & SSH_PROTO_1)) { + mismatch = 1; + break; + } + if (remote_minor < 3) { + fatal("Remote machine has too old SSH software version."); + } else if (remote_minor == 3 || remote_minor == 4) { + /* We speak 1.3, too. */ + enable_compat13(); + minor1 = 3; + if (options.forward_agent) { + logit("Agent forwarding disabled for protocol 1.3"); + options.forward_agent = 0; + } + } + break; + case 2: + if (options.protocol & SSH_PROTO_2) { + enable_compat20(); + break; + } + /* FALLTHROUGH */ + default: + mismatch = 1; + break; + } + if (mismatch) + fatal("Protocol major versions differ: %d vs. %d", + (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, + remote_major); + /* Send our own protocol version identification. */ + snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", + compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, + compat20 ? PROTOCOL_MINOR_2 : minor1, + SSH_VERSION); + if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf)) + fatal("write: %.100s", strerror(errno)); + client_version_string = xstrdup(buf); + chop(client_version_string); + chop(server_version_string); + debug("Local version string %.100s", client_version_string); +} + +/* defaults to 'no' */ +static int +confirm(const char *prompt) +{ + const char *msg, *again = "Please type 'yes' or 'no': "; + char *p; + int ret = -1; + + if (options.batch_mode) + return 0; + for (msg = prompt;;msg = again) { + p = read_passphrase(msg, RP_ECHO); + if (p == NULL || + (p[0] == '\0') || (p[0] == '\n') || + strncasecmp(p, "no", 2) == 0) + ret = 0; + if (p && strncasecmp(p, "yes", 3) == 0) + ret = 1; + if (p) + xfree(p); + if (ret != -1) + return ret; + } +} + +/* + * check whether the supplied host key is valid, return -1 if the key + * is not valid. the user_hostfile will not be updated if 'readonly' is true. + */ +static int +check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, + int readonly, const char *user_hostfile, const char *system_hostfile) +{ + Key *file_key; + const char *type = key_type(host_key); + char *ip = NULL; + char hostline[1000], *hostp, *fp; + HostStatus host_status; + HostStatus ip_status; + int local = 0, host_ip_differ = 0; + int salen; + char ntop[NI_MAXHOST]; + char msg[1024]; + int len, host_line, ip_line; + const char *host_file = NULL, *ip_file = NULL; + + /* + * Force accepting of the host key for loopback/localhost. 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. + */ + /** hostaddr == 0! */ + switch (hostaddr->sa_family) { + case AF_INET: + local = (ntohl(((struct sockaddr_in *)hostaddr)-> + sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; + salen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + local = IN6_IS_ADDR_LOOPBACK( + &(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); + salen = sizeof(struct sockaddr_in6); + break; + default: + local = 0; + salen = sizeof(struct sockaddr_storage); + break; + } + if (options.no_host_authentication_for_localhost == 1 && local && + options.host_key_alias == NULL) { + debug("Forcing accepting of host key for " + "loopback/localhost."); + return 0; + } + + /* + * We don't have the remote ip-address for connections + * using a proxy command + */ + if (options.proxy_command == NULL) { + if (getnameinfo(hostaddr, salen, ntop, sizeof(ntop), + NULL, 0, NI_NUMERICHOST) != 0) + fatal("check_host_key: getnameinfo failed"); + ip = xstrdup(ntop); + } else { + ip = xstrdup(""); + } + /* + * Turn off check_host_ip if the connection is to localhost, via proxy + * command or if we don't have a hostname to compare with + */ + if (options.check_host_ip && + (local || strcmp(host, ip) == 0 || options.proxy_command != NULL)) + options.check_host_ip = 0; + + /* + * Allow the user to record the key under a different name. This is + * useful for ssh tunneling over forwarded connections or if you run + * multiple sshd's on different ports on the same machine. + */ + if (options.host_key_alias != NULL) { + host = options.host_key_alias; + debug("using hostkeyalias: %s", host); + } + + /* + * Store the host key from the known host file in here so that we can + * compare it with the key for the IP address. + */ + file_key = key_new(host_key->type); + + /* + * Check if the host key is present in the user\'s list of known + * hosts or in the systemwide list. + */ + host_file = user_hostfile; + host_status = check_host_in_hostfile(host_file, host, host_key, + file_key, &host_line); + if (host_status == HOST_NEW) { + host_file = system_hostfile; + host_status = check_host_in_hostfile(host_file, host, host_key, + file_key, &host_line); + } + /* + * Also perform check for the ip address, skip the check if we are + * localhost or the hostname was an ip address to begin with + */ + if (options.check_host_ip) { + Key *ip_key = key_new(host_key->type); + + ip_file = user_hostfile; + ip_status = check_host_in_hostfile(ip_file, ip, host_key, + ip_key, &ip_line); + if (ip_status == HOST_NEW) { + ip_file = system_hostfile; + ip_status = check_host_in_hostfile(ip_file, ip, + host_key, ip_key, &ip_line); + } + if (host_status == HOST_CHANGED && + (ip_status != HOST_CHANGED || !key_equal(ip_key, file_key))) + host_ip_differ = 1; + + key_free(ip_key); + } else + ip_status = host_status; + + key_free(file_key); + + switch (host_status) { + case HOST_OK: + /* The host is known and the key matches. */ + debug("Host '%.200s' is known and matches the %s host key.", + host, type); + debug("Found key in %s:%d", host_file, host_line); + if (options.check_host_ip && ip_status == HOST_NEW) { + if (readonly) + logit("%s host key for IP address " + "'%.128s' not in list of known hosts.", + type, ip); + else if (!add_host_to_hostfile(user_hostfile, ip, + host_key)) + logit("Failed to add the %s host key for IP " + "address '%.128s' to the list of known " + "hosts (%.30s).", type, ip, user_hostfile); + else + logit("Warning: Permanently added the %s host " + "key for IP address '%.128s' to the list " + "of known hosts.", type, ip); + } + break; + case HOST_NEW: + if (readonly) + goto fail; + /* 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. + */ + error("No %s host key is known for %.200s and you " + "have requested strict checking.", type, host); + goto fail; + } else if (options.strict_host_key_checking == 2) { + char msg1[1024], msg2[1024]; + + if (show_other_keys(host, host_key)) + snprintf(msg1, sizeof(msg1), + "\nbut keys of different type are already" + " known for this host."); + else + snprintf(msg1, sizeof(msg1), "."); + /* The default */ + fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); + msg2[0] = '\0'; + if (options.verify_host_key_dns) { + if (matching_host_key_dns) + snprintf(msg2, sizeof(msg2), + "Matching host key fingerprint" + " found in DNS.\n"); + else + snprintf(msg2, sizeof(msg2), + "No matching host key fingerprint" + " found in DNS.\n"); + } + snprintf(msg, sizeof(msg), + "The authenticity of host '%.200s (%s)' can't be " + "established%s\n" + "%s key fingerprint is %s.\n%s" + "Are you sure you want to continue connecting " + "(yes/no)? ", + host, ip, msg1, type, fp, msg2); + xfree(fp); + if (!confirm(msg)) + goto fail; + } + if (options.check_host_ip && ip_status == HOST_NEW) { + snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); + hostp = hostline; + } else + hostp = host; + + /* + * If not in strict mode, add the key automatically to the + * local known_hosts file. + */ + if (!add_host_to_hostfile(user_hostfile, hostp, host_key)) + logit("Failed to add the host to the list of known " + "hosts (%.500s).", user_hostfile); + else + logit("Warning: Permanently added '%.200s' (%s) to the " + "list of known hosts.", hostp, type); + break; + case HOST_CHANGED: + if (options.check_host_ip && host_ip_differ) { + char *key_msg; + if (ip_status == HOST_NEW) + key_msg = "is unknown"; + else if (ip_status == HOST_OK) + key_msg = "is unchanged"; + else + key_msg = "has a different value"; + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("The %s host key for %s has changed,", type, host); + error("and the key for the according IP address %s", ip); + error("%s. This could either mean that", key_msg); + error("DNS SPOOFING is happening or the IP address for the host"); + error("and its host key have changed at the same time."); + if (ip_status != HOST_NEW) + error("Offending key for IP in %s:%d", ip_file, ip_line); + } + /* The host key has changed. */ + warn_changed_key(host_key); + error("Add correct host key in %.100s to get rid of this message.", + user_hostfile); + error("Offending key in %s:%d", host_file, host_line); + + /* + * 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) { + error("%s host key for %.200s has changed and you have " + "requested strict checking.", type, host); + goto fail; + } + + /* + * If strict host key checking has not been requested, allow + * the connection but without MITM-able authentication or + * agent forwarding. + */ + if (options.password_authentication) { + error("Password authentication is disabled to avoid " + "man-in-the-middle attacks."); + options.password_authentication = 0; + } + if (options.kbd_interactive_authentication) { + error("Keyboard-interactive authentication is disabled" + " to avoid man-in-the-middle attacks."); + options.kbd_interactive_authentication = 0; + options.challenge_response_authentication = 0; + } + if (options.challenge_response_authentication) { + error("Challenge/response authentication is disabled" + " to avoid man-in-the-middle attacks."); + options.challenge_response_authentication = 0; + } + if (options.forward_agent) { + error("Agent forwarding is disabled to avoid " + "man-in-the-middle attacks."); + options.forward_agent = 0; + } + if (options.forward_x11) { + error("X11 forwarding is disabled to avoid " + "man-in-the-middle attacks."); + options.forward_x11 = 0; + } + if (options.num_local_forwards > 0 || + options.num_remote_forwards > 0) { + error("Port forwarding is disabled to avoid " + "man-in-the-middle attacks."); + options.num_local_forwards = + options.num_remote_forwards = 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; + case HOST_FOUND: + fatal("internal error"); + break; + } + + if (options.check_host_ip && host_status != HOST_CHANGED && + ip_status == HOST_CHANGED) { + snprintf(msg, sizeof(msg), + "Warning: the %s host key for '%.200s' " + "differs from the key for the IP address '%.128s'" + "\nOffending key for IP in %s:%d", + type, host, ip, ip_file, ip_line); + if (host_status == HOST_OK) { + len = strlen(msg); + snprintf(msg + len, sizeof(msg) - len, + "\nMatching host key in %s:%d", + host_file, host_line); + } + if (options.strict_host_key_checking == 1) { + logit("%s", msg); + error("Exiting, you have requested strict checking."); + goto fail; + } else if (options.strict_host_key_checking == 2) { + strlcat(msg, "\nAre you sure you want " + "to continue connecting (yes/no)? ", sizeof(msg)); + if (!confirm(msg)) + goto fail; + } else { + logit("%s", msg); + } + } + + xfree(ip); + return 0; + +fail: + xfree(ip); + return -1; +} + +/* returns 0 if key verifies or -1 if key does NOT verify */ +int +verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) +{ + struct stat st; + int flags = 0; + + if (options.verify_host_key_dns && + verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { + + if (flags & DNS_VERIFY_FOUND) { + + if (options.verify_host_key_dns == 1 && + flags & DNS_VERIFY_MATCH && + flags & DNS_VERIFY_SECURE) + return 0; + + if (flags & DNS_VERIFY_MATCH) { + matching_host_key_dns = 1; + } else { + warn_changed_key(host_key); + error("Update the SSHFP RR in DNS with the new " + "host key to get rid of this message."); + } + } + } + + /* return ok if the key can be found in an old keyfile */ + if (stat(options.system_hostfile2, &st) == 0 || + stat(options.user_hostfile2, &st) == 0) { + if (check_host_key(host, hostaddr, host_key, /*readonly*/ 1, + options.user_hostfile2, options.system_hostfile2) == 0) + return 0; + } + return check_host_key(host, hostaddr, host_key, /*readonly*/ 0, + options.user_hostfile, options.system_hostfile); +} + +/* + * 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 function does not require super-user privileges. + */ +void +ssh_login(Sensitive *sensitive, const char *orighost, + struct sockaddr *hostaddr, struct passwd *pw) +{ + char *host, *cp; + char *server_user, *local_user; + + local_user = xstrdup(pw->pw_name); + server_user = options.user ? options.user : local_user; + + /* 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(); + + /* key exchange */ + /* authenticate user */ + if (compat20) { + ssh_kex2(host, hostaddr); + ssh_userauth2(local_user, server_user, host, sensitive); + } else { + ssh_kex(host, hostaddr); + ssh_userauth1(local_user, server_user, host, sensitive); + } +} + +void +ssh_put_password(char *password) +{ + int size; + char *padded; + + if (datafellows & SSH_BUG_PASSWORDPAD) { + packet_put_cstring(password); + return; + } + size = roundup(strlen(password) + 1, 32); + padded = xmalloc(size); + memset(padded, 0, size); + strlcpy(padded, password, size); + packet_put_string(padded, size); + memset(padded, 0, size); + xfree(padded); +} + +static int +show_key_from_file(const char *file, const char *host, int keytype) +{ + Key *found; + char *fp; + int line, ret; + + found = key_new(keytype); + if ((ret = lookup_key_in_hostfile_by_type(file, host, + keytype, found, &line))) { + fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); + logit("WARNING: %s key found for host %s\n" + "in %s:%d\n" + "%s key fingerprint %s.", + key_type(found), host, file, line, + key_type(found), fp); + xfree(fp); + } + key_free(found); + return (ret); +} + +/* print all known host keys for a given host, but skip keys of given type */ +static int +show_other_keys(const char *host, Key *key) +{ + int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, -1}; + int i, found = 0; + + for (i = 0; type[i] != -1; i++) { + if (type[i] == key->type) + continue; + if (type[i] != KEY_RSA1 && + show_key_from_file(options.user_hostfile2, host, type[i])) { + found = 1; + continue; + } + if (type[i] != KEY_RSA1 && + show_key_from_file(options.system_hostfile2, host, type[i])) { + found = 1; + continue; + } + if (show_key_from_file(options.user_hostfile, host, type[i])) { + found = 1; + continue; + } + if (show_key_from_file(options.system_hostfile, host, type[i])) { + found = 1; + continue; + } + debug2("no key of type %d for host %s", type[i], host); + } + return (found); +} + +static void +warn_changed_key(Key *host_key) +{ + char *fp; + const char *type = key_type(host_key); + + fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); + + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: REMOTE 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 %s host key has just been changed.", type); + error("The fingerprint for the %s key sent by the remote host is\n%s.", + type, fp); + error("Please contact your system administrator."); + + xfree(fp); +} diff --git a/crypto/openssh-3.9p1/sshconnect.h b/crypto/openssh-3.9p1/sshconnect.h new file mode 100644 index 0000000000..0be30fe695 --- /dev/null +++ b/crypto/openssh-3.9p1/sshconnect.h @@ -0,0 +1,69 @@ +/* $OpenBSD: sshconnect.h,v 1.17 2002/06/19 00:27:55 deraadt Exp $ */ + +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SSHCONNECT_H +#define SSHCONNECT_H + +typedef struct Sensitive Sensitive; +struct Sensitive { + Key **keys; + int nkeys; + int external_keysign; +}; + +int +ssh_connect(const char *, struct sockaddr_storage *, u_short, int, int, + int, const char *); + +void +ssh_login(Sensitive *, const char *, struct sockaddr *, struct passwd *); + +int verify_host_key(char *, struct sockaddr *, Key *); + +void ssh_kex(char *, struct sockaddr *); +void ssh_kex2(char *, struct sockaddr *); + +void ssh_userauth1(const char *, const char *, char *, Sensitive *); +void ssh_userauth2(const char *, const char *, char *, Sensitive *); + +void ssh_put_password(char *); + + +/* + * Macros to raise/lower permissions. + */ +#define PRIV_START do { \ + int save_errno = errno; \ + (void)seteuid(original_effective_uid); \ + errno = save_errno; \ +} while (0) + +#define PRIV_END do { \ + int save_errno = errno; \ + (void)seteuid(original_real_uid); \ + errno = save_errno; \ +} while (0) + +#endif diff --git a/crypto/openssh-3.9p1/sshconnect1.c b/crypto/openssh-3.9p1/sshconnect1.c new file mode 100644 index 0000000000..6e2e31c028 --- /dev/null +++ b/crypto/openssh-3.9p1/sshconnect1.c @@ -0,0 +1,735 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Code to connect to a remote host, and to perform the client side of the + * login (authentication) dialog. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: sshconnect1.c,v 1.60 2004/07/28 09:40:29 markus Exp $"); + +#include +#include + +#include "ssh.h" +#include "ssh1.h" +#include "xmalloc.h" +#include "rsa.h" +#include "buffer.h" +#include "packet.h" +#include "kex.h" +#include "uidswap.h" +#include "log.h" +#include "readconf.h" +#include "key.h" +#include "authfd.h" +#include "sshconnect.h" +#include "authfile.h" +#include "misc.h" +#include "cipher.h" +#include "canohost.h" +#include "auth.h" + +/* Session id for the current session. */ +u_char session_id[16]; +u_int supported_authentications = 0; + +extern Options options; +extern char *__progname; + +/* + * Checks if the user has an authentication agent, and if so, tries to + * authenticate using the agent. + */ +static int +try_agent_authentication(void) +{ + int type; + char *comment; + AuthenticationConnection *auth; + u_char response[16]; + u_int i; + Key *key; + BIGNUM *challenge; + + /* Get connection to the agent. */ + auth = ssh_get_authentication_connection(); + if (!auth) + return 0; + + if ((challenge = BN_new()) == NULL) + fatal("try_agent_authentication: BN_new failed"); + /* Loop through identities served by the agent. */ + for (key = ssh_get_first_identity(auth, &comment, 1); + key != NULL; + key = ssh_get_next_identity(auth, &comment, 1)) { + + /* 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_bignum(key->rsa->n); + packet_send(); + packet_write_wait(); + + /* Wait for server's response. */ + type = packet_read(); + + /* 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."); + key_free(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_bignum(challenge); + packet_check_eom(); + + debug("Received RSA challenge from server."); + + /* Ask the agent to decrypt the challenge. */ + if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) { + /* + * The agent failed to authenticate this identifier + * although it advertised it supports this. Just + * return a wrong value. + */ + logit("Authentication agent failed to decrypt challenge."); + memset(response, 0, sizeof(response)); + } + key_free(key); + 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(); + + /* The server returns success if it accepted the authentication. */ + if (type == SSH_SMSG_SUCCESS) { + ssh_close_authentication_connection(auth); + BN_clear_free(challenge); + debug("RSA authentication accepted by server."); + return 1; + } + /* Otherwise it should return failure. */ + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error waiting RSA auth response: %d", + type); + } + ssh_close_authentication_connection(auth); + BN_clear_free(challenge); + debug("RSA authentication using agent refused."); + return 0; +} + +/* + * Computes the proper response to a RSA challenge, and sends the response to + * the server. + */ +static void +respond_to_rsa_challenge(BIGNUM * challenge, RSA * prv) +{ + u_char buf[32], response[16]; + MD5_CTX md; + int i, len; + + /* Decrypt the challenge using the private key. */ + /* XXX think about Bleichenbacher, too */ + if (rsa_private_decrypt(challenge, challenge, prv) <= 0) + packet_disconnect( + "respond_to_rsa_challenge: rsa_private_decrypt failed"); + + /* Compute the response. */ + /* The response is MD5 of decrypted challenge plus session id. */ + len = BN_num_bytes(challenge); + if (len <= 0 || len > sizeof(buf)) + packet_disconnect( + "respond_to_rsa_challenge: bad challenge length %d", len); + + memset(buf, 0, sizeof(buf)); + BN_bn2bin(challenge, buf + sizeof(buf) - len); + MD5_Init(&md); + MD5_Update(&md, buf, 32); + MD5_Update(&md, session_id, 16); + MD5_Final(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. + */ +static int +try_rsa_authentication(int idx) +{ + BIGNUM *challenge; + Key *public, *private; + char buf[300], *passphrase, *comment, *authfile; + int i, type, quit; + + public = options.identity_keys[idx]; + authfile = options.identity_files[idx]; + comment = xstrdup(authfile); + + 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_bignum(public->rsa->n); + packet_send(); + packet_write_wait(); + + /* Wait for server's response. */ + type = packet_read(); + + /* + * 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; + } + /* 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. */ + if ((challenge = BN_new()) == NULL) + fatal("try_rsa_authentication: BN_new failed"); + packet_get_bignum(challenge); + packet_check_eom(); + + debug("Received RSA challenge from server."); + + /* + * If the key is not stored in external hardware, we have to + * load the private key. Try first with empty passphrase; if it + * fails, ask for a passphrase. + */ + if (public->flags & KEY_FLAG_EXT) + private = public; + else + private = key_load_private_type(KEY_RSA1, authfile, "", NULL); + if (private == NULL && !options.batch_mode) { + snprintf(buf, sizeof(buf), + "Enter passphrase for RSA key '%.100s': ", comment); + for (i = 0; i < options.number_of_password_prompts; i++) { + passphrase = read_passphrase(buf, 0); + if (strcmp(passphrase, "") != 0) { + private = key_load_private_type(KEY_RSA1, + authfile, passphrase, NULL); + quit = 0; + } else { + debug2("no passphrase given, try next key"); + quit = 1; + } + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + if (private != NULL || quit) + break; + debug2("bad passphrase given, try again..."); + } + } + /* We no longer need the comment. */ + xfree(comment); + + if (private == NULL) { + if (!options.batch_mode) + 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(SSH_SMSG_FAILURE); + BN_clear_free(challenge); + return 0; + } + + /* Compute and send a response to the challenge. */ + respond_to_rsa_challenge(challenge, private->rsa); + + /* Destroy the private key unless it in external hardware. */ + if (!(private->flags & KEY_FLAG_EXT)) + key_free(private); + + /* We no longer need the challenge. */ + BN_clear_free(challenge); + + /* Wait for response from the server. */ + type = packet_read(); + 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. + */ +static int +try_rhosts_rsa_authentication(const char *local_user, Key * host_key) +{ + int type; + BIGNUM *challenge; + + 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_cstring(local_user); + packet_put_int(BN_num_bits(host_key->rsa->n)); + packet_put_bignum(host_key->rsa->e); + packet_put_bignum(host_key->rsa->n); + packet_send(); + packet_write_wait(); + + /* Wait for server's response. */ + type = packet_read(); + + /* 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; + } + /* 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. */ + if ((challenge = BN_new()) == NULL) + fatal("try_rhosts_rsa_authentication: BN_new failed"); + packet_get_bignum(challenge); + packet_check_eom(); + + debug("Received RSA challenge for host key from server."); + + /* Compute a response to the challenge. */ + respond_to_rsa_challenge(challenge, host_key->rsa); + + /* We no longer need the challenge. */ + BN_clear_free(challenge); + + /* Wait for response from the server. */ + type = packet_read(); + 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; +} + +/* + * Tries to authenticate with any string-based challenge/response system. + * Note that the client code is not tied to s/key or TIS. + */ +static int +try_challenge_response_authentication(void) +{ + int type, i; + u_int clen; + char prompt[1024]; + char *challenge, *response; + + debug("Doing challenge response authentication."); + + for (i = 0; i < options.number_of_password_prompts; i++) { + /* request a challenge */ + packet_start(SSH_CMSG_AUTH_TIS); + packet_send(); + packet_write_wait(); + + type = packet_read(); + if (type != SSH_SMSG_FAILURE && + type != SSH_SMSG_AUTH_TIS_CHALLENGE) { + packet_disconnect("Protocol error: got %d in response " + "to SSH_CMSG_AUTH_TIS", type); + } + if (type != SSH_SMSG_AUTH_TIS_CHALLENGE) { + debug("No challenge."); + return 0; + } + challenge = packet_get_string(&clen); + packet_check_eom(); + snprintf(prompt, sizeof prompt, "%s%s", challenge, + strchr(challenge, '\n') ? "" : "\nResponse: "); + xfree(challenge); + if (i != 0) + error("Permission denied, please try again."); + if (options.cipher == SSH_CIPHER_NONE) + logit("WARNING: Encryption is disabled! " + "Response will be transmitted in clear text."); + response = read_passphrase(prompt, 0); + if (strcmp(response, "") == 0) { + xfree(response); + break; + } + packet_start(SSH_CMSG_AUTH_TIS_RESPONSE); + ssh_put_password(response); + memset(response, 0, strlen(response)); + xfree(response); + packet_send(); + packet_write_wait(); + type = packet_read(); + if (type == SSH_SMSG_SUCCESS) + return 1; + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error: got %d in response " + "to SSH_CMSG_AUTH_TIS_RESPONSE", type); + } + /* failure */ + return 0; +} + +/* + * Tries to authenticate with plain passwd authentication. + */ +static int +try_password_authentication(char *prompt) +{ + int type, i; + char *password; + + debug("Doing password authentication."); + if (options.cipher == SSH_CIPHER_NONE) + logit("WARNING: Encryption is disabled! Password will be transmitted in clear text."); + for (i = 0; i < options.number_of_password_prompts; i++) { + if (i != 0) + error("Permission denied, please try again."); + password = read_passphrase(prompt, 0); + packet_start(SSH_CMSG_AUTH_PASSWORD); + ssh_put_password(password); + memset(password, 0, strlen(password)); + xfree(password); + packet_send(); + packet_write_wait(); + + type = packet_read(); + if (type == SSH_SMSG_SUCCESS) + return 1; + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error: got %d in response to passwd auth", type); + } + /* failure */ + return 0; +} + +/* + * SSH1 key exchange + */ +void +ssh_kex(char *host, struct sockaddr *hostaddr) +{ + int i; + BIGNUM *key; + Key *host_key, *server_key; + int bits, rbits; + int ssh_cipher_default = SSH_CIPHER_3DES; + u_char session_key[SSH_SESSION_KEY_LENGTH]; + u_char cookie[8]; + u_int supported_ciphers; + u_int server_flags, client_flags; + u_int32_t rnd = 0; + + debug("Waiting for server public key."); + + /* Wait for a public key packet from the server. */ + packet_read_expect(SSH_SMSG_PUBLIC_KEY); + + /* Get cookie from the packet. */ + for (i = 0; i < 8; i++) + cookie[i] = packet_get_char(); + + /* Get the public key. */ + server_key = key_new(KEY_RSA1); + bits = packet_get_int(); + packet_get_bignum(server_key->rsa->e); + packet_get_bignum(server_key->rsa->n); + + rbits = BN_num_bits(server_key->rsa->n); + if (bits != rbits) { + logit("Warning: Server lies about size of server public key: " + "actual size is %d bits vs. announced %d.", rbits, bits); + logit("Warning: This may be due to an old implementation of ssh."); + } + /* Get the host key. */ + host_key = key_new(KEY_RSA1); + bits = packet_get_int(); + packet_get_bignum(host_key->rsa->e); + packet_get_bignum(host_key->rsa->n); + + rbits = BN_num_bits(host_key->rsa->n); + if (bits != rbits) { + logit("Warning: Server lies about size of server host key: " + "actual size is %d bits vs. announced %d.", rbits, bits); + logit("Warning: This may be due to an old implementation of ssh."); + } + + /* Get protocol flags. */ + server_flags = packet_get_int(); + packet_set_protocol_flags(server_flags); + + supported_ciphers = packet_get_int(); + supported_authentications = packet_get_int(); + packet_check_eom(); + + debug("Received server public key (%d bits) and host key (%d bits).", + BN_num_bits(server_key->rsa->n), BN_num_bits(host_key->rsa->n)); + + if (verify_host_key(host, hostaddr, host_key) == -1) + fatal("Host key verification failed."); + + client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN; + + derive_ssh1_session_id(host_key->rsa->n, server_key->rsa->n, cookie, session_id); + + /* Generate a session key. */ + arc4random_stir(); + + /* + * 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++) { + if (i % 4 == 0) + rnd = arc4random(); + session_key[i] = rnd & 0xff; + rnd >>= 8; + } + + /* + * 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. + */ + if ((key = BN_new()) == NULL) + fatal("respond_to_rsa_challenge: BN_new failed"); + BN_set_word(key, 0); + for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { + BN_lshift(key, key, 8); + if (i < 16) + BN_add_word(key, session_key[i] ^ session_id[i]); + else + BN_add_word(key, session_key[i]); + } + + /* + * Encrypt the integer using the public key and host key of the + * server (key with smaller modulus first). + */ + if (BN_cmp(server_key->rsa->n, host_key->rsa->n) < 0) { + /* Public key has smaller modulus. */ + if (BN_num_bits(host_key->rsa->n) < + BN_num_bits(server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("respond_to_rsa_challenge: host_key %d < server_key %d + " + "SSH_KEY_BITS_RESERVED %d", + BN_num_bits(host_key->rsa->n), + BN_num_bits(server_key->rsa->n), + SSH_KEY_BITS_RESERVED); + } + rsa_public_encrypt(key, key, server_key->rsa); + rsa_public_encrypt(key, key, host_key->rsa); + } else { + /* Host key has smaller modulus (or they are equal). */ + if (BN_num_bits(server_key->rsa->n) < + BN_num_bits(host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("respond_to_rsa_challenge: server_key %d < host_key %d + " + "SSH_KEY_BITS_RESERVED %d", + BN_num_bits(server_key->rsa->n), + BN_num_bits(host_key->rsa->n), + SSH_KEY_BITS_RESERVED); + } + rsa_public_encrypt(key, key, host_key->rsa); + rsa_public_encrypt(key, key, server_key->rsa); + } + + /* Destroy the public keys since we no longer need them. */ + key_free(server_key); + key_free(host_key); + + if (options.cipher == SSH_CIPHER_NOT_SET) { + if (cipher_mask_ssh1(1) & supported_ciphers & (1 << ssh_cipher_default)) + options.cipher = ssh_cipher_default; + } else if (options.cipher == SSH_CIPHER_INVALID || + !(cipher_mask_ssh1(1) & (1 << options.cipher))) { + logit("No valid SSH1 cipher, using %.100s instead.", + cipher_name(ssh_cipher_default)); + options.cipher = ssh_cipher_default; + } + /* 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 cookie back to the server. */ + for (i = 0; i < 8; i++) + packet_put_char(cookie[i]); + + /* Send and destroy the encrypted encryption key integer. */ + packet_put_bignum(key); + BN_clear_free(key); + + /* Send protocol flags. */ + packet_put_int(client_flags); + + /* Send the packet now. */ + packet_send(); + packet_write_wait(); + + debug("Sent encrypted session key."); + + /* Set the encryption key. */ + packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, options.cipher); + + /* 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(SSH_SMSG_SUCCESS); + + debug("Received encrypted confirmation."); +} + +/* + * Authenticate user + */ +void +ssh_userauth1(const char *local_user, const char *server_user, char *host, + Sensitive *sensitive) +{ + int i, type; + + if (supported_authentications == 0) + fatal("ssh_userauth1: server supports no auth methods"); + + /* Send the name of the user to log in as on the server. */ + packet_start(SSH_CMSG_USER); + packet_put_cstring(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(); + + /* check whether the connection was accepted without authentication. */ + if (type == SSH_SMSG_SUCCESS) + goto success; + if (type != SSH_SMSG_FAILURE) + packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", type); + + /* + * Try .rhosts or /etc/hosts.equiv authentication with RSA host + * authentication. + */ + if ((supported_authentications & (1 << SSH_AUTH_RHOSTS_RSA)) && + options.rhosts_rsa_authentication) { + for (i = 0; i < sensitive->nkeys; i++) { + if (sensitive->keys[i] != NULL && + sensitive->keys[i]->type == KEY_RSA1 && + try_rhosts_rsa_authentication(local_user, + sensitive->keys[i])) + goto success; + } + } + /* 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()) + goto success; + + /* Try RSA authentication for each identity. */ + for (i = 0; i < options.num_identity_files; i++) + if (options.identity_keys[i] != NULL && + options.identity_keys[i]->type == KEY_RSA1 && + try_rsa_authentication(i)) + goto success; + } + /* Try challenge response authentication if the server supports it. */ + if ((supported_authentications & (1 << SSH_AUTH_TIS)) && + options.challenge_response_authentication && !options.batch_mode) { + if (try_challenge_response_authentication()) + goto success; + } + /* Try password authentication if the server supports it. */ + if ((supported_authentications & (1 << SSH_AUTH_PASSWORD)) && + options.password_authentication && !options.batch_mode) { + char prompt[80]; + + snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", + server_user, host); + if (try_password_authentication(prompt)) + goto success; + } + /* All authentication methods have failed. Exit with an error message. */ + fatal("Permission denied."); + /* NOTREACHED */ + + success: + return; /* need statement after label */ +} diff --git a/crypto/openssh-3.9p1/sshconnect2.c b/crypto/openssh-3.9p1/sshconnect2.c new file mode 100644 index 0000000000..68d56d0207 --- /dev/null +++ b/crypto/openssh-3.9p1/sshconnect2.c @@ -0,0 +1,1485 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: sshconnect2.c,v 1.138 2004/06/13 12:53:24 djm Exp $"); + +#include "openbsd-compat/sys-queue.h" + +#include "ssh.h" +#include "ssh2.h" +#include "xmalloc.h" +#include "buffer.h" +#include "packet.h" +#include "compat.h" +#include "bufaux.h" +#include "cipher.h" +#include "kex.h" +#include "myproposal.h" +#include "sshconnect.h" +#include "authfile.h" +#include "dh.h" +#include "authfd.h" +#include "log.h" +#include "readconf.h" +#include "misc.h" +#include "match.h" +#include "dispatch.h" +#include "canohost.h" +#include "msg.h" +#include "pathnames.h" + +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + +/* import */ +extern char *client_version_string; +extern char *server_version_string; +extern Options options; + +/* + * SSH2 key exchange + */ + +u_char *session_id2 = NULL; +u_int session_id2_len = 0; + +char *xxx_host; +struct sockaddr *xxx_hostaddr; + +Kex *xxx_kex = NULL; + +static int +verify_host_key_callback(Key *hostkey) +{ + if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) + fatal("Host key verification failed."); + return 0; +} + +void +ssh_kex2(char *host, struct sockaddr *hostaddr) +{ + Kex *kex; + + xxx_host = host; + xxx_hostaddr = hostaddr; + + if (options.ciphers == (char *)-1) { + logit("No valid ciphers for protocol version 2 given, using defaults."); + options.ciphers = NULL; + } + if (options.ciphers != NULL) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; + } + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); + myproposal[PROPOSAL_ENC_ALGS_STOC] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); + if (options.compression) { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = + myproposal[PROPOSAL_COMP_ALGS_STOC] = "zlib,none"; + } else { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = + myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib"; + } + if (options.macs != NULL) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; + } + if (options.hostkeyalgorithms != NULL) + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = + options.hostkeyalgorithms; + + if (options.rekey_limit) + packet_set_rekey_limit(options.rekey_limit); + + /* start key exchange */ + kex = kex_setup(myproposal); + kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; + kex->client_version_string=client_version_string; + kex->server_version_string=server_version_string; + kex->verify_host_key=&verify_host_key_callback; + + xxx_kex = kex; + + dispatch_run(DISPATCH_BLOCK, &kex->done, kex); + + session_id2 = kex->session_id; + session_id2_len = kex->session_id_len; + +#ifdef DEBUG_KEXDH + /* send 1st encrypted/maced/compressed message */ + packet_start(SSH2_MSG_IGNORE); + packet_put_cstring("markus"); + packet_send(); + packet_write_wait(); +#endif +} + +/* + * Authenticate user + */ + +typedef struct Authctxt Authctxt; +typedef struct Authmethod Authmethod; +typedef struct identity Identity; +typedef struct idlist Idlist; + +struct identity { + TAILQ_ENTRY(identity) next; + AuthenticationConnection *ac; /* set if agent supports key */ + Key *key; /* public/private key */ + char *filename; /* comment for agent-only keys */ + int tried; + int isprivate; /* key points to the private key */ +}; +TAILQ_HEAD(idlist, identity); + +struct Authctxt { + const char *server_user; + const char *local_user; + const char *host; + const char *service; + Authmethod *method; + int success; + char *authlist; + /* pubkey */ + Idlist keys; + AuthenticationConnection *agent; + /* hostbased */ + Sensitive *sensitive; + /* kbd-interactive */ + int info_req_seen; + /* generic */ + void *methoddata; +}; +struct Authmethod { + char *name; /* string to compare against server's list */ + int (*userauth)(Authctxt *authctxt); + int *enabled; /* flag in option struct that enables method */ + int *batch_flag; /* flag in option struct that disables method */ +}; + +void input_userauth_success(int, u_int32_t, void *); +void input_userauth_failure(int, u_int32_t, void *); +void input_userauth_banner(int, u_int32_t, void *); +void input_userauth_error(int, u_int32_t, void *); +void input_userauth_info_req(int, u_int32_t, void *); +void input_userauth_pk_ok(int, u_int32_t, void *); +void input_userauth_passwd_changereq(int, u_int32_t, void *); + +int userauth_none(Authctxt *); +int userauth_pubkey(Authctxt *); +int userauth_passwd(Authctxt *); +int userauth_kbdint(Authctxt *); +int userauth_hostbased(Authctxt *); +int userauth_kerberos(Authctxt *); + +#ifdef GSSAPI +int userauth_gssapi(Authctxt *authctxt); +void input_gssapi_response(int type, u_int32_t, void *); +void input_gssapi_token(int type, u_int32_t, void *); +void input_gssapi_hash(int type, u_int32_t, void *); +void input_gssapi_error(int, u_int32_t, void *); +void input_gssapi_errtok(int, u_int32_t, void *); +#endif + +void userauth(Authctxt *, char *); + +static int sign_and_send_pubkey(Authctxt *, Identity *); +static void pubkey_prepare(Authctxt *); +static void pubkey_cleanup(Authctxt *); +static Key *load_identity_file(char *); + +static Authmethod *authmethod_get(char *authlist); +static Authmethod *authmethod_lookup(const char *name); +static char *authmethods_get(void); + +Authmethod authmethods[] = { +#ifdef GSSAPI + {"gssapi-with-mic", + userauth_gssapi, + &options.gss_authentication, + NULL}, +#endif + {"hostbased", + userauth_hostbased, + &options.hostbased_authentication, + NULL}, + {"publickey", + userauth_pubkey, + &options.pubkey_authentication, + NULL}, + {"keyboard-interactive", + userauth_kbdint, + &options.kbd_interactive_authentication, + &options.batch_mode}, + {"password", + userauth_passwd, + &options.password_authentication, + &options.batch_mode}, + {"none", + userauth_none, + NULL, + NULL}, + {NULL, NULL, NULL, NULL} +}; + +void +ssh_userauth2(const char *local_user, const char *server_user, char *host, + Sensitive *sensitive) +{ + Authctxt authctxt; + int type; + + if (options.challenge_response_authentication) + options.kbd_interactive_authentication = 1; + + packet_start(SSH2_MSG_SERVICE_REQUEST); + packet_put_cstring("ssh-userauth"); + packet_send(); + debug("SSH2_MSG_SERVICE_REQUEST sent"); + packet_write_wait(); + type = packet_read(); + if (type != SSH2_MSG_SERVICE_ACCEPT) + fatal("Server denied authentication request: %d", type); + if (packet_remaining() > 0) { + char *reply = packet_get_string(NULL); + debug2("service_accept: %s", reply); + xfree(reply); + } else { + debug2("buggy server: service_accept w/o service"); + } + packet_check_eom(); + debug("SSH2_MSG_SERVICE_ACCEPT received"); + + if (options.preferred_authentications == NULL) + options.preferred_authentications = authmethods_get(); + + /* setup authentication context */ + memset(&authctxt, 0, sizeof(authctxt)); + pubkey_prepare(&authctxt); + authctxt.server_user = server_user; + authctxt.local_user = local_user; + authctxt.host = host; + authctxt.service = "ssh-connection"; /* service name */ + authctxt.success = 0; + authctxt.method = authmethod_lookup("none"); + authctxt.authlist = NULL; + authctxt.methoddata = NULL; + authctxt.sensitive = sensitive; + authctxt.info_req_seen = 0; + if (authctxt.method == NULL) + fatal("ssh_userauth2: internal error: cannot send userauth none request"); + + /* initial userauth request */ + userauth_none(&authctxt); + + dispatch_init(&input_userauth_error); + dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); + dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); + dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); + dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt); /* loop until success */ + + pubkey_cleanup(&authctxt); + dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL); + + debug("Authentication succeeded (%s).", authctxt.method->name); +} + +void +userauth(Authctxt *authctxt, char *authlist) +{ + if (authctxt->methoddata) { + xfree(authctxt->methoddata); + authctxt->methoddata = NULL; + } + if (authlist == NULL) { + authlist = authctxt->authlist; + } else { + if (authctxt->authlist) + xfree(authctxt->authlist); + authctxt->authlist = authlist; + } + for (;;) { + Authmethod *method = authmethod_get(authlist); + if (method == NULL) + fatal("Permission denied (%s).", authlist); + authctxt->method = method; + + /* reset the per method handler */ + dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN, + SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL); + + /* and try new method */ + if (method->userauth(authctxt) != 0) { + debug2("we sent a %s packet, wait for reply", method->name); + break; + } else { + debug2("we did not send a packet, disable method"); + method->enabled = NULL; + } + } +} + +void +input_userauth_error(int type, u_int32_t seq, void *ctxt) +{ + fatal("input_userauth_error: bad message during authentication: " + "type %d", type); +} + +void +input_userauth_banner(int type, u_int32_t seq, void *ctxt) +{ + char *msg, *lang; + + debug3("input_userauth_banner"); + msg = packet_get_string(NULL); + lang = packet_get_string(NULL); + if (options.log_level > SYSLOG_LEVEL_QUIET) + fprintf(stderr, "%s", msg); + xfree(msg); + xfree(lang); +} + +void +input_userauth_success(int type, u_int32_t seq, void *ctxt) +{ + Authctxt *authctxt = ctxt; + if (authctxt == NULL) + fatal("input_userauth_success: no authentication context"); + if (authctxt->authlist) { + xfree(authctxt->authlist); + authctxt->authlist = NULL; + } + if (authctxt->methoddata) { + xfree(authctxt->methoddata); + authctxt->methoddata = NULL; + } + authctxt->success = 1; /* break out */ +} + +void +input_userauth_failure(int type, u_int32_t seq, void *ctxt) +{ + Authctxt *authctxt = ctxt; + char *authlist = NULL; + int partial; + + if (authctxt == NULL) + fatal("input_userauth_failure: no authentication context"); + + authlist = packet_get_string(NULL); + partial = packet_get_char(); + packet_check_eom(); + + if (partial != 0) + logit("Authenticated with partial success."); + debug("Authentications that can continue: %s", authlist); + + userauth(authctxt, authlist); +} +void +input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Key *key = NULL; + Identity *id = NULL; + Buffer b; + int pktype, sent = 0; + u_int alen, blen; + char *pkalg, *fp; + u_char *pkblob; + + if (authctxt == NULL) + fatal("input_userauth_pk_ok: no authentication context"); + if (datafellows & SSH_BUG_PKOK) { + /* this is similar to SSH_BUG_PKAUTH */ + debug2("input_userauth_pk_ok: SSH_BUG_PKOK"); + pkblob = packet_get_string(&blen); + buffer_init(&b); + buffer_append(&b, pkblob, blen); + pkalg = buffer_get_string(&b, &alen); + buffer_free(&b); + } else { + pkalg = packet_get_string(&alen); + pkblob = packet_get_string(&blen); + } + packet_check_eom(); + + debug("Server accepts key: pkalg %s blen %u", pkalg, blen); + + if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { + debug("unknown pkalg %s", pkalg); + goto done; + } + if ((key = key_from_blob(pkblob, blen)) == NULL) { + debug("no key from blob. pkalg %s", pkalg); + goto done; + } + if (key->type != pktype) { + error("input_userauth_pk_ok: type mismatch " + "for decoded key (received %d, expected %d)", + key->type, pktype); + goto done; + } + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + debug2("input_userauth_pk_ok: fp %s", fp); + xfree(fp); + + /* + * search keys in the reverse order, because last candidate has been + * moved to the end of the queue. this also avoids confusion by + * duplicate keys + */ + TAILQ_FOREACH_REVERSE(id, &authctxt->keys, idlist, next) { + if (key_equal(key, id->key)) { + sent = sign_and_send_pubkey(authctxt, id); + break; + } + } +done: + if (key != NULL) + key_free(key); + xfree(pkalg); + xfree(pkblob); + + /* try another method if we did not send a packet */ + if (sent == 0) + userauth(authctxt, NULL); +} + +#ifdef GSSAPI +int +userauth_gssapi(Authctxt *authctxt) +{ + Gssctxt *gssctxt = NULL; + static gss_OID_set gss_supported = NULL; + static int mech = 0; + OM_uint32 min; + int ok = 0; + + /* Try one GSSAPI method at a time, rather than sending them all at + * once. */ + + if (gss_supported == NULL) + gss_indicate_mechs(&min, &gss_supported); + + /* Check to see if the mechanism is usable before we offer it */ + while (mech < gss_supported->count && !ok) { + if (gssctxt) + ssh_gssapi_delete_ctx(&gssctxt); + ssh_gssapi_build_ctx(&gssctxt); + ssh_gssapi_set_oid(gssctxt, &gss_supported->elements[mech]); + + /* My DER encoding requires length<128 */ + if (gss_supported->elements[mech].length < 128 && + !GSS_ERROR(ssh_gssapi_import_name(gssctxt, + authctxt->host))) { + ok = 1; /* Mechanism works */ + } else { + mech++; + } + } + + if (!ok) return 0; + + authctxt->methoddata=(void *)gssctxt; + + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + + packet_put_int(1); + + packet_put_int((gss_supported->elements[mech].length) + 2); + packet_put_char(SSH_GSS_OIDTYPE); + packet_put_char(gss_supported->elements[mech].length); + packet_put_raw(gss_supported->elements[mech].elements, + gss_supported->elements[mech].length); + + packet_send(); + + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); + + mech++; /* Move along to next candidate */ + + return 1; +} + +static OM_uint32 +process_gssapi_token(void *ctxt, gss_buffer_t recv_tok) +{ + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt = authctxt->methoddata; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc gssbuf, mic; + OM_uint32 status, ms, flags; + Buffer b; + + status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, + recv_tok, &send_tok, &flags); + + if (send_tok.length > 0) { + if (GSS_ERROR(status)) + packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); + else + packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); + + packet_put_string(send_tok.value, send_tok.length); + packet_send(); + gss_release_buffer(&ms, &send_tok); + } + + if (status == GSS_S_COMPLETE) { + /* send either complete or MIC, depending on mechanism */ + if (!(flags & GSS_C_INTEG_FLAG)) { + packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE); + packet_send(); + } else { + ssh_gssapi_buildmic(&b, authctxt->server_user, + authctxt->service, "gssapi-with-mic"); + + gssbuf.value = buffer_ptr(&b); + gssbuf.length = buffer_len(&b); + + status = ssh_gssapi_sign(gssctxt, &gssbuf, &mic); + + if (!GSS_ERROR(status)) { + packet_start(SSH2_MSG_USERAUTH_GSSAPI_MIC); + packet_put_string(mic.value, mic.length); + + packet_send(); + } + + buffer_free(&b); + gss_release_buffer(&ms, &mic); + } + } + + return status; +} + +void +input_gssapi_response(int type, u_int32_t plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; + int oidlen; + char *oidv; + + if (authctxt == NULL) + fatal("input_gssapi_response: no authentication context"); + gssctxt = authctxt->methoddata; + + /* Setup our OID */ + oidv = packet_get_string(&oidlen); + + if (oidlen <= 2 || + oidv[0] != SSH_GSS_OIDTYPE || + oidv[1] != oidlen - 2) { + xfree(oidv); + debug("Badly encoded mechanism OID received"); + userauth(authctxt, NULL); + return; + } + + if (!ssh_gssapi_check_oid(gssctxt, oidv + 2, oidlen - 2)) + fatal("Server returned different OID than expected"); + + packet_check_eom(); + + xfree(oidv); + + if (GSS_ERROR(process_gssapi_token(ctxt, GSS_C_NO_BUFFER))) { + /* Start again with next method on list */ + debug("Trying to start again"); + userauth(authctxt, NULL); + return; + } +} + +void +input_gssapi_token(int type, u_int32_t plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + gss_buffer_desc recv_tok; + OM_uint32 status; + u_int slen; + + if (authctxt == NULL) + fatal("input_gssapi_response: no authentication context"); + + recv_tok.value = packet_get_string(&slen); + recv_tok.length = slen; /* safe typecast */ + + packet_check_eom(); + + status = process_gssapi_token(ctxt, &recv_tok); + + xfree(recv_tok.value); + + if (GSS_ERROR(status)) { + /* Start again with the next method in the list */ + userauth(authctxt, NULL); + return; + } +} + +void +input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; + gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; + gss_buffer_desc recv_tok; + OM_uint32 status, ms; + u_int len; + + if (authctxt == NULL) + fatal("input_gssapi_response: no authentication context"); + gssctxt = authctxt->methoddata; + + recv_tok.value = packet_get_string(&len); + recv_tok.length = len; + + packet_check_eom(); + + /* Stick it into GSSAPI and see what it says */ + status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, + &recv_tok, &send_tok, NULL); + + xfree(recv_tok.value); + gss_release_buffer(&ms, &send_tok); + + /* Server will be returning a failed packet after this one */ +} + +void +input_gssapi_error(int type, u_int32_t plen, void *ctxt) +{ + OM_uint32 maj, min; + char *msg; + char *lang; + + maj=packet_get_int(); + min=packet_get_int(); + msg=packet_get_string(NULL); + lang=packet_get_string(NULL); + + packet_check_eom(); + + debug("Server GSSAPI Error:\n%s\n", msg); + xfree(msg); + xfree(lang); +} +#endif /* GSSAPI */ + +int +userauth_none(Authctxt *authctxt) +{ + /* initial userauth request */ + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_send(); + return 1; +} + +int +userauth_passwd(Authctxt *authctxt) +{ + static int attempt = 0; + char prompt[150]; + char *password; + + if (attempt++ >= options.number_of_password_prompts) + return 0; + + if (attempt != 1) + error("Permission denied, please try again."); + + snprintf(prompt, sizeof(prompt), "%.30s@%.128s's password: ", + authctxt->server_user, authctxt->host); + password = read_passphrase(prompt, 0); + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_char(0); + packet_put_cstring(password); + memset(password, 0, strlen(password)); + xfree(password); + packet_add_padding(64); + packet_send(); + + dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, + &input_userauth_passwd_changereq); + + return 1; +} +/* + * parse PASSWD_CHANGEREQ, prompt user and send SSH2_MSG_USERAUTH_REQUEST + */ +void +input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt) +{ + Authctxt *authctxt = ctxt; + char *info, *lang, *password = NULL, *retype = NULL; + char prompt[150]; + + debug2("input_userauth_passwd_changereq"); + + if (authctxt == NULL) + fatal("input_userauth_passwd_changereq: " + "no authentication context"); + + info = packet_get_string(NULL); + lang = packet_get_string(NULL); + if (strlen(info) > 0) + logit("%s", info); + xfree(info); + xfree(lang); + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_char(1); /* additional info */ + snprintf(prompt, sizeof(prompt), + "Enter %.30s@%.128s's old password: ", + authctxt->server_user, authctxt->host); + password = read_passphrase(prompt, 0); + packet_put_cstring(password); + memset(password, 0, strlen(password)); + xfree(password); + password = NULL; + while (password == NULL) { + snprintf(prompt, sizeof(prompt), + "Enter %.30s@%.128s's new password: ", + authctxt->server_user, authctxt->host); + password = read_passphrase(prompt, RP_ALLOW_EOF); + if (password == NULL) { + /* bail out */ + return; + } + snprintf(prompt, sizeof(prompt), + "Retype %.30s@%.128s's new password: ", + authctxt->server_user, authctxt->host); + retype = read_passphrase(prompt, 0); + if (strcmp(password, retype) != 0) { + memset(password, 0, strlen(password)); + xfree(password); + logit("Mismatch; try again, EOF to quit."); + password = NULL; + } + memset(retype, 0, strlen(retype)); + xfree(retype); + } + packet_put_cstring(password); + memset(password, 0, strlen(password)); + xfree(password); + packet_add_padding(64); + packet_send(); + + dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, + &input_userauth_passwd_changereq); +} + +static int +identity_sign(Identity *id, u_char **sigp, u_int *lenp, + u_char *data, u_int datalen) +{ + Key *prv; + int ret; + + /* the agent supports this key */ + if (id->ac) + return (ssh_agent_sign(id->ac, id->key, sigp, lenp, + data, datalen)); + /* + * we have already loaded the private key or + * the private key is stored in external hardware + */ + if (id->isprivate || (id->key->flags & KEY_FLAG_EXT)) + return (key_sign(id->key, sigp, lenp, data, datalen)); + /* load the private key from the file */ + if ((prv = load_identity_file(id->filename)) == NULL) + return (-1); + ret = key_sign(prv, sigp, lenp, data, datalen); + key_free(prv); + return (ret); +} + +static int +sign_and_send_pubkey(Authctxt *authctxt, Identity *id) +{ + Buffer b; + u_char *blob, *signature; + u_int bloblen, slen; + u_int skip = 0; + int ret = -1; + int have_sig = 1; + + debug3("sign_and_send_pubkey"); + + if (key_to_blob(id->key, &blob, &bloblen) == 0) { + /* we cannot handle this key */ + debug3("sign_and_send_pubkey: cannot handle key"); + return 0; + } + /* data to be signed */ + buffer_init(&b); + if (datafellows & SSH_OLD_SESSIONID) { + buffer_append(&b, session_id2, session_id2_len); + skip = session_id2_len; + } else { + buffer_put_string(&b, session_id2, session_id2_len); + skip = buffer_len(&b); + } + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(&b, authctxt->server_user); + buffer_put_cstring(&b, + datafellows & SSH_BUG_PKSERVICE ? + "ssh-userauth" : + authctxt->service); + if (datafellows & SSH_BUG_PKAUTH) { + buffer_put_char(&b, have_sig); + } else { + buffer_put_cstring(&b, authctxt->method->name); + buffer_put_char(&b, have_sig); + buffer_put_cstring(&b, key_ssh_name(id->key)); + } + buffer_put_string(&b, blob, bloblen); + + /* generate signature */ + ret = identity_sign(id, &signature, &slen, + buffer_ptr(&b), buffer_len(&b)); + if (ret == -1) { + xfree(blob); + buffer_free(&b); + return 0; + } +#ifdef DEBUG_PK + buffer_dump(&b); +#endif + if (datafellows & SSH_BUG_PKSERVICE) { + buffer_clear(&b); + buffer_append(&b, session_id2, session_id2_len); + skip = session_id2_len; + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(&b, authctxt->server_user); + buffer_put_cstring(&b, authctxt->service); + buffer_put_cstring(&b, authctxt->method->name); + buffer_put_char(&b, have_sig); + if (!(datafellows & SSH_BUG_PKAUTH)) + buffer_put_cstring(&b, key_ssh_name(id->key)); + buffer_put_string(&b, blob, bloblen); + } + xfree(blob); + + /* append signature */ + buffer_put_string(&b, signature, slen); + xfree(signature); + + /* skip session id and packet type */ + if (buffer_len(&b) < skip + 1) + fatal("userauth_pubkey: internal error"); + buffer_consume(&b, skip + 1); + + /* put remaining data from buffer into packet */ + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_raw(buffer_ptr(&b), buffer_len(&b)); + buffer_free(&b); + packet_send(); + + return 1; +} + +static int +send_pubkey_test(Authctxt *authctxt, Identity *id) +{ + u_char *blob; + u_int bloblen, have_sig = 0; + + debug3("send_pubkey_test"); + + if (key_to_blob(id->key, &blob, &bloblen) == 0) { + /* we cannot handle this key */ + debug3("send_pubkey_test: cannot handle key"); + return 0; + } + /* register callback for USERAUTH_PK_OK message */ + dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); + + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_char(have_sig); + if (!(datafellows & SSH_BUG_PKAUTH)) + packet_put_cstring(key_ssh_name(id->key)); + packet_put_string(blob, bloblen); + xfree(blob); + packet_send(); + return 1; +} + +static Key * +load_identity_file(char *filename) +{ + Key *private; + char prompt[300], *passphrase; + int quit, i; + struct stat st; + + if (stat(filename, &st) < 0) { + debug3("no such identity: %s", filename); + return NULL; + } + private = key_load_private_type(KEY_UNSPEC, filename, "", NULL); + if (private == NULL) { + if (options.batch_mode) + return NULL; + snprintf(prompt, sizeof prompt, + "Enter passphrase for key '%.100s': ", filename); + for (i = 0; i < options.number_of_password_prompts; i++) { + passphrase = read_passphrase(prompt, 0); + if (strcmp(passphrase, "") != 0) { + private = key_load_private_type(KEY_UNSPEC, filename, + passphrase, NULL); + quit = 0; + } else { + debug2("no passphrase given, try next key"); + quit = 1; + } + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + if (private != NULL || quit) + break; + debug2("bad passphrase given, try again..."); + } + } + return private; +} + +/* + * try keys in the following order: + * 1. agent keys that are found in the config file + * 2. other agent keys + * 3. keys that are only listed in the config file + */ +static void +pubkey_prepare(Authctxt *authctxt) +{ + Identity *id; + Idlist agent, files, *preferred; + Key *key; + AuthenticationConnection *ac; + char *comment; + int i, found; + + TAILQ_INIT(&agent); /* keys from the agent */ + TAILQ_INIT(&files); /* keys from the config file */ + preferred = &authctxt->keys; + TAILQ_INIT(preferred); /* preferred order of keys */ + + /* list of keys stored in the filesystem */ + for (i = 0; i < options.num_identity_files; i++) { + key = options.identity_keys[i]; + if (key && key->type == KEY_RSA1) + continue; + options.identity_keys[i] = NULL; + id = xmalloc(sizeof(*id)); + memset(id, 0, sizeof(*id)); + id->key = key; + id->filename = xstrdup(options.identity_files[i]); + TAILQ_INSERT_TAIL(&files, id, next); + } + /* list of keys supported by the agent */ + if ((ac = ssh_get_authentication_connection())) { + for (key = ssh_get_first_identity(ac, &comment, 2); + key != NULL; + key = ssh_get_next_identity(ac, &comment, 2)) { + found = 0; + TAILQ_FOREACH(id, &files, next) { + /* agent keys from the config file are preferred */ + if (key_equal(key, id->key)) { + key_free(key); + xfree(comment); + TAILQ_REMOVE(&files, id, next); + TAILQ_INSERT_TAIL(preferred, id, next); + id->ac = ac; + found = 1; + break; + } + } + if (!found && !options.identities_only) { + id = xmalloc(sizeof(*id)); + memset(id, 0, sizeof(*id)); + id->key = key; + id->filename = comment; + id->ac = ac; + TAILQ_INSERT_TAIL(&agent, id, next); + } + } + /* append remaining agent keys */ + for (id = TAILQ_FIRST(&agent); id; id = TAILQ_FIRST(&agent)) { + TAILQ_REMOVE(&agent, id, next); + TAILQ_INSERT_TAIL(preferred, id, next); + } + authctxt->agent = ac; + } + /* append remaining keys from the config file */ + for (id = TAILQ_FIRST(&files); id; id = TAILQ_FIRST(&files)) { + TAILQ_REMOVE(&files, id, next); + TAILQ_INSERT_TAIL(preferred, id, next); + } + TAILQ_FOREACH(id, preferred, next) { + debug2("key: %s (%p)", id->filename, id->key); + } +} + +static void +pubkey_cleanup(Authctxt *authctxt) +{ + Identity *id; + + if (authctxt->agent != NULL) + ssh_close_authentication_connection(authctxt->agent); + for (id = TAILQ_FIRST(&authctxt->keys); id; + id = TAILQ_FIRST(&authctxt->keys)) { + TAILQ_REMOVE(&authctxt->keys, id, next); + if (id->key) + key_free(id->key); + if (id->filename) + xfree(id->filename); + xfree(id); + } +} + +int +userauth_pubkey(Authctxt *authctxt) +{ + Identity *id; + int sent = 0; + + while ((id = TAILQ_FIRST(&authctxt->keys))) { + if (id->tried++) + return (0); + /* move key to the end of the queue */ + TAILQ_REMOVE(&authctxt->keys, id, next); + TAILQ_INSERT_TAIL(&authctxt->keys, id, next); + /* + * send a test message if we have the public key. for + * encrypted keys we cannot do this and have to load the + * private key instead + */ + if (id->key && id->key->type != KEY_RSA1) { + debug("Offering public key: %s", id->filename); + sent = send_pubkey_test(authctxt, id); + } else if (id->key == NULL) { + debug("Trying private key: %s", id->filename); + id->key = load_identity_file(id->filename); + if (id->key != NULL) { + id->isprivate = 1; + sent = sign_and_send_pubkey(authctxt, id); + key_free(id->key); + id->key = NULL; + } + } + if (sent) + return (sent); + } + return (0); +} + +/* + * Send userauth request message specifying keyboard-interactive method. + */ +int +userauth_kbdint(Authctxt *authctxt) +{ + static int attempt = 0; + + if (attempt++ >= options.number_of_password_prompts) + return 0; + /* disable if no SSH2_MSG_USERAUTH_INFO_REQUEST has been seen */ + if (attempt > 1 && !authctxt->info_req_seen) { + debug3("userauth_kbdint: disable: no info_req_seen"); + dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, NULL); + return 0; + } + + debug2("userauth_kbdint"); + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_cstring(""); /* lang */ + packet_put_cstring(options.kbd_interactive_devices ? + options.kbd_interactive_devices : ""); + packet_send(); + + dispatch_set(SSH2_MSG_USERAUTH_INFO_REQUEST, &input_userauth_info_req); + return 1; +} + +/* + * parse INFO_REQUEST, prompt user and send INFO_RESPONSE + */ +void +input_userauth_info_req(int type, u_int32_t seq, void *ctxt) +{ + Authctxt *authctxt = ctxt; + char *name, *inst, *lang, *prompt, *response; + u_int num_prompts, i; + int echo = 0; + + debug2("input_userauth_info_req"); + + if (authctxt == NULL) + fatal("input_userauth_info_req: no authentication context"); + + authctxt->info_req_seen = 1; + + name = packet_get_string(NULL); + inst = packet_get_string(NULL); + lang = packet_get_string(NULL); + if (strlen(name) > 0) + logit("%s", name); + if (strlen(inst) > 0) + logit("%s", inst); + xfree(name); + xfree(inst); + xfree(lang); + + num_prompts = packet_get_int(); + /* + * Begin to build info response packet based on prompts requested. + * We commit to providing the correct number of responses, so if + * further on we run into a problem that prevents this, we have to + * be sure and clean this up and send a correct error response. + */ + packet_start(SSH2_MSG_USERAUTH_INFO_RESPONSE); + packet_put_int(num_prompts); + + debug2("input_userauth_info_req: num_prompts %d", num_prompts); + for (i = 0; i < num_prompts; i++) { + prompt = packet_get_string(NULL); + echo = packet_get_char(); + + response = read_passphrase(prompt, echo ? RP_ECHO : 0); + + packet_put_cstring(response); + memset(response, 0, strlen(response)); + xfree(response); + xfree(prompt); + } + packet_check_eom(); /* done with parsing incoming message. */ + + packet_add_padding(64); + packet_send(); +} + +static int +ssh_keysign(Key *key, u_char **sigp, u_int *lenp, + u_char *data, u_int datalen) +{ + Buffer b; + struct stat st; + pid_t pid; + int to[2], from[2], status, version = 2; + + debug2("ssh_keysign called"); + + if (stat(_PATH_SSH_KEY_SIGN, &st) < 0) { + error("ssh_keysign: no installed: %s", strerror(errno)); + return -1; + } + if (fflush(stdout) != 0) + error("ssh_keysign: fflush: %s", strerror(errno)); + if (pipe(to) < 0) { + error("ssh_keysign: pipe: %s", strerror(errno)); + return -1; + } + if (pipe(from) < 0) { + error("ssh_keysign: pipe: %s", strerror(errno)); + return -1; + } + if ((pid = fork()) < 0) { + error("ssh_keysign: fork: %s", strerror(errno)); + return -1; + } + if (pid == 0) { + seteuid(getuid()); + setuid(getuid()); + close(from[0]); + if (dup2(from[1], STDOUT_FILENO) < 0) + fatal("ssh_keysign: dup2: %s", strerror(errno)); + close(to[1]); + if (dup2(to[0], STDIN_FILENO) < 0) + fatal("ssh_keysign: dup2: %s", strerror(errno)); + close(from[1]); + close(to[0]); + execl(_PATH_SSH_KEY_SIGN, _PATH_SSH_KEY_SIGN, (char *) 0); + fatal("ssh_keysign: exec(%s): %s", _PATH_SSH_KEY_SIGN, + strerror(errno)); + } + close(from[1]); + close(to[0]); + + buffer_init(&b); + buffer_put_int(&b, packet_get_connection_in()); /* send # of socket */ + buffer_put_string(&b, data, datalen); + if (ssh_msg_send(to[1], version, &b) == -1) + fatal("ssh_keysign: couldn't send request"); + + if (ssh_msg_recv(from[0], &b) < 0) { + error("ssh_keysign: no reply"); + buffer_free(&b); + return -1; + } + close(from[0]); + close(to[1]); + + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + break; + + if (buffer_get_char(&b) != version) { + error("ssh_keysign: bad version"); + buffer_free(&b); + return -1; + } + *sigp = buffer_get_string(&b, lenp); + buffer_free(&b); + + return 0; +} + +int +userauth_hostbased(Authctxt *authctxt) +{ + Key *private = NULL; + Sensitive *sensitive = authctxt->sensitive; + Buffer b; + u_char *signature, *blob; + char *chost, *pkalg, *p; + const char *service; + u_int blen, slen; + int ok, i, len, found = 0; + + /* check for a useful key */ + for (i = 0; i < sensitive->nkeys; i++) { + private = sensitive->keys[i]; + if (private && private->type != KEY_RSA1) { + found = 1; + /* we take and free the key */ + sensitive->keys[i] = NULL; + break; + } + } + if (!found) { + debug("No more client hostkeys for hostbased authentication."); + return 0; + } + if (key_to_blob(private, &blob, &blen) == 0) { + key_free(private); + return 0; + } + /* figure out a name for the client host */ + p = get_local_name(packet_get_connection_in()); + if (p == NULL) { + error("userauth_hostbased: cannot get local ipaddr/name"); + key_free(private); + return 0; + } + len = strlen(p) + 2; + chost = xmalloc(len); + strlcpy(chost, p, len); + strlcat(chost, ".", len); + debug2("userauth_hostbased: chost %s", chost); + xfree(p); + + service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : + authctxt->service; + pkalg = xstrdup(key_ssh_name(private)); + buffer_init(&b); + /* construct data */ + buffer_put_string(&b, session_id2, session_id2_len); + buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); + buffer_put_cstring(&b, authctxt->server_user); + buffer_put_cstring(&b, service); + buffer_put_cstring(&b, authctxt->method->name); + buffer_put_cstring(&b, pkalg); + buffer_put_string(&b, blob, blen); + buffer_put_cstring(&b, chost); + buffer_put_cstring(&b, authctxt->local_user); +#ifdef DEBUG_PK + buffer_dump(&b); +#endif + if (sensitive->external_keysign) + ok = ssh_keysign(private, &signature, &slen, + buffer_ptr(&b), buffer_len(&b)); + else + ok = key_sign(private, &signature, &slen, + buffer_ptr(&b), buffer_len(&b)); + key_free(private); + buffer_free(&b); + if (ok != 0) { + error("key_sign failed"); + xfree(chost); + xfree(pkalg); + return 0; + } + packet_start(SSH2_MSG_USERAUTH_REQUEST); + packet_put_cstring(authctxt->server_user); + packet_put_cstring(authctxt->service); + packet_put_cstring(authctxt->method->name); + packet_put_cstring(pkalg); + packet_put_string(blob, blen); + packet_put_cstring(chost); + packet_put_cstring(authctxt->local_user); + packet_put_string(signature, slen); + memset(signature, 's', slen); + xfree(signature); + xfree(chost); + xfree(pkalg); + + packet_send(); + return 1; +} + +/* find auth method */ + +/* + * given auth method name, if configurable options permit this method fill + * in auth_ident field and return true, otherwise return false. + */ +static int +authmethod_is_enabled(Authmethod *method) +{ + if (method == NULL) + return 0; + /* return false if options indicate this method is disabled */ + if (method->enabled == NULL || *method->enabled == 0) + return 0; + /* return false if batch mode is enabled but method needs interactive mode */ + if (method->batch_flag != NULL && *method->batch_flag != 0) + return 0; + return 1; +} + +static Authmethod * +authmethod_lookup(const char *name) +{ + Authmethod *method = NULL; + if (name != NULL) + for (method = authmethods; method->name != NULL; method++) + if (strcmp(name, method->name) == 0) + return method; + debug2("Unrecognized authentication method name: %s", name ? name : "NULL"); + return NULL; +} + +/* XXX internal state */ +static Authmethod *current = NULL; +static char *supported = NULL; +static char *preferred = NULL; + +/* + * Given the authentication method list sent by the server, return the + * next method we should try. If the server initially sends a nil list, + * use a built-in default list. + */ +static Authmethod * +authmethod_get(char *authlist) +{ + char *name = NULL; + u_int next; + + /* Use a suitable default if we're passed a nil list. */ + if (authlist == NULL || strlen(authlist) == 0) + authlist = options.preferred_authentications; + + if (supported == NULL || strcmp(authlist, supported) != 0) { + debug3("start over, passed a different list %s", authlist); + if (supported != NULL) + xfree(supported); + supported = xstrdup(authlist); + preferred = options.preferred_authentications; + debug3("preferred %s", preferred); + current = NULL; + } else if (current != NULL && authmethod_is_enabled(current)) + return current; + + for (;;) { + if ((name = match_list(preferred, supported, &next)) == NULL) { + debug("No more authentication methods to try."); + current = NULL; + return NULL; + } + preferred += next; + debug3("authmethod_lookup %s", name); + debug3("remaining preferred: %s", preferred); + if ((current = authmethod_lookup(name)) != NULL && + authmethod_is_enabled(current)) { + debug3("authmethod_is_enabled %s", name); + debug("Next authentication method: %s", name); + return current; + } + } +} + +static char * +authmethods_get(void) +{ + Authmethod *method = NULL; + Buffer b; + char *list; + + buffer_init(&b); + for (method = authmethods; method->name != NULL; method++) { + if (authmethod_is_enabled(method)) { + if (buffer_len(&b) > 0) + buffer_append(&b, ",", 1); + buffer_append(&b, method->name, strlen(method->name)); + } + } + buffer_append(&b, "\0", 1); + list = xstrdup(buffer_ptr(&b)); + buffer_free(&b); + return list; +} diff --git a/crypto/openssh-3.9p1/sshd.8 b/crypto/openssh-3.9p1/sshd.8 new file mode 100644 index 0000000000..233b000376 --- /dev/null +++ b/crypto/openssh-3.9p1/sshd.8 @@ -0,0 +1,838 @@ +.\" -*- nroff -*- +.\" +.\" Author: Tatu Ylonen +.\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +.\" All rights reserved +.\" +.\" 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". +.\" +.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. +.\" Copyright (c) 1999 Aaron Campbell. All rights reserved. +.\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $OpenBSD: sshd.8,v 1.201 2004/05/02 11:54:31 dtucker Exp $ +.Dd September 25, 1999 +.Dt SSHD 8 +.Os +.Sh NAME +.Nm sshd +.Nd OpenSSH SSH daemon +.Sh SYNOPSIS +.Nm sshd +.Bk -words +.Op Fl 46Ddeiqt +.Op Fl b Ar bits +.Op Fl f Ar config_file +.Op Fl g Ar login_grace_time +.Op Fl h Ar host_key_file +.Op Fl k Ar key_gen_time +.Op Fl o Ar option +.Op Fl p Ar port +.Op Fl u Ar len +.Ek +.Sh DESCRIPTION +.Nm +(SSH Daemon) is the daemon program for +.Xr ssh 1 . +Together these programs replace rlogin and rsh, 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. +.Pp +.Nm +is the daemon that listens for connections from clients. +It is normally started at boot from +.Pa /etc/rc . +It forks a new +daemon for each incoming connection. +The forked daemons handle +key exchange, encryption, authentication, command execution, +and data exchange. +This implementation of +.Nm +supports both SSH protocol version 1 and 2 simultaneously. +.Nm +works as follows: +.Ss SSH protocol version 1 +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. +.Pp +Whenever a client connects, the daemon responds with its public +host and server keys. +The client compares the +RSA 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 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 Blowfish or 3DES, with 3DES +being used by default. +The client selects the encryption algorithm +to use from those offered by the server. +.Pp +Next, the server and the client enter an authentication dialog. +The client tries to authenticate itself using +.Em .rhosts +authentication, +.Em .rhosts +authentication combined with RSA host +authentication, RSA challenge-response authentication, or password +based authentication. +.Pp +Regardless of the authentication type, the account is checked to +ensure that it is accessible. An account is not accessible if it is +locked, listed in +.Cm DenyUsers +or its group is listed in +.Cm DenyGroups +\&. The definition of a locked account is system dependant. Some platforms +have their own account database (eg AIX) and some modify the passwd field ( +.Ql \&*LK\&* +on Solaris, +.Ql \&* +on HP-UX, containing +.Ql Nologin +on Tru64 and a leading +.Ql \&!! +on Linux). If there is a requirement to disable password authentication +for the account while allowing still public-key, then the passwd field +should be set to something other than these values (eg +.Ql NP +or +.Ql \&*NP\&* +). +.Pp +.Em 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 +.Nm rshd , +.Nm rlogind , +and +.Nm rexecd +are disabled (thus completely disabling +.Xr rlogin +and +.Xr rsh +into the machine). +.Ss SSH protocol version 2 +Version 2 works similarly: +Each host has a host-specific key (RSA or DSA) used to identify the host. +However, when the daemon starts, it does not generate a server key. +Forward security is provided through a Diffie-Hellman key agreement. +This key agreement results in a shared session key. +.Pp +The rest of the session is encrypted using a symmetric cipher, currently +128-bit AES, Blowfish, 3DES, CAST128, Arcfour, 192-bit AES, or 256-bit AES. +The client selects the encryption algorithm +to use from those offered by the server. +Additionally, session integrity is provided +through a cryptographic message authentication code +(hmac-sha1 or hmac-md5). +.Pp +Protocol version 2 provides a public key based +user (PubkeyAuthentication) or +client host (HostbasedAuthentication) authentication method, +conventional password authentication and challenge response based methods. +.Ss Command execution and data forwarding +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. +.Pp +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. +.Pp +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. +.Pp +.Nm +can be configured using command-line options or a configuration file +(by default +.Xr sshd_config 5 ) . +Command-line options override values specified in the +configuration file. +.Pp +.Nm +rereads its configuration file when it receives a hangup signal, +.Dv SIGHUP , +by executing itself with the name and options it was started with, e.g., +.Pa /usr/sbin/sshd . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 4 +Forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +Forces +.Nm +to use IPv6 addresses only. +.It Fl b Ar bits +Specifies the number of bits in the ephemeral protocol version 1 +server key (default 768). +.It Fl D +When this option is specified, +.Nm +will not detach and does not become a daemon. +This allows easy monitoring of +.Nm sshd . +.It Fl 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. +Multiple +.Fl d +options increase the debugging level. +Maximum is 3. +.It Fl e +When this option is specified, +.Nm +will send the output to the standard error instead of the system log. +.It Fl f Ar configuration_file +Specifies the name of the configuration file. +The default is +.Pa /etc/ssh/sshd_config . +.Nm +refuses to start if there is no configuration file. +.It Fl g Ar login_grace_time +Gives the grace time for clients to authenticate themselves (default +120 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. +.It Fl h Ar host_key_file +Specifies a file from which a host key is read. +This option must be given if +.Nm +is not run as root (as the normal +host key files are normally not readable by anyone but root). +The default is +.Pa /etc/ssh/ssh_host_key +for protocol version 1, and +.Pa /etc/ssh/ssh_host_rsa_key +and +.Pa /etc/ssh/ssh_host_dsa_key +for protocol version 2. +It is possible to have multiple host key files for +the different protocol versions and host key algorithms. +.It Fl i +Specifies that +.Nm +is being run from +.Xr inetd 8 . +.Nm +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 +.Nm +from inetd may +be feasible. +.It Fl k Ar key_gen_time +Specifies how often the ephemeral protocol version 1 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. +.It Fl o Ar option +Can be used to give options in the format used in the configuration file. +This is useful for specifying options for which there is no separate +command-line flag. +For full details of the options, and their values, see +.Xr sshd_config 5 . +.It Fl p Ar port +Specifies the port on which the server listens for connections +(default 22). +Multiple port options are permitted. +Ports specified in the configuration file are ignored when a +command-line port is specified. +.It Fl q +Quiet mode. +Nothing is sent to the system log. +Normally the beginning, +authentication, and termination of each connection is logged. +.It Fl t +Test mode. +Only check the validity of the configuration file and sanity of the keys. +This is useful for updating +.Nm +reliably as configuration options may change. +.It Fl u Ar len +This option is used to specify the size of the field +in the +.Li utmp +structure that holds the remote host name. +If the resolved host name is longer than +.Ar len , +the dotted decimal value will be used instead. +This allows hosts with very long host names that +overflow this field to still be uniquely identified. +Specifying +.Fl u0 +indicates that only dotted decimal addresses +should be put into the +.Pa utmp +file. +.Fl u0 +may also be used to prevent +.Nm +from making DNS requests unless the authentication +mechanism or configuration requires it. +Authentication mechanisms that may require DNS include +.Cm RhostsRSAAuthentication , +.Cm HostbasedAuthentication +and using a +.Cm from="pattern-list" +option in a key file. +Configuration options that require DNS include using a +USER@HOST pattern in +.Cm AllowUsers +or +.Cm DenyUsers . +.El +.Sh CONFIGURATION FILE +.Nm +reads configuration data from +.Pa /etc/ssh/sshd_config +(or the file specified with +.Fl f +on the command line). +The file format and configuration options are described in +.Xr sshd_config 5 . +.Sh LOGIN PROCESS +When a user successfully logs in, +.Nm +does the following: +.Bl -enum -offset indent +.It +If the login is on a tty, and no command has been specified, +prints last login time and +.Pa /etc/motd +(unless prevented in the configuration file or by +.Pa $HOME/.hushlogin ; +see the +.Sx FILES +section). +.It +If the login is on a tty, records login time. +.It +Checks +.Pa /etc/nologin ; +if it exists, prints contents and quits +(unless root). +.It +Changes to run with normal user privileges. +.It +Sets up basic environment. +.It +Reads the file +.Pa $HOME/.ssh/environment , +if it exists, and users are allowed to change their environment. +See the +.Cm PermitUserEnvironment +option in +.Xr sshd_config 5 . +.It +Changes to user's home directory. +.It +If +.Pa $HOME/.ssh/rc +exists, runs it; else if +.Pa /etc/ssh/sshrc +exists, runs +it; otherwise runs xauth. +The +.Dq rc +files are given the X11 +authentication protocol and cookie in standard input. +.It +Runs user's shell or command. +.El +.Sh AUTHORIZED_KEYS FILE FORMAT +.Pa $HOME/.ssh/authorized_keys +is the default file that lists the public keys that are +permitted for RSA authentication in protocol version 1 +and for public key authentication (PubkeyAuthentication) +in protocol version 2. +.Cm AuthorizedKeysFile +may be used to specify an alternative file. +.Pp +Each line of the file contains one +key (empty lines and lines starting with a +.Ql # +are ignored as +comments). +Each RSA public key consists of the following fields, separated by +spaces: options, bits, exponent, modulus, comment. +Each protocol version 2 public key consists of: +options, keytype, base64 encoded key, comment. +The options field +is optional; its presence is determined by whether the line starts +with a number or not (the options field never starts with a number). +The bits, exponent, modulus and comment fields give the RSA key for +protocol version 1; the +comment field is not used for anything (but may be convenient for the +user to identify the key). +For protocol version 2 the keytype is +.Dq ssh-dss +or +.Dq ssh-rsa . +.Pp +Note that lines in this file are usually several hundred bytes long +(because of the size of the public key encoding). +You don't want to type them in; instead, copy the +.Pa identity.pub , +.Pa id_dsa.pub +or the +.Pa id_rsa.pub +file and edit it. +.Pp +.Nm +enforces a minimum RSA key modulus size for protocol 1 +and protocol 2 keys of 768 bits. +.Pp +The options (if present) consist of comma-separated option +specifications. +No spaces are permitted, except within double quotes. +The following option specifications are supported (note +that option keywords are case-insensitive): +.Bl -tag -width Ds +.It Cm from="pattern-list" +Specifies that in addition to public key authentication, the canonical name +of the remote host must be present in the comma-separated list of +patterns +.Pf ( Ql \&* +and +.Ql \&? +serve as wildcards). +The list may also contain +patterns negated by prefixing them with +.Ql \&! ; +if the canonical host name matches a negated pattern, the key is not accepted. +The purpose +of this option is to optionally increase security: public key 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). +.It Cm command="command" +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 client requests a pty; +otherwise it is run without a tty. +If an 8-bit clean channel is required, +one must not request a pty or should specify +.Cm no-pty . +A quote may be included in the command by quoting it with a backslash. +This option might be useful +to restrict certain public keys to perform just a specific operation. +An example might be a key that permits remote backups but nothing else. +Note that the client may specify TCP/IP and/or X11 +forwarding unless they are explicitly prohibited. +Note that this option applies to shell, command or subsystem execution. +.It Cm environment="NAME=value" +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. +Environment processing is disabled by default and is +controlled via the +.Cm PermitUserEnvironment +option. +This option is automatically disabled if +.Cm UseLogin +is enabled. +.It Cm 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 +.Cm command +option. +.It Cm no-X11-forwarding +Forbids X11 forwarding when this key is used for authentication. +Any X11 forward requests by the client will return an error. +.It Cm no-agent-forwarding +Forbids authentication agent forwarding when this key is used for +authentication. +.It Cm no-pty +Prevents tty allocation (a request to allocate a pty will fail). +.It Cm permitopen="host:port" +Limit local +.Li ``ssh -L'' +port forwarding such that it may only connect to the specified host and +port. +IPv6 addresses can be specified with an alternative syntax: +.Ar host Ns / Ns Ar port . +Multiple +.Cm permitopen +options may be applied separated by commas. +No pattern matching is performed on the specified hostnames, +they must be literal domains or addresses. +.El +.Ss Examples +1024 33 12121...312314325 ylo@foo.bar +.Pp +from="*.niksula.hut.fi,!pc.niksula.hut.fi" 1024 35 23...2334 ylo@niksula +.Pp +command="dump /home",no-pty,no-port-forwarding 1024 33 23...2323 backup.hut.fi +.Pp +permitopen="10.2.1.55:80",permitopen="10.2.1.56:25" 1024 33 23...2323 +.Sh SSH_KNOWN_HOSTS FILE FORMAT +The +.Pa /etc/ssh/ssh_known_hosts +and +.Pa $HOME/.ssh/known_hosts +files contain host public keys for all known hosts. +The global file should +be prepared by the administrator (optional), and the per-user file is +maintained automatically: whenever the user connects from an unknown host +its key is added to the per-user file. +.Pp +Each line in these files contains the following fields: hostnames, +bits, exponent, modulus, comment. +The fields are separated by spaces. +.Pp +Hostnames is a comma-separated list of patterns +.Pf ( Ql \&* +and +.Ql \&? +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 +.Ql \&! +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. +.Pp +Bits, exponent, and modulus are taken directly from the RSA host key; they +can be obtained, e.g., from +.Pa /etc/ssh/ssh_host_key.pub . +The optional comment field continues to the end of the line, and is not used. +.Pp +Lines starting with +.Ql # +and empty lines are ignored as comments. +.Pp +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. +.Pp +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 +or by taking +.Pa /etc/ssh/ssh_host_key.pub +and adding the host names at the front. +.Ss Examples +.Bd -literal +closenet,...,130.233.208.41 1024 37 159...93 closenet.hut.fi +cvs.openbsd.org,199.185.137.3 ssh-rsa AAAA1234.....= +.Ed +.Sh FILES +.Bl -tag -width Ds +.It Pa /etc/ssh/sshd_config +Contains configuration data for +.Nm sshd . +The file format and configuration options are described in +.Xr sshd_config 5 . +.It Pa /etc/ssh/ssh_host_key, /etc/ssh/ssh_host_dsa_key, /etc/ssh/ssh_host_rsa_key +These three files contain the private parts of the host keys. +These files should only be owned by root, readable only by root, and not +accessible to others. +Note that +.Nm +does not start if this file is group/world-accessible. +.It Pa /etc/ssh/ssh_host_key.pub, /etc/ssh/ssh_host_dsa_key.pub, /etc/ssh/ssh_host_rsa_key.pub +These three files contain the public parts of the host keys. +These files should be world-readable but writable only by +root. +Their contents should match the respective private parts. +These files are not +really used for anything; they are provided for the convenience of +the user so their contents can be copied to known hosts files. +These files are created using +.Xr ssh-keygen 1 . +.It Pa /etc/moduli +Contains Diffie-Hellman groups used for the "Diffie-Hellman Group Exchange". +The file format is described in +.Xr moduli 5 . +.It Pa /var/empty +.Xr chroot 2 +directory used by +.Nm +during privilege separation in the pre-authentication phase. +The directory should not contain any files and must be owned by root +and not group or world-writable. +.It Pa /var/run/sshd.pid +Contains the process ID of the +.Nm +listening for connections (if there are several daemons running +concurrently for different ports, this contains the process ID of the one +started last). +The content of this file is not sensitive; it can be world-readable. +.It Pa $HOME/.ssh/authorized_keys +Lists the public keys (RSA or DSA) 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. +Users will place the contents of their +.Pa identity.pub , +.Pa id_dsa.pub +and/or +.Pa id_rsa.pub +files into this file, as described in +.Xr ssh-keygen 1 . +.It Pa "/etc/ssh/ssh_known_hosts", "$HOME/.ssh/known_hosts" +These files are consulted when using rhosts with RSA host +authentication or protocol version 2 hostbased 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 it is connecting to the correct remote host. +These files should be writable only by root/the owner. +.Pa /etc/ssh/ssh_known_hosts +should be world-readable, and +.Pa $HOME/.ssh/known_hosts +can, but need not be, world-readable. +.It Pa /etc/nologin +If this file exists, +.Nm +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. +.It Pa /etc/hosts.allow, /etc/hosts.deny +Access controls that should be enforced by tcp-wrappers are defined here. +Further details are described in +.Xr hosts_access 5 . +.It Pa $HOME/.rhosts +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 a password. +The same file is used by rlogind and rshd. +The file must +be writable only by the user; it is recommended that it not be +accessible by others. +.Pp +It 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. +.It Pa $HOME/.shosts +For ssh, +this file is exactly the same as for +.Pa .rhosts . +However, this file is +not used by rlogin and rshd, so using this permits access using SSH only. +.It Pa /etc/hosts.equiv +This file is used during +.Em rhosts +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 +.Em any +user on this machine (except root). +Additionally, the syntax +.Dq +@group +can be used to specify netgroups. +Negated entries start with +.Ql \&- . +.Pp +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. +.Pp +.Sy "Warning: It is almost never a good idea to use user names in" +.Pa hosts.equiv . +Beware that it really means that the named user(s) can log in as +.Em anybody , +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. +.Pp +Note that this warning also applies to rsh/rlogin. +.It Pa /etc/shosts.equiv +This is processed exactly as +.Pa /etc/hosts.equiv . +However, this file may be useful in environments that want to run both +rsh/rlogin and ssh. +.It Pa $HOME/.ssh/environment +This file is read into the environment at login (if it exists). +It can only contain empty lines, comment lines (that start with +.Ql # ) , +and assignment lines of the form name=value. +The file should be writable +only by the user; it need not be readable by anyone else. +Environment processing is disabled by default and is +controlled via the +.Cm PermitUserEnvironment +option. +.It Pa $HOME/.ssh/rc +If this file exists, it is run with +.Pa /bin/sh +after reading the +environment files but before starting the user's shell or command. +It must not produce any output on stdout; stderr must be used +instead. +If X11 forwarding is in use, it will receive the "proto cookie" pair in +its standard input (and +.Ev DISPLAY +in its environment). +The script must call +.Xr xauth 1 +because +.Nm +will not run xauth automatically to add X11 cookies. +.Pp +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. +.Pp +This file will probably contain some initialization code followed by +something similar to: +.Bd -literal +if read proto cookie && [ -n "$DISPLAY" ]; then + if [ `echo $DISPLAY | cut -c1-10` = 'localhost:' ]; then + # X11UseLocalhost=yes + echo add unix:`echo $DISPLAY | + cut -c11-` $proto $cookie + else + # X11UseLocalhost=no + echo add $DISPLAY $proto $cookie + fi | xauth -q - +fi +.Ed +.Pp +If this file does not exist, +.Pa /etc/ssh/sshrc +is run, and if that +does not exist either, xauth is used to add the cookie. +.Pp +This file should be writable only by the user, and need not be +readable by anyone else. +.It Pa /etc/ssh/sshrc +Like +.Pa $HOME/.ssh/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. +.El +.Sh SEE ALSO +.Xr scp 1 , +.Xr sftp 1 , +.Xr ssh 1 , +.Xr ssh-add 1 , +.Xr ssh-agent 1 , +.Xr ssh-keygen 1 , +.Xr chroot 2 , +.Xr hosts_access 5 , +.Xr login.conf 5 , +.Xr moduli 5 , +.Xr sshd_config 5 , +.Xr inetd 8 , +.Xr sftp-server 8 +.Rs +.%A T. Ylonen +.%A T. Kivinen +.%A M. Saarinen +.%A T. Rinne +.%A S. Lehtinen +.%T "SSH Protocol Architecture" +.%N draft-ietf-secsh-architecture-12.txt +.%D January 2002 +.%O work in progress material +.Re +.Rs +.%A M. Friedl +.%A N. Provos +.%A W. A. Simpson +.%T "Diffie-Hellman Group Exchange for the SSH Transport Layer Protocol" +.%N draft-ietf-secsh-dh-group-exchange-02.txt +.%D January 2002 +.%O work in progress material +.Re +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. +Niels Provos and Markus Friedl contributed support +for privilege separation. diff --git a/crypto/openssh-3.9p1/sshd.c b/crypto/openssh-3.9p1/sshd.c new file mode 100644 index 0000000000..60f63ef7b7 --- /dev/null +++ b/crypto/openssh-3.9p1/sshd.c @@ -0,0 +1,2021 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * 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. + * + * 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". + * + * SSH2 implementation: + * Privilege Separation: + * + * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. + * Copyright (c) 2002 Niels Provos. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: sshd.c,v 1.301 2004/08/11 11:50:09 dtucker Exp $"); + +#include +#include +#include +#include +#ifdef HAVE_SECUREWARE +#include +#include +#endif + +#include "ssh.h" +#include "ssh1.h" +#include "ssh2.h" +#include "xmalloc.h" +#include "rsa.h" +#include "sshpty.h" +#include "packet.h" +#include "log.h" +#include "servconf.h" +#include "uidswap.h" +#include "compat.h" +#include "buffer.h" +#include "bufaux.h" +#include "cipher.h" +#include "kex.h" +#include "key.h" +#include "dh.h" +#include "myproposal.h" +#include "authfile.h" +#include "pathnames.h" +#include "atomicio.h" +#include "canohost.h" +#include "auth.h" +#include "misc.h" +#include "msg.h" +#include "dispatch.h" +#include "channels.h" +#include "session.h" +#include "monitor_mm.h" +#include "monitor.h" +#include "monitor_wrap.h" +#include "monitor_fdpass.h" + +#ifdef LIBWRAP +#include +#include +int allow_severity = LOG_INFO; +int deny_severity = LOG_WARNING; +#endif /* LIBWRAP */ + +#ifndef O_NOCTTY +#define O_NOCTTY 0 +#endif + +/* Re-exec fds */ +#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) +#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) +#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) +#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4) + +extern char *__progname; + +/* Server configuration options. */ +ServerOptions options; + +/* Name of the server configuration file. */ +char *config_file_name = _PATH_SERVER_CONFIG_FILE; + +/* + * Flag indicating whether IPv4 or IPv6. This can be set on the command line. + * Default value is AF_UNSPEC means both IPv4 and IPv6. + */ +int IPv4or6 = AF_UNSPEC; + +/* + * 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 should only test the configuration and keys. */ +int test_flag = 0; + +/* Flag indicating that the daemon is being started from inetd. */ +int inetd_flag = 0; + +/* Flag indicating that sshd should not detach and become a daemon. */ +int no_daemon_flag = 0; + +/* debug goes to stderr unless inetd_flag is set */ +int log_stderr = 0; + +/* Saved arguments to main(). */ +char **saved_argv; +int saved_argc; + +/* re-exec */ +int rexeced_flag = 0; +int rexec_flag = 1; +int rexec_argc = 0; +char **rexec_argv; + +/* + * The sockets that the server is listening; this is used in the SIGHUP + * signal handler. + */ +#define MAX_LISTEN_SOCKS 16 +int listen_socks[MAX_LISTEN_SOCKS]; +int num_listen_socks = 0; + +/* + * the client's version string, passed by sshd2 in compat mode. if != NULL, + * sshd will skip the version-number exchange + */ +char *client_version_string = NULL; +char *server_version_string = NULL; + +/* for rekeying XXX fixme */ +Kex *xxx_kex; + +/* + * 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 BIGNUMs, 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 { + Key *server_key; /* ephemeral server key */ + Key *ssh1_host_key; /* ssh1 host key */ + Key **host_keys; /* all private host keys */ + int have_ssh1_key; + int have_ssh2_key; + u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; +} sensitive_data; + +/* + * Flag indicating whether the RSA server key needs to be regenerated. + * Is set in the SIGALRM handler and cleared when the key is regenerated. + */ +static volatile sig_atomic_t key_do_regen = 0; + +/* This is set to true when a signal is received. */ +static volatile sig_atomic_t received_sighup = 0; +static volatile sig_atomic_t received_sigterm = 0; + +/* session identifier, used by RSA-auth */ +u_char session_id[16]; + +/* same for ssh2 */ +u_char *session_id2 = NULL; +u_int session_id2_len = 0; + +/* record remote hostname or ip */ +u_int utmp_len = MAXHOSTNAMELEN; + +/* options.max_startup sized array of fd ints */ +int *startup_pipes = NULL; +int startup_pipe; /* in child */ + +/* variables used for privilege separation */ +int use_privsep; +struct monitor *pmonitor = NULL; + +/* global authentication context */ +Authctxt *the_authctxt = NULL; + +/* message to be displayed after login */ +Buffer loginmsg; + +/* Prototypes for various functions defined later in this file. */ +void destroy_sensitive_data(void); +void demote_sensitive_data(void); + +static void do_ssh1_kex(void); +static void do_ssh2_kex(void); + +/* + * Close all listening sockets + */ +static void +close_listen_socks(void) +{ + int i; + + for (i = 0; i < num_listen_socks; i++) + close(listen_socks[i]); + num_listen_socks = -1; +} + +static void +close_startup_pipes(void) +{ + int i; + + if (startup_pipes) + for (i = 0; i < options.max_startups; i++) + if (startup_pipes[i] != -1) + close(startup_pipes[i]); +} + +/* + * 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). + */ +static void +sighup_handler(int sig) +{ + int save_errno = errno; + + received_sighup = 1; + signal(SIGHUP, sighup_handler); + errno = save_errno; +} + +/* + * Called from the main program after receiving SIGHUP. + * Restarts the server. + */ +static void +sighup_restart(void) +{ + logit("Received SIGHUP; restarting."); + close_listen_socks(); + close_startup_pipes(); + execv(saved_argv[0], saved_argv); + logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], + strerror(errno)); + exit(1); +} + +/* + * Generic signal handler for terminating signals in the master daemon. + */ +static void +sigterm_handler(int sig) +{ + received_sigterm = sig; +} + +/* + * SIGCHLD handler. This is called whenever a child dies. This will then + * reap any zombies left by exited children. + */ +static void +main_sigchld_handler(int sig) +{ + int save_errno = errno; + pid_t pid; + int status; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || + (pid < 0 && errno == EINTR)) + ; + + signal(SIGCHLD, main_sigchld_handler); + errno = save_errno; +} + +/* + * Signal handler for the alarm after the login grace period has expired. + */ +static void +grace_alarm_handler(int sig) +{ + /* XXX no idea how fix this signal handler */ + + if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0) + kill(pmonitor->m_pid, SIGALRM); + + /* Log error and exit. */ + fatal("Timeout before authentication for %s", get_remote_ipaddr()); +} + +/* + * 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. + */ +static void +generate_ephemeral_server_key(void) +{ + u_int32_t rnd = 0; + int i; + + verbose("Generating %s%d bit RSA key.", + sensitive_data.server_key ? "new " : "", options.server_key_bits); + if (sensitive_data.server_key != NULL) + key_free(sensitive_data.server_key); + sensitive_data.server_key = key_generate(KEY_RSA1, + options.server_key_bits); + verbose("RSA key generation complete."); + + for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { + if (i % 4 == 0) + rnd = arc4random(); + sensitive_data.ssh1_cookie[i] = rnd & 0xff; + rnd >>= 8; + } + arc4random_stir(); +} + +static void +key_regeneration_alarm(int sig) +{ + int save_errno = errno; + + signal(SIGALRM, SIG_DFL); + errno = save_errno; + key_do_regen = 1; +} + +static void +sshd_exchange_identification(int sock_in, int sock_out) +{ + int i, mismatch; + int remote_major, remote_minor; + int major, minor; + char *s; + char buf[256]; /* Must not be larger than remote_version. */ + char remote_version[256]; /* Must be at least as big as buf. */ + + if ((options.protocol & SSH_PROTO_1) && + (options.protocol & SSH_PROTO_2)) { + major = PROTOCOL_MAJOR_1; + minor = 99; + } else if (options.protocol & SSH_PROTO_2) { + major = PROTOCOL_MAJOR_2; + minor = PROTOCOL_MINOR_2; + } else { + major = PROTOCOL_MAJOR_1; + minor = PROTOCOL_MINOR_1; + } + snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION); + server_version_string = xstrdup(buf); + + /* Send our protocol version identification. */ + if (atomicio(vwrite, sock_out, server_version_string, + strlen(server_version_string)) + != strlen(server_version_string)) { + logit("Could not write ident string to %s", get_remote_ipaddr()); + cleanup_exit(255); + } + + /* Read other sides version identification. */ + memset(buf, 0, sizeof(buf)); + for (i = 0; i < sizeof(buf) - 1; i++) { + if (atomicio(read, sock_in, &buf[i], 1) != 1) { + logit("Did not receive identification string from %s", + get_remote_ipaddr()); + cleanup_exit(255); + } + if (buf[i] == '\r') { + buf[i] = 0; + /* Kludge for F-Secure Macintosh < 1.0.2 */ + if (i == 12 && + strncmp(buf, "SSH-1.5-W1.0", 12) == 0) + break; + continue; + } + if (buf[i] == '\n') { + buf[i] = 0; + break; + } + } + buf[sizeof(buf) - 1] = 0; + client_version_string = xstrdup(buf); + + /* + * Check that the versions match. In future this might accept + * several versions and set appropriate flags to handle them. + */ + if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n", + &remote_major, &remote_minor, remote_version) != 3) { + s = "Protocol mismatch.\n"; + (void) atomicio(vwrite, sock_out, s, strlen(s)); + close(sock_in); + close(sock_out); + logit("Bad protocol version identification '%.100s' from %s", + client_version_string, get_remote_ipaddr()); + cleanup_exit(255); + } + debug("Client protocol version %d.%d; client software version %.100s", + remote_major, remote_minor, remote_version); + + compat_datafellows(remote_version); + + if (datafellows & SSH_BUG_PROBE) { + logit("probed from %s with %s. Don't panic.", + get_remote_ipaddr(), client_version_string); + cleanup_exit(255); + } + + if (datafellows & SSH_BUG_SCANNER) { + logit("scanned from %s with %s. Don't panic.", + get_remote_ipaddr(), client_version_string); + cleanup_exit(255); + } + + mismatch = 0; + switch (remote_major) { + case 1: + if (remote_minor == 99) { + if (options.protocol & SSH_PROTO_2) + enable_compat20(); + else + mismatch = 1; + break; + } + if (!(options.protocol & SSH_PROTO_1)) { + mismatch = 1; + break; + } + if (remote_minor < 3) { + packet_disconnect("Your ssh version is too old and " + "is no longer supported. Please install a newer version."); + } else if (remote_minor == 3) { + /* note that this disables agent-forwarding */ + enable_compat13(); + } + break; + case 2: + if (options.protocol & SSH_PROTO_2) { + enable_compat20(); + break; + } + /* FALLTHROUGH */ + default: + mismatch = 1; + break; + } + chop(server_version_string); + debug("Local version string %.200s", server_version_string); + + if (mismatch) { + s = "Protocol major versions differ.\n"; + (void) atomicio(vwrite, sock_out, s, strlen(s)); + close(sock_in); + close(sock_out); + logit("Protocol major versions differ for %s: %.200s vs. %.200s", + get_remote_ipaddr(), + server_version_string, client_version_string); + cleanup_exit(255); + } +} + +/* Destroy the host and server keys. They will no longer be needed. */ +void +destroy_sensitive_data(void) +{ + int i; + + if (sensitive_data.server_key) { + key_free(sensitive_data.server_key); + sensitive_data.server_key = NULL; + } + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = NULL; + } + } + sensitive_data.ssh1_host_key = NULL; + memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); +} + +/* Demote private to public keys for network child */ +void +demote_sensitive_data(void) +{ + Key *tmp; + int i; + + if (sensitive_data.server_key) { + tmp = key_demote(sensitive_data.server_key); + key_free(sensitive_data.server_key); + sensitive_data.server_key = tmp; + } + + for (i = 0; i < options.num_host_key_files; i++) { + if (sensitive_data.host_keys[i]) { + tmp = key_demote(sensitive_data.host_keys[i]); + key_free(sensitive_data.host_keys[i]); + sensitive_data.host_keys[i] = tmp; + if (tmp->type == KEY_RSA1) + sensitive_data.ssh1_host_key = tmp; + } + } + + /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ +} + +static void +privsep_preauth_child(void) +{ + u_int32_t rnd[256]; + gid_t gidset[1]; + struct passwd *pw; + int i; + + /* Enable challenge-response authentication for privilege separation */ + privsep_challenge_enable(); + + for (i = 0; i < 256; i++) + rnd[i] = arc4random(); + RAND_seed(rnd, sizeof(rnd)); + + /* Demote the private keys to public keys. */ + demote_sensitive_data(); + + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) + fatal("Privilege separation user %s does not exist", + SSH_PRIVSEP_USER); + memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); + endpwent(); + + /* Change our root directory */ + if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) + fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, + strerror(errno)); + if (chdir("/") == -1) + fatal("chdir(\"/\"): %s", strerror(errno)); + + /* Drop our privileges */ + debug3("privsep user:group %u:%u", (u_int)pw->pw_uid, + (u_int)pw->pw_gid); +#if 0 + /* XXX not ready, too heavy after chroot */ + do_setusercontext(pw); +#else + gidset[0] = pw->pw_gid; + if (setgroups(1, gidset) < 0) + fatal("setgroups: %.100s", strerror(errno)); + permanently_set_uid(pw); +#endif +} + +static int +privsep_preauth(Authctxt *authctxt) +{ + int status; + pid_t pid; + + /* Set up unprivileged child process to deal with network data */ + pmonitor = monitor_init(); + /* Store a pointer to the kex for later rekeying */ + pmonitor->m_pkex = &xxx_kex; + + pid = fork(); + if (pid == -1) { + fatal("fork of unprivileged child failed"); + } else if (pid != 0) { + debug2("Network child is on pid %ld", (long)pid); + + close(pmonitor->m_recvfd); + pmonitor->m_pid = pid; + monitor_child_preauth(authctxt, pmonitor); + close(pmonitor->m_sendfd); + + /* Sync memory */ + monitor_sync(pmonitor); + + /* Wait for the child's exit status */ + while (waitpid(pid, &status, 0) < 0) + if (errno != EINTR) + break; + return (1); + } else { + /* child */ + + close(pmonitor->m_sendfd); + + /* Demote the child */ + if (getuid() == 0 || geteuid() == 0) + privsep_preauth_child(); + setproctitle("%s", "[net]"); + } + return (0); +} + +static void +privsep_postauth(Authctxt *authctxt) +{ +#ifdef DISABLE_FD_PASSING + if (1) { +#else + if (authctxt->pw->pw_uid == 0 || options.use_login) { +#endif + /* File descriptor passing is broken or root login */ + monitor_apply_keystate(pmonitor); + use_privsep = 0; + return; + } + + /* Authentication complete */ + alarm(0); + if (startup_pipe != -1) { + close(startup_pipe); + startup_pipe = -1; + } + + /* New socket pair */ + monitor_reinit(pmonitor); + + pmonitor->m_pid = fork(); + if (pmonitor->m_pid == -1) + fatal("fork of unprivileged child failed"); + else if (pmonitor->m_pid != 0) { + debug2("User child is on pid %ld", (long)pmonitor->m_pid); + close(pmonitor->m_recvfd); + buffer_clear(&loginmsg); + monitor_child_postauth(pmonitor); + + /* NEVERREACHED */ + exit(0); + } + + close(pmonitor->m_sendfd); + + /* Demote the private keys to public keys. */ + demote_sensitive_data(); + + /* Drop privileges */ + do_setusercontext(authctxt->pw); + + /* It is safe now to apply the key state */ + monitor_apply_keystate(pmonitor); +} + +static char * +list_hostkey_types(void) +{ + Buffer b; + const char *p; + char *ret; + int i; + + buffer_init(&b); + for (i = 0; i < options.num_host_key_files; i++) { + Key *key = sensitive_data.host_keys[i]; + if (key == NULL) + continue; + switch (key->type) { + case KEY_RSA: + case KEY_DSA: + if (buffer_len(&b) > 0) + buffer_append(&b, ",", 1); + p = key_ssh_name(key); + buffer_append(&b, p, strlen(p)); + break; + } + } + buffer_append(&b, "\0", 1); + ret = xstrdup(buffer_ptr(&b)); + buffer_free(&b); + debug("list_hostkey_types: %s", ret); + return ret; +} + +Key * +get_hostkey_by_type(int type) +{ + int i; + + for (i = 0; i < options.num_host_key_files; i++) { + Key *key = sensitive_data.host_keys[i]; + if (key != NULL && key->type == type) + return key; + } + return NULL; +} + +Key * +get_hostkey_by_index(int ind) +{ + if (ind < 0 || ind >= options.num_host_key_files) + return (NULL); + return (sensitive_data.host_keys[ind]); +} + +int +get_hostkey_index(Key *key) +{ + int i; + + for (i = 0; i < options.num_host_key_files; i++) { + if (key == sensitive_data.host_keys[i]) + return (i); + } + return (-1); +} + +/* + * returns 1 if connection should be dropped, 0 otherwise. + * dropping starts at connection #max_startups_begin with a probability + * of (max_startups_rate/100). the probability increases linearly until + * all connections are dropped for startups > max_startups + */ +static int +drop_connection(int startups) +{ + double p, r; + + if (startups < options.max_startups_begin) + return 0; + if (startups >= options.max_startups) + return 1; + if (options.max_startups_rate == 100) + return 1; + + p = 100 - options.max_startups_rate; + p *= startups - options.max_startups_begin; + p /= (double) (options.max_startups - options.max_startups_begin); + p += options.max_startups_rate; + p /= 100.0; + r = arc4random() / (double) UINT_MAX; + + debug("drop_connection: p %g, r %g", p, r); + return (r < p) ? 1 : 0; +} + +static void +usage(void) +{ + fprintf(stderr, "%s, %s\n", + SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); + fprintf(stderr, +"usage: sshd [-46Ddeiqt] [-b bits] [-f config_file] [-g login_grace_time]\n" +" [-h host_key_file] [-k key_gen_time] [-o option] [-p port] [-u len]\n" + ); + exit(1); +} + +static void +send_rexec_state(int fd, Buffer *conf) +{ + Buffer m; + + debug3("%s: entering fd = %d config len %d", __func__, fd, + buffer_len(conf)); + + /* + * Protocol from reexec master to child: + * string configuration + * u_int ephemeral_key_follows + * bignum e (only if ephemeral_key_follows == 1) + * bignum n " + * bignum d " + * bignum iqmp " + * bignum p " + * bignum q " + */ + buffer_init(&m); + buffer_put_cstring(&m, buffer_ptr(conf)); + + if (sensitive_data.server_key != NULL && + sensitive_data.server_key->type == KEY_RSA1) { + buffer_put_int(&m, 1); + buffer_put_bignum(&m, sensitive_data.server_key->rsa->e); + buffer_put_bignum(&m, sensitive_data.server_key->rsa->n); + buffer_put_bignum(&m, sensitive_data.server_key->rsa->d); + buffer_put_bignum(&m, sensitive_data.server_key->rsa->iqmp); + buffer_put_bignum(&m, sensitive_data.server_key->rsa->p); + buffer_put_bignum(&m, sensitive_data.server_key->rsa->q); + } else + buffer_put_int(&m, 0); + + if (ssh_msg_send(fd, 0, &m) == -1) + fatal("%s: ssh_msg_send failed", __func__); + + buffer_free(&m); + + debug3("%s: done", __func__); +} + +static void +recv_rexec_state(int fd, Buffer *conf) +{ + Buffer m; + char *cp; + u_int len; + + debug3("%s: entering fd = %d", __func__, fd); + + buffer_init(&m); + + if (ssh_msg_recv(fd, &m) == -1) + fatal("%s: ssh_msg_recv failed", __func__); + if (buffer_get_char(&m) != 0) + fatal("%s: rexec version mismatch", __func__); + + cp = buffer_get_string(&m, &len); + if (conf != NULL) + buffer_append(conf, cp, len + 1); + xfree(cp); + + if (buffer_get_int(&m)) { + if (sensitive_data.server_key != NULL) + key_free(sensitive_data.server_key); + sensitive_data.server_key = key_new_private(KEY_RSA1); + buffer_get_bignum(&m, sensitive_data.server_key->rsa->e); + buffer_get_bignum(&m, sensitive_data.server_key->rsa->n); + buffer_get_bignum(&m, sensitive_data.server_key->rsa->d); + buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp); + buffer_get_bignum(&m, sensitive_data.server_key->rsa->p); + buffer_get_bignum(&m, sensitive_data.server_key->rsa->q); + rsa_generate_additional_parameters( + sensitive_data.server_key->rsa); + } + buffer_free(&m); + + debug3("%s: done", __func__); +} + +/* + * Main program for the daemon. + */ +int +main(int ac, char **av) +{ + extern char *optarg; + extern int optind; + int opt, j, i, fdsetsz, on = 1; + int sock_in = -1, sock_out = -1, newsock = -1; + pid_t pid; + socklen_t fromlen; + fd_set *fdset; + struct sockaddr_storage from; + const char *remote_ip; + int remote_port; + FILE *f; + struct addrinfo *ai; + char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + char *line; + int listen_sock, maxfd; + int startup_p[2], config_s[2]; + int startups = 0; + Key *key; + Authctxt *authctxt; + int ret, key_used = 0; + Buffer cfg; + +#ifdef HAVE_SECUREWARE + (void)set_auth_parameters(ac, av); +#endif + __progname = ssh_get_progname(av[0]); + init_rng(); + + /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ + saved_argc = ac; + rexec_argc = ac; + saved_argv = xmalloc(sizeof(*saved_argv) * (ac + 1)); + for (i = 0; i < ac; i++) + saved_argv[i] = xstrdup(av[i]); + saved_argv[i] = NULL; + +#ifndef HAVE_SETPROCTITLE + /* Prepare for later setproctitle emulation */ + compat_init_setproctitle(ac, av); + av = saved_argv; +#endif + + if (geteuid() == 0 && setgroups(0, NULL) == -1) + debug("setgroups(): %.200s", strerror(errno)); + + /* 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:u:o:dDeiqrtQR46")) != -1) { + switch (opt) { + case '4': + IPv4or6 = AF_INET; + break; + case '6': + IPv4or6 = AF_INET6; + break; + case 'f': + config_file_name = optarg; + break; + case 'd': + if (debug_flag == 0) { + debug_flag = 1; + options.log_level = SYSLOG_LEVEL_DEBUG1; + } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) + options.log_level++; + break; + case 'D': + no_daemon_flag = 1; + break; + case 'e': + log_stderr = 1; + break; + case 'i': + inetd_flag = 1; + break; + case 'r': + rexec_flag = 0; + break; + case 'R': + rexeced_flag = 1; + inetd_flag = 1; + break; + case 'Q': + /* ignored */ + break; + case 'q': + options.log_level = SYSLOG_LEVEL_QUIET; + break; + case 'b': + options.server_key_bits = atoi(optarg); + break; + case 'p': + options.ports_from_cmdline = 1; + if (options.num_ports >= MAX_PORTS) { + fprintf(stderr, "too many ports.\n"); + exit(1); + } + options.ports[options.num_ports++] = a2port(optarg); + if (options.ports[options.num_ports-1] == 0) { + fprintf(stderr, "Bad port number.\n"); + exit(1); + } + break; + case 'g': + if ((options.login_grace_time = convtime(optarg)) == -1) { + fprintf(stderr, "Invalid login grace time.\n"); + exit(1); + } + break; + case 'k': + if ((options.key_regeneration_time = convtime(optarg)) == -1) { + fprintf(stderr, "Invalid key regeneration interval.\n"); + exit(1); + } + break; + case 'h': + if (options.num_host_key_files >= MAX_HOSTKEYS) { + fprintf(stderr, "too many host keys.\n"); + exit(1); + } + options.host_key_files[options.num_host_key_files++] = optarg; + break; + case 't': + test_flag = 1; + break; + case 'u': + utmp_len = atoi(optarg); + if (utmp_len > MAXHOSTNAMELEN) { + fprintf(stderr, "Invalid utmp length.\n"); + exit(1); + } + break; + case 'o': + line = xstrdup(optarg); + if (process_server_config_line(&options, line, + "command-line", 0) != 0) + exit(1); + xfree(line); + break; + case '?': + default: + usage(); + break; + } + } + if (rexeced_flag || inetd_flag) + rexec_flag = 0; + if (rexec_flag && (av[0] == NULL || *av[0] != '/')) + fatal("sshd re-exec requires execution with an absolute path"); + if (rexeced_flag) + closefrom(REEXEC_MIN_FREE_FD); + else + closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); + + SSLeay_add_all_algorithms(); + channel_set_af(IPv4or6); + + /* + * Force logging to stderr until we have loaded the private host + * key (unless started from inetd) + */ + log_init(__progname, + options.log_level == SYSLOG_LEVEL_NOT_SET ? + SYSLOG_LEVEL_INFO : options.log_level, + options.log_facility == SYSLOG_FACILITY_NOT_SET ? + SYSLOG_FACILITY_AUTH : options.log_facility, + log_stderr || !inetd_flag); + +#ifdef _AIX + /* + * Unset KRB5CCNAME, otherwise the user's session may inherit it from + * root's environment + */ + unsetenv("KRB5CCNAME"); +#endif /* _AIX */ +#ifdef _UNICOS + /* Cray can define user privs drop all privs now! + * Not needed on PRIV_SU systems! + */ + drop_cray_privs(); +#endif + + seed_rng(); + + sensitive_data.server_key = NULL; + sensitive_data.ssh1_host_key = NULL; + sensitive_data.have_ssh1_key = 0; + sensitive_data.have_ssh2_key = 0; + + /* Fetch our configuration */ + buffer_init(&cfg); + if (rexeced_flag) + recv_rexec_state(REEXEC_CONFIG_PASS_FD, &cfg); + else + load_server_config(config_file_name, &cfg); + + parse_server_config(&options, + rexeced_flag ? "rexec" : config_file_name, &cfg); + + if (!rexec_flag) + buffer_free(&cfg); + + /* Fill in default values for those options not explicitly set. */ + fill_default_server_options(&options); + + /* Check that there are no remaining arguments. */ + if (optind < ac) { + fprintf(stderr, "Extra argument %s.\n", av[optind]); + exit(1); + } + + debug("sshd version %.100s", SSH_VERSION); + + /* load private host keys */ + sensitive_data.host_keys = xmalloc(options.num_host_key_files * + sizeof(Key *)); + for (i = 0; i < options.num_host_key_files; i++) + sensitive_data.host_keys[i] = NULL; + + for (i = 0; i < options.num_host_key_files; i++) { + key = key_load_private(options.host_key_files[i], "", NULL); + sensitive_data.host_keys[i] = key; + if (key == NULL) { + error("Could not load host key: %s", + options.host_key_files[i]); + sensitive_data.host_keys[i] = NULL; + continue; + } + switch (key->type) { + case KEY_RSA1: + sensitive_data.ssh1_host_key = key; + sensitive_data.have_ssh1_key = 1; + break; + case KEY_RSA: + case KEY_DSA: + sensitive_data.have_ssh2_key = 1; + break; + } + debug("private host key: #%d type %d %s", i, key->type, + key_type(key)); + } + if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { + logit("Disabling protocol version 1. Could not load host key"); + options.protocol &= ~SSH_PROTO_1; + } + if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) { + logit("Disabling protocol version 2. Could not load host key"); + options.protocol &= ~SSH_PROTO_2; + } + if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { + logit("sshd: no hostkeys available -- exiting."); + exit(1); + } + + /* Check certain values for sanity. */ + if (options.protocol & SSH_PROTO_1) { + if (options.server_key_bits < 512 || + options.server_key_bits > 32768) { + fprintf(stderr, "Bad server key size.\n"); + exit(1); + } + /* + * Check that server and host key lengths differ sufficiently. This + * is necessary to make double encryption work with rsaref. Oh, I + * hate software patents. I dont know if this can go? Niels + */ + if (options.server_key_bits > + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) - + SSH_KEY_BITS_RESERVED && options.server_key_bits < + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + + SSH_KEY_BITS_RESERVED) { + options.server_key_bits = + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + + SSH_KEY_BITS_RESERVED; + debug("Forcing server key to %d bits to make it differ from host key.", + options.server_key_bits); + } + } + + if (use_privsep) { + struct passwd *pw; + struct stat st; + + if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) + fatal("Privilege separation user %s does not exist", + SSH_PRIVSEP_USER); + if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || + (S_ISDIR(st.st_mode) == 0)) + fatal("Missing privilege separation directory: %s", + _PATH_PRIVSEP_CHROOT_DIR); + +#ifdef HAVE_CYGWIN + if (check_ntsec(_PATH_PRIVSEP_CHROOT_DIR) && + (st.st_uid != getuid () || + (st.st_mode & (S_IWGRP|S_IWOTH)) != 0)) +#else + if (st.st_uid != 0 || (st.st_mode & (S_IWGRP|S_IWOTH)) != 0) +#endif + fatal("%s must be owned by root and not group or " + "world-writable.", _PATH_PRIVSEP_CHROOT_DIR); + } + + /* Configuration looks good, so exit if in test mode. */ + if (test_flag) + exit(0); + + /* + * Clear out any supplemental groups we may have inherited. This + * prevents inadvertent creation of files with bad modes (in the + * portable version at least, it's certainly possible for PAM + * to create a file, and we can't control the code in every + * module which might be used). + */ + if (setgroups(0, NULL) < 0) + debug("setgroups() failed: %.200s", strerror(errno)); + + if (rexec_flag) { + rexec_argv = xmalloc(sizeof(char *) * (rexec_argc + 2)); + for (i = 0; i < rexec_argc; i++) { + debug("rexec_argv[%d]='%s'", i, saved_argv[i]); + rexec_argv[i] = saved_argv[i]; + } + rexec_argv[rexec_argc] = "-R"; + rexec_argv[rexec_argc + 1] = NULL; + } + + /* Initialize the log (it is reinitialized below in case we forked). */ + if (debug_flag && !inetd_flag) + log_stderr = 1; + log_init(__progname, options.log_level, options.log_facility, log_stderr); + + /* + * 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 || no_daemon_flag)) { +#ifdef TIOCNOTTY + int fd; +#endif /* TIOCNOTTY */ + if (daemon(0, 0) < 0) + fatal("daemon() failed: %.200s", strerror(errno)); + + /* Disconnect from the controlling tty. */ +#ifdef TIOCNOTTY + fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); + if (fd >= 0) { + (void) ioctl(fd, TIOCNOTTY, NULL); + close(fd); + } +#endif /* TIOCNOTTY */ + } + /* Reinitialize the log (because of the fork above). */ + log_init(__progname, options.log_level, options.log_facility, log_stderr); + + /* Initialize the random number generator. */ + arc4random_stir(); + + /* Chdir to the root directory so that the current disk can be + unmounted if desired. */ + chdir("/"); + + /* ignore SIGPIPE */ + signal(SIGPIPE, SIG_IGN); + + /* Start listening for a socket, unless started from inetd. */ + if (inetd_flag) { + int fd; + + startup_pipe = -1; + if (rexeced_flag) { + close(REEXEC_CONFIG_PASS_FD); + sock_in = sock_out = dup(STDIN_FILENO); + if (!debug_flag) { + startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); + close(REEXEC_STARTUP_PIPE_FD); + } + } else { + sock_in = dup(STDIN_FILENO); + sock_out = dup(STDOUT_FILENO); + } + /* + * 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. + */ + if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + if (fd > STDOUT_FILENO) + close(fd); + } + debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); + if ((options.protocol & SSH_PROTO_1) && + sensitive_data.server_key == NULL) + generate_ephemeral_server_key(); + } else { + for (ai = options.listen_addrs; ai; ai = ai->ai_next) { + if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) + continue; + if (num_listen_socks >= MAX_LISTEN_SOCKS) + fatal("Too many listen sockets. " + "Enlarge MAX_LISTEN_SOCKS"); + if (getnameinfo(ai->ai_addr, ai->ai_addrlen, + ntop, sizeof(ntop), strport, sizeof(strport), + NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + error("getnameinfo failed"); + continue; + } + /* Create socket for listening. */ + listen_sock = socket(ai->ai_family, ai->ai_socktype, + ai->ai_protocol); + if (listen_sock < 0) { + /* kernel may not support ipv6 */ + verbose("socket: %.100s", strerror(errno)); + continue; + } + if (set_nonblock(listen_sock) == -1) { + close(listen_sock); + continue; + } + /* + * Set socket options. + * Allow local port reuse in TIME_WAIT. + */ + if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, + &on, sizeof(on)) == -1) + error("setsockopt SO_REUSEADDR: %s", strerror(errno)); + + debug("Bind to port %s on %s.", strport, ntop); + + /* Bind the socket to the desired port. */ + if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { + if (!ai->ai_next) + error("Bind to port %s on %s failed: %.200s.", + strport, ntop, strerror(errno)); + close(listen_sock); + continue; + } + listen_socks[num_listen_socks] = listen_sock; + num_listen_socks++; + + /* Start listening on the port. */ + logit("Server listening on %s port %s.", ntop, strport); + if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) + fatal("listen: %.100s", strerror(errno)); + + } + freeaddrinfo(options.listen_addrs); + + if (!num_listen_socks) + fatal("Cannot bind any address."); + + if (options.protocol & SSH_PROTO_1) + generate_ephemeral_server_key(); + + /* + * 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); + + /* Write out the pid file after the sigterm handler is setup */ + if (!debug_flag) { + /* + * Record our pid in /var/run/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(options.pid_file, "wb"); + if (f == NULL) { + error("Couldn't create pid file \"%s\": %s", + options.pid_file, strerror(errno)); + } else { + fprintf(f, "%ld\n", (long) getpid()); + fclose(f); + } + } + + /* setup fd set for listen */ + fdset = NULL; + maxfd = 0; + for (i = 0; i < num_listen_socks; i++) + if (listen_socks[i] > maxfd) + maxfd = listen_socks[i]; + /* pipes connected to unauthenticated childs */ + startup_pipes = xmalloc(options.max_startups * sizeof(int)); + for (i = 0; i < options.max_startups; i++) + startup_pipes[i] = -1; + + /* + * Stay listening for connections until the system crashes or + * the daemon is killed with a signal. + */ + for (;;) { + if (received_sighup) + sighup_restart(); + if (fdset != NULL) + xfree(fdset); + fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)xmalloc(fdsetsz); + memset(fdset, 0, fdsetsz); + + for (i = 0; i < num_listen_socks; i++) + FD_SET(listen_socks[i], fdset); + for (i = 0; i < options.max_startups; i++) + if (startup_pipes[i] != -1) + FD_SET(startup_pipes[i], fdset); + + /* Wait in select until there is a connection. */ + ret = select(maxfd+1, fdset, NULL, NULL, NULL); + if (ret < 0 && errno != EINTR) + error("select: %.100s", strerror(errno)); + if (received_sigterm) { + logit("Received signal %d; terminating.", + (int) received_sigterm); + close_listen_socks(); + unlink(options.pid_file); + exit(255); + } + if (key_used && key_do_regen) { + generate_ephemeral_server_key(); + key_used = 0; + key_do_regen = 0; + } + if (ret < 0) + continue; + + for (i = 0; i < options.max_startups; i++) + if (startup_pipes[i] != -1 && + FD_ISSET(startup_pipes[i], fdset)) { + /* + * the read end of the pipe is ready + * if the child has closed the pipe + * after successful authentication + * or if the child has died + */ + close(startup_pipes[i]); + startup_pipes[i] = -1; + startups--; + } + for (i = 0; i < num_listen_socks; i++) { + if (!FD_ISSET(listen_socks[i], fdset)) + continue; + fromlen = sizeof(from); + newsock = accept(listen_socks[i], (struct sockaddr *)&from, + &fromlen); + if (newsock < 0) { + if (errno != EINTR && errno != EWOULDBLOCK) + error("accept: %.100s", strerror(errno)); + continue; + } + if (unset_nonblock(newsock) == -1) { + close(newsock); + continue; + } + if (drop_connection(startups) == 1) { + debug("drop connection #%d", startups); + close(newsock); + continue; + } + if (pipe(startup_p) == -1) { + close(newsock); + continue; + } + + if (rexec_flag && socketpair(AF_UNIX, + SOCK_STREAM, 0, config_s) == -1) { + error("reexec socketpair: %s", + strerror(errno)); + close(newsock); + close(startup_p[0]); + close(startup_p[1]); + continue; + } + + for (j = 0; j < options.max_startups; j++) + if (startup_pipes[j] == -1) { + startup_pipes[j] = startup_p[0]; + if (maxfd < startup_p[0]) + maxfd = startup_p[0]; + startups++; + break; + } + + /* + * 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_socks(); + sock_in = newsock; + sock_out = newsock; + close(startup_p[0]); + close(startup_p[1]); + startup_pipe = -1; + pid = getpid(); + if (rexec_flag) { + send_rexec_state(config_s[0], + &cfg); + close(config_s[0]); + } + 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 and max_startup + * sockets. Start using the accepted socket. + * Reinitialize logging (since our pid has + * changed). We break out of the loop to handle + * the connection. + */ + startup_pipe = startup_p[1]; + close_startup_pipes(); + close_listen_socks(); + sock_in = newsock; + sock_out = newsock; + log_init(__progname, options.log_level, options.log_facility, log_stderr); + close(config_s[0]); + break; + } + } + + /* Parent. Stay in the loop. */ + if (pid < 0) + error("fork: %.100s", strerror(errno)); + else + debug("Forked child %ld.", (long)pid); + + close(startup_p[1]); + + if (rexec_flag) { + send_rexec_state(config_s[0], &cfg); + close(config_s[0]); + close(config_s[1]); + } + + /* Mark that the key has been used (it was "given" to the child). */ + if ((options.protocol & SSH_PROTO_1) && + key_used == 0) { + /* Schedule server key regeneration alarm. */ + signal(SIGALRM, key_regeneration_alarm); + alarm(options.key_regeneration_time); + key_used = 1; + } + + arc4random_stir(); + + /* Close the new socket (the child is now taking care of it). */ + close(newsock); + } + /* child process check (or debug mode) */ + if (num_listen_socks < 0) + break; + } + } + + /* This is the child processing a new connection. */ + setproctitle("%s", "[accepted]"); + + /* + * Create a new session and process group since the 4.4BSD + * setlogin() affects the entire process group. We don't + * want the child to be able to affect the parent. + */ +#if !defined(SSHD_ACQUIRES_CTTY) + /* + * If setsid is called, on some platforms sshd will later acquire a + * controlling terminal which will result in "could not set + * controlling tty" errors. + */ + if (!debug_flag && !inetd_flag && setsid() < 0) + error("setsid: %.100s", strerror(errno)); +#endif + + if (rexec_flag) { + int fd; + + debug("rexec start in %d out %d newsock %d pipe %d sock %d", + sock_in, sock_out, newsock, startup_pipe, config_s[0]); + dup2(newsock, STDIN_FILENO); + dup2(STDIN_FILENO, STDOUT_FILENO); + if (startup_pipe == -1) + close(REEXEC_STARTUP_PIPE_FD); + else + dup2(startup_pipe, REEXEC_STARTUP_PIPE_FD); + + dup2(config_s[1], REEXEC_CONFIG_PASS_FD); + close(config_s[1]); + if (startup_pipe != -1) + close(startup_pipe); + + execv(rexec_argv[0], rexec_argv); + + /* Reexec has failed, fall back and continue */ + error("rexec of %s failed: %s", rexec_argv[0], strerror(errno)); + recv_rexec_state(REEXEC_CONFIG_PASS_FD, NULL); + log_init(__progname, options.log_level, + options.log_facility, log_stderr); + + /* Clean up fds */ + startup_pipe = REEXEC_STARTUP_PIPE_FD; + close(config_s[1]); + close(REEXEC_CONFIG_PASS_FD); + newsock = sock_out = sock_in = dup(STDIN_FILENO); + if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + if (fd > STDERR_FILENO) + close(fd); + } + debug("rexec cleanup in %d out %d newsock %d pipe %d sock %d", + sock_in, sock_out, newsock, startup_pipe, config_s[0]); + } + + /* + * 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); + signal(SIGINT, SIG_DFL); + + /* Set SO_KEEPALIVE if requested. */ + if (options.tcp_keep_alive && + setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, + sizeof(on)) < 0) + error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); + + /* + * Register our connection. This turns encryption off because we do + * not have a key. + */ + packet_set_connection(sock_in, sock_out); + + remote_port = get_remote_port(); + remote_ip = get_remote_ipaddr(); + +#ifdef LIBWRAP + /* Check whether logins are denied from this host. */ + if (packet_connection_is_on_socket()) { + struct request_info req; + + request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); + fromhost(&req); + + if (!hosts_access(&req)) { + debug("Connection refused by tcp wrapper"); + refuse(&req); + /* NOTREACHED */ + fatal("libwrap refuse returns"); + } + } +#endif /* LIBWRAP */ + + /* Log the connection. */ + verbose("Connection from %.500s port %d", remote_ip, remote_port); + + /* + * 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); + + sshd_exchange_identification(sock_in, sock_out); + + packet_set_nonblocking(); + + /* prepare buffers to collect authentication messages */ + buffer_init(&loginmsg); + + /* allocate authentication context */ + authctxt = xmalloc(sizeof(*authctxt)); + memset(authctxt, 0, sizeof(*authctxt)); + + /* XXX global for cleanup, access from other modules */ + the_authctxt = authctxt; + + if (use_privsep) + if (privsep_preauth(authctxt) == 1) + goto authenticated; + + /* prepare buffer to collect messages to display to user after login */ + buffer_init(&loginmsg); + + /* perform the key exchange */ + /* authenticate user and start session */ + if (compat20) { + do_ssh2_kex(); + do_authentication2(authctxt); + } else { + do_ssh1_kex(); + do_authentication(authctxt); + } + /* + * If we use privilege separation, the unprivileged child transfers + * the current keystate and exits + */ + if (use_privsep) { + mm_send_keystate(pmonitor); + exit(0); + } + + authenticated: + /* + * In privilege separation, we fork another child and prepare + * file descriptor passing. + */ + if (use_privsep) { + privsep_postauth(authctxt); + /* the monitor process [priv] will not return */ + if (!compat20) + destroy_sensitive_data(); + } + + /* Start session. */ + do_authenticated(authctxt); + + /* The connection has been terminated. */ + verbose("Closing connection to %.100s", remote_ip); + +#ifdef USE_PAM + if (options.use_pam) + finish_pam(); +#endif /* USE_PAM */ + + packet_close(); + + if (use_privsep) + mm_terminate(); + + exit(0); +} + +/* + * Decrypt session_key_int using our private server key and private host key + * (key with larger modulus first). + */ +int +ssh1_session_key(BIGNUM *session_key_int) +{ + int rsafail = 0; + + if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { + /* Server key has bigger modulus. */ + if (BN_num_bits(sensitive_data.server_key->rsa->n) < + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.server_key->rsa->n), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + SSH_KEY_BITS_RESERVED); + } + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.server_key->rsa) <= 0) + rsafail++; + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.ssh1_host_key->rsa) <= 0) + rsafail++; + } else { + /* Host key has bigger modulus (or they are equal). */ + if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < + BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { + fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", + get_remote_ipaddr(), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), + BN_num_bits(sensitive_data.server_key->rsa->n), + SSH_KEY_BITS_RESERVED); + } + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.ssh1_host_key->rsa) < 0) + rsafail++; + if (rsa_private_decrypt(session_key_int, session_key_int, + sensitive_data.server_key->rsa) < 0) + rsafail++; + } + return (rsafail); +} +/* + * SSH1 key exchange + */ +static void +do_ssh1_kex(void) +{ + int i, len; + int rsafail = 0; + BIGNUM *session_key_int; + u_char session_key[SSH_SESSION_KEY_LENGTH]; + u_char cookie[8]; + u_int cipher_type, auth_mask, protocol_flags; + u_int32_t rnd = 0; + + /* + * 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++) { + if (i % 4 == 0) + rnd = arc4random(); + cookie[i] = rnd & 0xff; + rnd >>= 8; + } + + /* + * 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(cookie[i]); + + /* Store our public server RSA key. */ + packet_put_int(BN_num_bits(sensitive_data.server_key->rsa->n)); + packet_put_bignum(sensitive_data.server_key->rsa->e); + packet_put_bignum(sensitive_data.server_key->rsa->n); + + /* Store our public host RSA key. */ + packet_put_int(BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); + packet_put_bignum(sensitive_data.ssh1_host_key->rsa->e); + packet_put_bignum(sensitive_data.ssh1_host_key->rsa->n); + + /* Put protocol flags. */ + packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); + + /* Declare which ciphers we support. */ + packet_put_int(cipher_mask_ssh1(0)); + + /* Declare supported authentication types. */ + auth_mask = 0; + if (options.rhosts_rsa_authentication) + auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA; + if (options.rsa_authentication) + auth_mask |= 1 << SSH_AUTH_RSA; + if (options.challenge_response_authentication == 1) + auth_mask |= 1 << SSH_AUTH_TIS; + 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 server key and %d bit host key.", + BN_num_bits(sensitive_data.server_key->rsa->n), + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); + + /* Read clients reply (cipher type and session key). */ + packet_read_expect(SSH_CMSG_SESSION_KEY); + + /* Get cipher type and check whether we accept this. */ + cipher_type = packet_get_char(); + + if (!(cipher_mask_ssh1(0) & (1 << cipher_type))) + packet_disconnect("Warning: client selects unsupported cipher."); + + /* 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 (cookie[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. */ + if ((session_key_int = BN_new()) == NULL) + fatal("do_ssh1_kex: BN_new failed"); + packet_get_bignum(session_key_int); + + protocol_flags = packet_get_int(); + packet_set_protocol_flags(protocol_flags); + packet_check_eom(); + + /* Decrypt session_key_int using host/server keys */ + rsafail = PRIVSEP(ssh1_session_key(session_key_int)); + + /* + * 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. + */ + if (!rsafail) { + BN_mask_bits(session_key_int, sizeof(session_key) * 8); + len = BN_num_bytes(session_key_int); + if (len < 0 || len > sizeof(session_key)) { + error("do_connection: bad session key len from %s: " + "session_key_int %d > sizeof(session_key) %lu", + get_remote_ipaddr(), len, (u_long)sizeof(session_key)); + rsafail++; + } else { + memset(session_key, 0, sizeof(session_key)); + BN_bn2bin(session_key_int, + session_key + sizeof(session_key) - len); + + derive_ssh1_session_id( + sensitive_data.ssh1_host_key->rsa->n, + sensitive_data.server_key->rsa->n, + cookie, session_id); + /* + * 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]; + } + } + if (rsafail) { + int bytes = BN_num_bytes(session_key_int); + u_char *buf = xmalloc(bytes); + MD5_CTX md; + + logit("do_connection: generating a fake encryption key"); + BN_bn2bin(session_key_int, buf); + MD5_Init(&md); + MD5_Update(&md, buf, bytes); + MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); + MD5_Final(session_key, &md); + MD5_Init(&md); + MD5_Update(&md, session_key, 16); + MD5_Update(&md, buf, bytes); + MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); + MD5_Final(session_key + 16, &md); + memset(buf, 0, bytes); + xfree(buf); + for (i = 0; i < 16; i++) + session_id[i] = session_key[i] ^ session_key[i + 16]; + } + /* Destroy the private and public keys. No longer. */ + destroy_sensitive_data(); + + if (use_privsep) + mm_ssh1_session_id(session_id); + + /* Destroy the decrypted integer. It is no longer needed. */ + BN_clear_free(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); + + /* 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 acknowledgment packet. Note that this packet is sent encrypted. */ + packet_start(SSH_SMSG_SUCCESS); + packet_send(); + packet_write_wait(); +} + +/* + * SSH2 key exchange: diffie-hellman-group1-sha1 + */ +static void +do_ssh2_kex(void) +{ + Kex *kex; + + if (options.ciphers != NULL) { + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; + } + myproposal[PROPOSAL_ENC_ALGS_CTOS] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); + myproposal[PROPOSAL_ENC_ALGS_STOC] = + compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); + + if (options.macs != NULL) { + myproposal[PROPOSAL_MAC_ALGS_CTOS] = + myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; + } + if (!options.compression) { + myproposal[PROPOSAL_COMP_ALGS_CTOS] = + myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; + } + myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); + + /* start key exchange */ + kex = kex_setup(myproposal); + kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; + kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; + kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; + kex->server = 1; + kex->client_version_string=client_version_string; + kex->server_version_string=server_version_string; + kex->load_host_key=&get_hostkey_by_type; + kex->host_key_index=&get_hostkey_index; + + xxx_kex = kex; + + dispatch_run(DISPATCH_BLOCK, &kex->done, kex); + + session_id2 = kex->session_id; + session_id2_len = kex->session_id_len; + +#ifdef DEBUG_KEXDH + /* send 1st encrypted/maced/compressed message */ + packet_start(SSH2_MSG_IGNORE); + packet_put_cstring("markus"); + packet_send(); + packet_write_wait(); +#endif + debug("KEX done"); +} + +/* server specific fatal cleanup */ +void +cleanup_exit(int i) +{ + if (the_authctxt) + do_cleanup(the_authctxt); + _exit(i); +} diff --git a/crypto/openssh-3.9p1/sshd_config b/crypto/openssh-3.9p1/sshd_config new file mode 100644 index 0000000000..65e6f1c32f --- /dev/null +++ b/crypto/openssh-3.9p1/sshd_config @@ -0,0 +1,103 @@ +# $OpenBSD: sshd_config,v 1.69 2004/05/23 23:59:53 dtucker Exp $ + +# This is the sshd server system-wide configuration file. See +# sshd_config(5) for more information. + +# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin + +# The strategy used for options in the default sshd_config shipped with +# OpenSSH is to specify options with their default value where +# possible, but leave them commented. Uncommented options change a +# default value. + +#Port 22 +#Protocol 2,1 +#ListenAddress 0.0.0.0 +#ListenAddress :: + +# HostKey for protocol version 1 +#HostKey /etc/ssh/ssh_host_key +# HostKeys for protocol version 2 +#HostKey /etc/ssh/ssh_host_rsa_key +#HostKey /etc/ssh/ssh_host_dsa_key + +# Lifetime and size of ephemeral version 1 server key +#KeyRegenerationInterval 1h +#ServerKeyBits 768 + +# Logging +#obsoletes QuietMode and FascistLogging +#SyslogFacility AUTH +#LogLevel INFO + +# Authentication: + +#LoginGraceTime 2m +#PermitRootLogin yes +#StrictModes yes +#MaxAuthTries 6 + +#RSAAuthentication yes +#PubkeyAuthentication yes +#AuthorizedKeysFile .ssh/authorized_keys + +# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts +#RhostsRSAAuthentication no +# similar for protocol version 2 +#HostbasedAuthentication no +# Change to yes if you don't trust ~/.ssh/known_hosts for +# RhostsRSAAuthentication and HostbasedAuthentication +#IgnoreUserKnownHosts no +# Don't read the user's ~/.rhosts and ~/.shosts files +#IgnoreRhosts yes + +# To disable tunneled clear text passwords, change to no here! +#PasswordAuthentication yes +#PermitEmptyPasswords no + +# Change to no to disable s/key passwords +#ChallengeResponseAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes +#KerberosGetAFSToken no + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication mechanism. +# Depending on your PAM configuration, this may bypass the setting of +# PasswordAuthentication, PermitEmptyPasswords, and +# "PermitRootLogin without-password". If you just want the PAM account and +# session checks to run without PAM authentication, then enable this but set +# ChallengeResponseAuthentication=no +#UsePAM no + +#AllowTcpForwarding yes +#GatewayPorts no +#X11Forwarding no +#X11DisplayOffset 10 +#X11UseLocalhost yes +#PrintMotd yes +#PrintLastLog yes +#TCPKeepAlive yes +#UseLogin no +#UsePrivilegeSeparation yes +#PermitUserEnvironment no +#Compression yes +#ClientAliveInterval 0 +#ClientAliveCountMax 3 +#UseDNS yes +#PidFile /var/run/sshd.pid +#MaxStartups 10 + +# no default banner path +#Banner /some/path + +# override default of no subsystems +Subsystem sftp /usr/libexec/sftp-server diff --git a/crypto/openssh-3.9p1/sshd_config.5 b/crypto/openssh-3.9p1/sshd_config.5 new file mode 100644 index 0000000000..09532fb8d6 --- /dev/null +++ b/crypto/openssh-3.9p1/sshd_config.5 @@ -0,0 +1,812 @@ +.\" -*- nroff -*- +.\" +.\" Author: Tatu Ylonen +.\" Copyright (c) 1995 Tatu Ylonen , Espoo, Finland +.\" All rights reserved +.\" +.\" 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". +.\" +.\" Copyright (c) 1999,2000 Markus Friedl. All rights reserved. +.\" Copyright (c) 1999 Aaron Campbell. All rights reserved. +.\" Copyright (c) 1999 Theo de Raadt. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $OpenBSD: sshd_config.5,v 1.35 2004/06/26 09:14:40 jmc Exp $ +.Dd September 25, 1999 +.Dt SSHD_CONFIG 5 +.Os +.Sh NAME +.Nm sshd_config +.Nd OpenSSH SSH daemon configuration file +.Sh SYNOPSIS +.Bl -tag -width Ds -compact +.It Pa /etc/ssh/sshd_config +.El +.Sh DESCRIPTION +.Nm sshd +reads configuration data from +.Pa /etc/ssh/sshd_config +(or the file specified with +.Fl f +on the command line). +The file contains keyword-argument pairs, one per line. +Lines starting with +.Ql # +and empty lines are interpreted as comments. +.Pp +The possible +keywords and their meanings are as follows (note that +keywords are case-insensitive and arguments are case-sensitive): +.Bl -tag -width Ds +.It Cm AcceptEnv +Specifies what environment variables sent by the client will be copied into +the session's +.Xr environ 7 . +See +.Cm SendEnv +in +.Xr ssh_config 5 +for how to configure the client. +Note that environment passing is only supported for protocol 2. +Variables are specified by name, which may contain the wildcard characters +.Ql \&* +and +.Ql \&? . +Multiple environment variables may be separated by whitespace or spread +across multiple +.Cm AcceptEnv +directives. +Be warned that some environment variables could be used to bypass restricted +user environments. +For this reason, care should be taken in the use of this directive. +The default is not to accept any environment variables. +.It Cm AllowGroups +This keyword can be followed by a list of group name patterns, separated +by spaces. +If specified, login is allowed only for users whose primary +group or supplementary group list matches one of the patterns. +.Ql \&* +and +.Ql \&? +can be used as +wildcards in the patterns. +Only group names are valid; a numerical group ID is not recognized. +By default, login is allowed for all groups. +.It Cm AllowTcpForwarding +Specifies whether TCP forwarding is permitted. +The default is +.Dq yes . +Note that disabling TCP forwarding does not improve security unless +users are also denied shell access, as they can always install their +own forwarders. +.It Cm AllowUsers +This keyword can be followed by a list of user name patterns, separated +by spaces. +If specified, login is allowed only for user names that +match one of the patterns. +.Ql \&* +and +.Ql \&? +can be used as +wildcards in the patterns. +Only user names are valid; a numerical user ID is not recognized. +By default, login is allowed for all users. +If the pattern takes the form USER@HOST then USER and HOST +are separately checked, restricting logins to particular +users from particular hosts. +.It Cm AuthorizedKeysFile +Specifies the file that contains the public keys that can be used +for user authentication. +.Cm AuthorizedKeysFile +may contain tokens of the form %T which are substituted during connection +set-up. +The following tokens are defined: %% is replaced by a literal '%', +%h is replaced by the home directory of the user being authenticated and +%u is replaced by the username of that user. +After expansion, +.Cm AuthorizedKeysFile +is taken to be an absolute path or one relative to the user's home +directory. +The default is +.Dq .ssh/authorized_keys . +.It Cm Banner +In some jurisdictions, sending a warning message before authentication +may be relevant for getting legal protection. +The contents of the specified file are sent to the remote user before +authentication is allowed. +This option is only available for protocol version 2. +By default, no banner is displayed. +.It Cm ChallengeResponseAuthentication +Specifies whether challenge response authentication is allowed. +All authentication styles from +.Xr login.conf 5 +are supported. +The default is +.Dq yes . +.It Cm Ciphers +Specifies the ciphers allowed for protocol version 2. +Multiple ciphers must be comma-separated. +The supported ciphers are +.Dq 3des-cbc , +.Dq aes128-cbc , +.Dq aes192-cbc , +.Dq aes256-cbc , +.Dq aes128-ctr , +.Dq aes192-ctr , +.Dq aes256-ctr , +.Dq arcfour , +.Dq blowfish-cbc , +and +.Dq cast128-cbc . +The default is +.Bd -literal + ``aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour, + aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr'' +.Ed +.It Cm ClientAliveInterval +Sets a timeout interval in seconds after which if no data has been received +from the client, +.Nm sshd +will send a message through the encrypted +channel to request a response from the client. +The default +is 0, indicating that these messages will not be sent to the client. +This option applies to protocol version 2 only. +.It Cm ClientAliveCountMax +Sets the number of client alive messages (see above) which may be +sent without +.Nm sshd +receiving any messages back from the client. +If this threshold is reached while client alive messages are being sent, +.Nm sshd +will disconnect the client, terminating the session. +It is important to note that the use of client alive messages is very +different from +.Cm TCPKeepAlive +(below). +The client alive messages are sent through the encrypted channel +and therefore will not be spoofable. +The TCP keepalive option enabled by +.Cm TCPKeepAlive +is spoofable. +The client alive mechanism is valuable when the client or +server depend on knowing when a connection has become inactive. +.Pp +The default value is 3. +If +.Cm ClientAliveInterval +(above) is set to 15, and +.Cm ClientAliveCountMax +is left at the default, unresponsive ssh clients +will be disconnected after approximately 45 seconds. +.It Cm Compression +Specifies whether compression is allowed. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq yes . +.It Cm DenyGroups +This keyword can be followed by a list of group name patterns, separated +by spaces. +Login is disallowed for users whose primary group or supplementary +group list matches one of the patterns. +.Ql \&* +and +.Ql \&? +can be used as +wildcards in the patterns. +Only group names are valid; a numerical group ID is not recognized. +By default, login is allowed for all groups. +.It Cm DenyUsers +This keyword can be followed by a list of user name patterns, separated +by spaces. +Login is disallowed for user names that match one of the patterns. +.Ql \&* +and +.Ql \&? +can be used as wildcards in the patterns. +Only user names are valid; a numerical user ID is not recognized. +By default, login is allowed for all users. +If the pattern takes the form USER@HOST then USER and HOST +are separately checked, restricting logins to particular +users from particular hosts. +.It Cm GatewayPorts +Specifies whether remote hosts are allowed to connect to ports +forwarded for the client. +By default, +.Nm sshd +binds remote port forwardings to the loopback address. +This prevents other remote hosts from connecting to forwarded ports. +.Cm GatewayPorts +can be used to specify that +.Nm sshd +should bind remote port forwardings to the wildcard address, +thus allowing remote hosts to connect to forwarded ports. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +.It Cm GSSAPIAuthentication +Specifies whether user authentication based on GSSAPI is allowed. +The default is +.Dq no . +Note that this option applies to protocol version 2 only. +.It Cm GSSAPICleanupCredentials +Specifies whether to automatically destroy the user's credentials cache +on logout. +The default is +.Dq yes . +Note that this option applies to protocol version 2 only. +.It Cm HostbasedAuthentication +Specifies whether rhosts or /etc/hosts.equiv authentication together +with successful public key client host authentication is allowed +(hostbased authentication). +This option is similar to +.Cm RhostsRSAAuthentication +and applies to protocol version 2 only. +The default is +.Dq no . +.It Cm HostKey +Specifies a file containing a private host key +used by SSH. +The default is +.Pa /etc/ssh/ssh_host_key +for protocol version 1, and +.Pa /etc/ssh/ssh_host_rsa_key +and +.Pa /etc/ssh/ssh_host_dsa_key +for protocol version 2. +Note that +.Nm sshd +will refuse to use a file if it is group/world-accessible. +It is possible to have multiple host key files. +.Dq rsa1 +keys are used for version 1 and +.Dq dsa +or +.Dq rsa +are used for version 2 of the SSH protocol. +.It Cm IgnoreRhosts +Specifies that +.Pa .rhosts +and +.Pa .shosts +files will not be used in +.Cm RhostsRSAAuthentication +or +.Cm HostbasedAuthentication . +.Pp +.Pa /etc/hosts.equiv +and +.Pa /etc/shosts.equiv +are still used. +The default is +.Dq yes . +.It Cm IgnoreUserKnownHosts +Specifies whether +.Nm sshd +should ignore the user's +.Pa $HOME/.ssh/known_hosts +during +.Cm RhostsRSAAuthentication +or +.Cm HostbasedAuthentication . +The default is +.Dq no . +.It Cm KerberosAuthentication +Specifies whether the password provided by the user for +.Cm PasswordAuthentication +will be validated through the Kerberos KDC. +To use this option, the server needs a +Kerberos servtab which allows the verification of the KDC's identity. +Default is +.Dq no . +.It Cm KerberosGetAFSToken +If AFS is active and the user has a Kerberos 5 TGT, attempt to aquire +an AFS token before accessing the user's home directory. +Default is +.Dq no . +.It Cm KerberosOrLocalPasswd +If set then if password authentication through Kerberos fails then +the password will be validated via any additional local mechanism +such as +.Pa /etc/passwd . +Default is +.Dq yes . +.It Cm KerberosTicketCleanup +Specifies whether to automatically destroy the user's ticket cache +file on logout. +Default is +.Dq yes . +.It Cm KeyRegenerationInterval +In protocol version 1, the ephemeral 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). +.It Cm ListenAddress +Specifies the local addresses +.Nm sshd +should listen on. +The following forms may be used: +.Pp +.Bl -item -offset indent -compact +.It +.Cm ListenAddress +.Sm off +.Ar host No | Ar IPv4_addr No | Ar IPv6_addr +.Sm on +.It +.Cm ListenAddress +.Sm off +.Ar host No | Ar IPv4_addr No : Ar port +.Sm on +.It +.Cm ListenAddress +.Sm off +.Oo +.Ar host No | Ar IPv6_addr Oc : Ar port +.Sm on +.El +.Pp +If +.Ar port +is not specified, +.Nm sshd +will listen on the address and all prior +.Cm Port +options specified. +The default is to listen on all local addresses. +Multiple +.Cm ListenAddress +options are permitted. +Additionally, any +.Cm Port +options must precede this option for non port qualified addresses. +.It Cm 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 120 seconds. +.It Cm LogLevel +Gives the verbosity level that is used when logging messages from +.Nm sshd . +The possible values are: +QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2 and DEBUG3. +The default is INFO. +DEBUG and DEBUG1 are equivalent. +DEBUG2 and DEBUG3 each specify higher levels of debugging output. +Logging with a DEBUG level violates the privacy of users and is not recommended. +.It Cm MACs +Specifies the available MAC (message authentication code) algorithms. +The MAC algorithm is used in protocol version 2 +for data integrity protection. +Multiple algorithms must be comma-separated. +The default is +.Dq hmac-md5,hmac-sha1,hmac-ripemd160,hmac-sha1-96,hmac-md5-96 . +.It Cm MaxAuthTries +Specifies the maximum number of authentication attempts permitted per +connection. +Once the number of failures reaches half this value, +additional failures are logged. +The default is 6. +.It Cm MaxStartups +Specifies the maximum number of concurrent unauthenticated connections to the +.Nm sshd +daemon. +Additional connections will be dropped until authentication succeeds or the +.Cm LoginGraceTime +expires for a connection. +The default is 10. +.Pp +Alternatively, random early drop can be enabled by specifying +the three colon separated values +.Dq start:rate:full +(e.g., "10:30:60"). +.Nm sshd +will refuse connection attempts with a probability of +.Dq rate/100 +(30%) +if there are currently +.Dq start +(10) +unauthenticated connections. +The probability increases linearly and all connection attempts +are refused if the number of unauthenticated connections reaches +.Dq full +(60). +.It Cm PasswordAuthentication +Specifies whether password authentication is allowed. +The default is +.Dq yes . +.It Cm PermitEmptyPasswords +When password authentication is allowed, it specifies whether the +server allows login to accounts with empty password strings. +The default is +.Dq no . +.It Cm PermitRootLogin +Specifies whether root can login using +.Xr ssh 1 . +The argument must be +.Dq yes , +.Dq without-password , +.Dq forced-commands-only +or +.Dq no . +The default is +.Dq yes . +.Pp +If this option is set to +.Dq without-password +password authentication is disabled for root. Note that other authentication +methods (e.g., keyboard-interactive/PAM) may still allow root to login using +a password. +.Pp +If this option is set to +.Dq forced-commands-only +root login with public key authentication will be allowed, +but only if the +.Ar command +option has been specified +(which may be useful for taking remote backups even if root login is +normally not allowed). +All other authentication methods are disabled for root. +.Pp +If this option is set to +.Dq no +root is not allowed to login. +.It Cm PermitUserEnvironment +Specifies whether +.Pa ~/.ssh/environment +and +.Cm environment= +options in +.Pa ~/.ssh/authorized_keys +are processed by +.Nm sshd . +The default is +.Dq no . +Enabling environment processing may enable users to bypass access +restrictions in some configurations using mechanisms such as +.Ev LD_PRELOAD . +.It Cm PidFile +Specifies the file that contains the process ID of the +.Nm sshd +daemon. +The default is +.Pa /var/run/sshd.pid . +.It Cm Port +Specifies the port number that +.Nm sshd +listens on. +The default is 22. +Multiple options of this type are permitted. +See also +.Cm ListenAddress . +.It Cm PrintLastLog +Specifies whether +.Nm sshd +should print the date and time when the user last logged in. +The default is +.Dq yes . +.It Cm PrintMotd +Specifies whether +.Nm sshd +should print +.Pa /etc/motd +when a user logs in interactively. +(On some systems it is also printed by the shell, +.Pa /etc/profile , +or equivalent.) +The default is +.Dq yes . +.It Cm Protocol +Specifies the protocol versions +.Nm sshd +supports. +The possible values are +.Dq 1 +and +.Dq 2 . +Multiple versions must be comma-separated. +The default is +.Dq 2,1 . +Note that the order of the protocol list does not indicate preference, +because the client selects among multiple protocol versions offered +by the server. +Specifying +.Dq 2,1 +is identical to +.Dq 1,2 . +.It Cm PubkeyAuthentication +Specifies whether public key authentication is allowed. +The default is +.Dq yes . +Note that this option applies to protocol version 2 only. +.It Cm RhostsRSAAuthentication +Specifies whether rhosts or /etc/hosts.equiv authentication together +with successful RSA host authentication is allowed. +The default is +.Dq no . +This option applies to protocol version 1 only. +.It Cm RSAAuthentication +Specifies whether pure RSA authentication is allowed. +The default is +.Dq yes . +This option applies to protocol version 1 only. +.It Cm ServerKeyBits +Defines the number of bits in the ephemeral protocol version 1 server key. +The minimum value is 512, and the default is 768. +.It Cm StrictModes +Specifies whether +.Nm sshd +should check file modes and ownership of the +user's files and home directory before accepting login. +This is normally desirable because novices sometimes accidentally leave their +directory or files world-writable. +The default is +.Dq yes . +.It Cm Subsystem +Configures an external subsystem (e.g., file transfer daemon). +Arguments should be a subsystem name and a command to execute upon subsystem +request. +The command +.Xr sftp-server 8 +implements the +.Dq sftp +file transfer subsystem. +By default no subsystems are defined. +Note that this option applies to protocol version 2 only. +.It Cm SyslogFacility +Gives the facility code that is used when logging messages from +.Nm sshd . +The possible values are: DAEMON, USER, AUTH, LOCAL0, LOCAL1, LOCAL2, +LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. +The default is AUTH. +.It Cm TCPKeepAlive +Specifies whether the system should send TCP 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 TCP keepalives are not sent, +sessions may hang indefinitely on the server, leaving +.Dq ghost +users and consuming server resources. +.Pp +The default is +.Dq yes +(to send TCP keepalive messages), and the server will notice +if the network goes down or the client host crashes. +This avoids infinitely hanging sessions. +.Pp +To disable TCP keepalive messages, the value should be set to +.Dq no . +.It Cm UseDNS +Specifies whether +.Nm sshd +should lookup the remote host name and check that +the resolved host name for the remote IP address maps back to the +very same IP address. +The default is +.Dq yes . +.It Cm UseLogin +Specifies whether +.Xr login 1 +is used for interactive login sessions. +The default is +.Dq no . +Note that +.Xr login 1 +is never used for remote command execution. +Note also, that if this is enabled, +.Cm X11Forwarding +will be disabled because +.Xr login 1 +does not know how to handle +.Xr xauth 1 +cookies. +If +.Cm UsePrivilegeSeparation +is specified, it will be disabled after authentication. +.It Cm UsePAM +Enables the Pluggable Authentication Module interface. +If set to +.Dq yes +this will enable PAM authentication using +.Cm ChallengeResponseAuthentication +and PAM account and session module processing for all authentication types. +.Pp +Because PAM challenge-response authentication usually serves an equivalent +role to password authentication, you should disable either +.Cm PasswordAuthentication +or +.Cm ChallengeResponseAuthentication. +.Pp +If +.Cm UsePAM +is enabled, you will not be able to run +.Xr sshd 8 +as a non-root user. +The default is +.Dq no . +.It Cm UsePrivilegeSeparation +Specifies whether +.Nm sshd +separates privileges by creating an unprivileged child process +to deal with incoming network traffic. +After successful authentication, another process will be created that has +the privilege of the authenticated user. +The goal of privilege separation is to prevent privilege +escalation by containing any corruption within the unprivileged processes. +The default is +.Dq yes . +.It Cm X11DisplayOffset +Specifies the first display number available for +.Nm sshd Ns 's +X11 forwarding. +This prevents +.Nm sshd +from interfering with real X11 servers. +The default is 10. +.It Cm X11Forwarding +Specifies whether X11 forwarding is permitted. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq no . +.Pp +When X11 forwarding is enabled, there may be additional exposure to +the server and to client displays if the +.Nm sshd +proxy display is configured to listen on the wildcard address (see +.Cm X11UseLocalhost +below), however this is not the default. +Additionally, the authentication spoofing and authentication data +verification and substitution occur on the client side. +The security risk of using X11 forwarding is that the client's X11 +display server may be exposed to attack when the ssh client requests +forwarding (see the warnings for +.Cm ForwardX11 +in +.Xr ssh_config 5 ) . +A system administrator may have a stance in which they want to +protect clients that may expose themselves to attack by unwittingly +requesting X11 forwarding, which can warrant a +.Dq no +setting. +.Pp +Note that disabling X11 forwarding does not prevent users from +forwarding X11 traffic, as users can always install their own forwarders. +X11 forwarding is automatically disabled if +.Cm UseLogin +is enabled. +.It Cm X11UseLocalhost +Specifies whether +.Nm sshd +should bind the X11 forwarding server to the loopback address or to +the wildcard address. +By default, +.Nm sshd +binds the forwarding server to the loopback address and sets the +hostname part of the +.Ev DISPLAY +environment variable to +.Dq localhost . +This prevents remote hosts from connecting to the proxy display. +However, some older X11 clients may not function with this +configuration. +.Cm X11UseLocalhost +may be set to +.Dq no +to specify that the forwarding server should be bound to the wildcard +address. +The argument must be +.Dq yes +or +.Dq no . +The default is +.Dq yes . +.It Cm XAuthLocation +Specifies the full pathname of the +.Xr xauth 1 +program. +The default is +.Pa /usr/X11R6/bin/xauth . +.El +.Ss Time Formats +.Nm sshd +command-line arguments and configuration file options that specify time +may be expressed using a sequence of the form: +.Sm off +.Ar time Op Ar qualifier , +.Sm on +where +.Ar time +is a positive integer value and +.Ar qualifier +is one of the following: +.Pp +.Bl -tag -width Ds -compact -offset indent +.It Cm +seconds +.It Cm s | Cm S +seconds +.It Cm m | Cm M +minutes +.It Cm h | Cm H +hours +.It Cm d | Cm D +days +.It Cm w | Cm W +weeks +.El +.Pp +Each member of the sequence is added together to calculate +the total time value. +.Pp +Time format examples: +.Pp +.Bl -tag -width Ds -compact -offset indent +.It 600 +600 seconds (10 minutes) +.It 10m +10 minutes +.It 1h30m +1 hour 30 minutes (90 minutes) +.El +.Sh FILES +.Bl -tag -width Ds +.It Pa /etc/ssh/sshd_config +Contains configuration data for +.Nm sshd . +This file should be writable by root only, but it is recommended +(though not necessary) that it be world-readable. +.El +.Sh SEE ALSO +.Xr sshd 8 +.Sh AUTHORS +OpenSSH is a derivative of the original and free +ssh 1.2.12 release by Tatu Ylonen. +Aaron Campbell, Bob Beck, Markus Friedl, Niels Provos, +Theo de Raadt and Dug Song +removed many bugs, re-added newer features and +created OpenSSH. +Markus Friedl contributed the support for SSH +protocol versions 1.5 and 2.0. +Niels Provos and Markus Friedl contributed support +for privilege separation. diff --git a/crypto/openssh-3.9p1/sshlogin.c b/crypto/openssh-3.9p1/sshlogin.c new file mode 100644 index 0000000000..15eb916d16 --- /dev/null +++ b/crypto/openssh-3.9p1/sshlogin.c @@ -0,0 +1,142 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * 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. + * + * 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". + * + * Copyright (c) 1999 Theo de Raadt. All rights reserved. + * Copyright (c) 1999 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: sshlogin.c,v 1.13 2004/08/12 09:18:24 djm Exp $"); + +#include "loginrec.h" +#include "log.h" +#include "buffer.h" +#include "servconf.h" + +extern Buffer loginmsg; +extern ServerOptions options; + +/* + * 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. + */ +u_long +get_last_login_time(uid_t uid, const char *logname, + char *buf, u_int bufsize) +{ + struct logininfo li; + + login_get_lastlog(&li, uid); + strlcpy(buf, li.hostname, bufsize); + return li.tv_sec; +} + +/* + * Generate and store last login message. This must be done before + * login_login() is called and lastlog is updated. + */ +static void +store_lastlog_message(const char *user, uid_t uid) +{ + char *time_string, hostname[MAXHOSTNAMELEN] = "", buf[512]; + time_t last_login_time; + +#ifndef NO_SSH_LASTLOG + if (!options.print_lastlog) + return; + + last_login_time = get_last_login_time(uid, user, hostname, + sizeof(hostname)); + + if (last_login_time != 0) { + time_string = ctime(&last_login_time); + if (strchr(time_string, '\n')) + *strchr(time_string, '\n') = '\0'; + if (strcmp(hostname, "") == 0) + snprintf(buf, sizeof(buf), "Last login: %s\r\n", + time_string); + else + snprintf(buf, sizeof(buf), "Last login: %s from %s\r\n", + time_string, hostname); + buffer_append(&loginmsg, buf, strlen(buf)); + } +#endif /* NO_SSH_LASTLOG */ +} + +/* + * Records that the user has logged in. I wish these parts of operating + * systems were more standardized. + */ +void +record_login(pid_t pid, const char *tty, const char *user, uid_t uid, + const char *host, struct sockaddr * addr, socklen_t addrlen) +{ + struct logininfo *li; + + /* save previous login details before writing new */ + store_lastlog_message(user, uid); + + li = login_alloc_entry(pid, user, host, tty); + login_set_addr(li, addr, addrlen); + login_login(li); + login_free_entry(li); +} + +#ifdef LOGIN_NEEDS_UTMPX +void +record_utmp_only(pid_t pid, const char *ttyname, const char *user, + const char *host, struct sockaddr * addr, socklen_t addrlen) +{ + struct logininfo *li; + + li = login_alloc_entry(pid, user, host, ttyname); + login_set_addr(li, addr, addrlen); + login_utmp_only(li); + login_free_entry(li); +} +#endif + +/* Records that the user has logged out. */ +void +record_logout(pid_t pid, const char *tty, const char *user) +{ + struct logininfo *li; + + li = login_alloc_entry(pid, user, NULL, tty); + login_logout(li); + login_free_entry(li); +} diff --git a/crypto/openssh-3.9p1/sshlogin.h b/crypto/openssh-3.9p1/sshlogin.h new file mode 100644 index 0000000000..1c8bfad323 --- /dev/null +++ b/crypto/openssh-3.9p1/sshlogin.h @@ -0,0 +1,28 @@ +/* $OpenBSD: sshlogin.h,v 1.4 2002/08/29 15:57:25 stevesk Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ +#ifndef SSHLOGIN_H +#define SSHLOGIN_H + +void +record_login(pid_t, const char *, const char *, uid_t, + const char *, struct sockaddr *, socklen_t); +void record_logout(pid_t, const char *, const char *); +u_long get_last_login_time(uid_t, const char *, char *, u_int); + +#ifdef LOGIN_NEEDS_UTMPX +void record_utmp_only(pid_t, const char *, const char *, const char *, + struct sockaddr *, socklen_t); +#endif + +#endif diff --git a/crypto/openssh-3.9p1/sshpty.c b/crypto/openssh-3.9p1/sshpty.c new file mode 100644 index 0000000000..efd1dfefa3 --- /dev/null +++ b/crypto/openssh-3.9p1/sshpty.c @@ -0,0 +1,228 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Allocating a pseudo-terminal, and making it the controlling tty. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: sshpty.c,v 1.12 2004/06/21 17:36:31 avsm Exp $"); + +#ifdef HAVE_UTIL_H +# include +#endif /* HAVE_UTIL_H */ + +#include "sshpty.h" +#include "log.h" +#include "misc.h" + +#ifdef HAVE_PTY_H +# include +#endif + +#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, int namebuflen) +{ + /* openpty(3) exists in OSF/1 and some other os'es */ + char *name; + int i; + + i = openpty(ptyfd, ttyfd, NULL, NULL, NULL); + if (i < 0) { + error("openpty: %.100s", strerror(errno)); + return 0; + } + name = ttyname(*ttyfd); + if (!name) + fatal("openpty returns device for which ttyname fails."); + + strlcpy(namebuf, name, namebuflen); /* possible truncation */ + return 1; +} + +/* Releases the tty. Its ownership is returned to root, and permissions to 0666. */ + +void +pty_release(const char *tty) +{ + if (chown(tty, (uid_t) 0, (gid_t) 0) < 0) + error("chown %.100s 0 0 failed: %.100s", tty, strerror(errno)); + if (chmod(tty, (mode_t) 0666) < 0) + error("chmod %.100s 0666 failed: %.100s", tty, strerror(errno)); +} + +/* Makes the tty the process's controlling tty and sets it to sane modes. */ + +void +pty_make_controlling_tty(int *ttyfd, const char *tty) +{ + int fd; +#ifdef USE_VHANGUP + void *old; +#endif /* USE_VHANGUP */ + +#ifdef _UNICOS + if (setsid() < 0) + error("setsid: %.100s", strerror(errno)); + + fd = open(tty, O_RDWR|O_NOCTTY); + if (fd != -1) { + signal(SIGHUP, SIG_IGN); + ioctl(fd, TCVHUP, (char *)NULL); + signal(SIGHUP, SIG_DFL); + setpgid(0, 0); + close(fd); + } else { + error("Failed to disconnect from controlling tty."); + } + + debug("Setting controlling tty using TCSETCTTY."); + ioctl(*ttyfd, TCSETCTTY, NULL); + fd = open("/dev/tty", O_RDWR); + if (fd < 0) + error("%.100s: %.100s", tty, strerror(errno)); + close(*ttyfd); + *ttyfd = fd; +#else /* _UNICOS */ + + /* First disconnect from the old controlling tty. */ +#ifdef TIOCNOTTY + fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); + if (fd >= 0) { + (void) ioctl(fd, TIOCNOTTY, NULL); + close(fd); + } +#endif /* TIOCNOTTY */ + if (setsid() < 0) + error("setsid: %.100s", strerror(errno)); + + /* + * Verify that we are successfully disconnected from the controlling + * tty. + */ + fd = open(_PATH_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."); + if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0) + error("ioctl(TIOCSCTTY): %.100s", strerror(errno)); +#endif /* TIOCSCTTY */ +#ifdef HAVE_NEWS4 + if (setpgrp(0,0) < 0) + error("SETPGRP %s",strerror(errno)); +#endif /* HAVE_NEWS4 */ +#ifdef USE_VHANGUP + old = signal(SIGHUP, SIG_IGN); + vhangup(); + signal(SIGHUP, old); +#endif /* USE_VHANGUP */ + fd = open(tty, O_RDWR); + if (fd < 0) { + error("%.100s: %.100s", tty, strerror(errno)); + } else { +#ifdef USE_VHANGUP + close(*ttyfd); + *ttyfd = fd; +#else /* USE_VHANGUP */ + close(fd); +#endif /* USE_VHANGUP */ + } + /* Verify that we now have a controlling tty. */ + fd = open(_PATH_TTY, O_WRONLY); + if (fd < 0) + error("open /dev/tty failed - could not set controlling tty: %.100s", + strerror(errno)); + else + close(fd); +#endif /* _UNICOS */ +} + +/* 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); +} + +void +pty_setowner(struct passwd *pw, const char *tty) +{ + struct group *grp; + gid_t gid; + mode_t mode; + struct stat st; + + /* Determine the group to make the owner of the tty. */ + grp = getgrnam("tty"); + if (grp) { + gid = grp->gr_gid; + mode = S_IRUSR | S_IWUSR | S_IWGRP; + } else { + gid = pw->pw_gid; + mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH; + } + + /* + * Change owner and mode of the tty as required. + * Warn but continue if filesystem is read-only and the uids match/ + * tty is owned by root. + */ + if (stat(tty, &st)) + fatal("stat(%.100s) failed: %.100s", tty, + strerror(errno)); + + if (st.st_uid != pw->pw_uid || st.st_gid != gid) { + if (chown(tty, pw->pw_uid, gid) < 0) { + if (errno == EROFS && + (st.st_uid == pw->pw_uid || st.st_uid == 0)) + debug("chown(%.100s, %u, %u) failed: %.100s", + tty, (u_int)pw->pw_uid, (u_int)gid, + strerror(errno)); + else + fatal("chown(%.100s, %u, %u) failed: %.100s", + tty, (u_int)pw->pw_uid, (u_int)gid, + strerror(errno)); + } + } + + if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) { + if (chmod(tty, mode) < 0) { + if (errno == EROFS && + (st.st_mode & (S_IRGRP | S_IROTH)) == 0) + debug("chmod(%.100s, 0%o) failed: %.100s", + tty, (u_int)mode, strerror(errno)); + else + fatal("chmod(%.100s, 0%o) failed: %.100s", + tty, (u_int)mode, strerror(errno)); + } + } +} diff --git a/crypto/openssh-3.9p1/sshpty.h b/crypto/openssh-3.9p1/sshpty.h new file mode 100644 index 0000000000..c0678de221 --- /dev/null +++ b/crypto/openssh-3.9p1/sshpty.h @@ -0,0 +1,30 @@ +/* $OpenBSD: sshpty.h,v 1.5 2004/05/08 00:01:37 deraadt Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Functions for allocating a pseudo-terminal and making it the controlling + * tty. + * + * 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". + */ + +#ifndef SSHPTY_H +#define SSHPTY_H + +struct termios get_saved_tio(void); +void leave_raw_mode(void); +void enter_raw_mode(void); + +int pty_allocate(int *, int *, char *, int); +void pty_release(const char *); +void pty_make_controlling_tty(int *, const char *); +void pty_change_window_size(int, int, int, int, int); +void pty_setowner(struct passwd *, const char *); + +#endif /* SSHPTY_H */ diff --git a/crypto/openssh-3.9p1/sshtty.c b/crypto/openssh-3.9p1/sshtty.c new file mode 100644 index 0000000000..0b17c3e2d8 --- /dev/null +++ b/crypto/openssh-3.9p1/sshtty.c @@ -0,0 +1,89 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: sshtty.c,v 1.6 2004/05/08 00:01:37 deraadt Exp $"); + +#include "sshpty.h" +#include "log.h" + +static struct termios _saved_tio; +static int _in_raw_mode = 0; + +struct termios +get_saved_tio(void) +{ + return _saved_tio; +} + +void +leave_raw_mode(void) +{ + if (!_in_raw_mode) + return; + if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) + perror("tcsetattr"); + else + _in_raw_mode = 0; +} + +void +enter_raw_mode(void) +{ + struct termios tio; + + if (tcgetattr(fileno(stdin), &tio) == -1) { + perror("tcgetattr"); + return; + } + _saved_tio = tio; + tio.c_iflag |= IGNPAR; + tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); +#ifdef IUCLC + tio.c_iflag &= ~IUCLC; +#endif + tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL); +#ifdef IEXTEN + tio.c_lflag &= ~IEXTEN; +#endif + tio.c_oflag &= ~OPOST; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1) + perror("tcsetattr"); + else + _in_raw_mode = 1; +} diff --git a/crypto/openssh-3.9p1/tildexpand.c b/crypto/openssh-3.9p1/tildexpand.c new file mode 100644 index 0000000000..cedb653b24 --- /dev/null +++ b/crypto/openssh-3.9p1/tildexpand.c @@ -0,0 +1,73 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: tildexpand.c,v 1.15 2004/05/21 08:43:03 markus Exp $"); + +#include "xmalloc.h" +#include "log.h" +#include "misc.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; + u_int userlen; + char *expanded; + struct passwd *pw; + char user[100]; + int len; + + /* Return immediately if no tilde. */ + if (filename[0] != '~') + return xstrdup(filename); + + /* Skip the tilde. */ + filename++; + + /* Find where the username ends. */ + cp = strchr(filename, '/'); + if (cp) + userlen = cp - filename; /* Something after username. */ + else + userlen = strlen(filename); /* Nothing 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); + } + 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. */ + len = strlen(pw->pw_dir) + strlen(cp + 1) + 2; + if (len > MAXPATHLEN) + fatal("Home directory too long (%d > %d", len-1, MAXPATHLEN-1); + expanded = xmalloc(len); + snprintf(expanded, len, "%s%s%s", pw->pw_dir, + strcmp(pw->pw_dir, "/") ? "/" : "", cp + 1); + return expanded; +} diff --git a/crypto/openssh-3.9p1/ttymodes.c b/crypto/openssh-3.9p1/ttymodes.c new file mode 100644 index 0000000000..c32e213a43 --- /dev/null +++ b/crypto/openssh-3.9p1/ttymodes.c @@ -0,0 +1,459 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +/* + * SSH2 tty modes support by Kevin Steves. + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * 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("$OpenBSD: ttymodes.c,v 1.19 2003/04/08 20:21:29 itojun Exp $"); + +#include "packet.h" +#include "log.h" +#include "ssh1.h" +#include "compat.h" +#include "buffer.h" +#include "bufaux.h" + +#define TTY_OP_END 0 +/* + * uint32 (u_int) follows speed in SSH1 and SSH2 + */ +#define TTY_OP_ISPEED_PROTO1 192 +#define TTY_OP_OSPEED_PROTO1 193 +#define TTY_OP_ISPEED_PROTO2 128 +#define TTY_OP_OSPEED_PROTO2 129 + +/* + * 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 + * or tiop in a portable manner, and appends the modes to a packet + * being constructed. + */ +void +tty_make_modes(int fd, struct termios *tiop) +{ + struct termios tio; + int baud; + Buffer buf; + int tty_op_ospeed, tty_op_ispeed; + void (*put_arg)(Buffer *, u_int); + + buffer_init(&buf); + if (compat20) { + tty_op_ospeed = TTY_OP_OSPEED_PROTO2; + tty_op_ispeed = TTY_OP_ISPEED_PROTO2; + put_arg = buffer_put_int; + } else { + tty_op_ospeed = TTY_OP_OSPEED_PROTO1; + tty_op_ispeed = TTY_OP_ISPEED_PROTO1; + put_arg = (void (*)(Buffer *, u_int)) buffer_put_char; + } + + if (tiop == NULL) { + if (tcgetattr(fd, &tio) == -1) { + logit("tcgetattr: %.100s", strerror(errno)); + goto end; + } + } else + tio = *tiop; + + /* Store input and output baud rates. */ + baud = speed_to_baud(cfgetospeed(&tio)); + debug3("tty_make_modes: ospeed %d", baud); + buffer_put_char(&buf, tty_op_ospeed); + buffer_put_int(&buf, baud); + baud = speed_to_baud(cfgetispeed(&tio)); + debug3("tty_make_modes: ispeed %d", baud); + buffer_put_char(&buf, tty_op_ispeed); + buffer_put_int(&buf, baud); + + /* Store values of mode flags. */ +#define TTYCHAR(NAME, OP) \ + debug3("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \ + buffer_put_char(&buf, OP); \ + put_arg(&buf, tio.c_cc[NAME]); + +#define TTYMODE(NAME, FIELD, OP) \ + debug3("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \ + buffer_put_char(&buf, OP); \ + put_arg(&buf, ((tio.FIELD & NAME) != 0)); + +#include "ttymodes.h" + +#undef TTYCHAR +#undef TTYMODE + +end: + /* Mark end of mode data. */ + buffer_put_char(&buf, TTY_OP_END); + if (compat20) + packet_put_string(buffer_ptr(&buf), buffer_len(&buf)); + else + packet_put_raw(buffer_ptr(&buf), buffer_len(&buf)); + buffer_free(&buf); +} + +/* + * 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) +{ + struct termios tio; + int opcode, baud; + int n_bytes = 0; + int failure = 0; + u_int (*get_arg)(void); + int arg, arg_size; + + if (compat20) { + *n_bytes_ptr = packet_get_int(); + debug3("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr); + if (*n_bytes_ptr == 0) + return; + get_arg = packet_get_int; + arg_size = 4; + } else { + get_arg = packet_get_char; + arg_size = 1; + } + + /* + * 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. + */ + if (tcgetattr(fd, &tio) == -1) { + logit("tcgetattr: %.100s", strerror(errno)); + failure = -1; + } + + for (;;) { + n_bytes += 1; + opcode = packet_get_char(); + switch (opcode) { + case TTY_OP_END: + goto set; + + /* XXX: future conflict possible */ + case TTY_OP_ISPEED_PROTO1: + case TTY_OP_ISPEED_PROTO2: + n_bytes += 4; + baud = packet_get_int(); + debug3("tty_parse_modes: ispeed %d", baud); + if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) == -1) + error("cfsetispeed failed for %d", baud); + break; + + /* XXX: future conflict possible */ + case TTY_OP_OSPEED_PROTO1: + case TTY_OP_OSPEED_PROTO2: + n_bytes += 4; + baud = packet_get_int(); + debug3("tty_parse_modes: ospeed %d", baud); + if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) == -1) + error("cfsetospeed failed for %d", baud); + break; + +#define TTYCHAR(NAME, OP) \ + case OP: \ + n_bytes += arg_size; \ + tio.c_cc[NAME] = get_arg(); \ + debug3("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \ + break; +#define TTYMODE(NAME, FIELD, OP) \ + case OP: \ + n_bytes += arg_size; \ + if ((arg = get_arg())) \ + tio.FIELD |= NAME; \ + else \ + tio.FIELD &= ~NAME; \ + debug3("tty_parse_modes: %d %d", OP, arg); \ + break; + +#include "ttymodes.h" + +#undef TTYCHAR +#undef TTYMODE + + default: + debug("Ignoring unsupported tty mode opcode %d (0x%x)", + opcode, opcode); + if (!compat20) { + /* + * SSH1: + * Opcodes 1 to 127 are defined to have + * a one-byte argument. + * Opcodes 128 to 159 are defined to have + * an integer argument. + */ + if (opcode > 0 && opcode < 128) { + n_bytes += 1; + (void) packet_get_char(); + break; + } else if (opcode >= 128 && opcode < 160) { + n_bytes += 4; + (void) packet_get_int(); + break; + } else { + /* + * 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. + */ + logit("parse_tty_modes: unknown opcode %d", opcode); + goto set; + } + } else { + /* + * SSH2: + * Opcodes 1 to 159 are defined to have + * a uint32 argument. + * Opcodes 160 to 255 are undefined and + * cause parsing to stop. + */ + if (opcode > 0 && opcode < 160) { + n_bytes += 4; + (void) packet_get_int(); + break; + } else { + logit("parse_tty_modes: unknown opcode %d", opcode); + goto set; + } + } + } + } + +set: + if (*n_bytes_ptr != n_bytes) { + *n_bytes_ptr = n_bytes; + logit("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d", + *n_bytes_ptr, n_bytes); + return; /* Don't process bytes passed */ + } + if (failure == -1) + return; /* Packet parsed ok but tcgetattr() failed */ + + /* Set the new modes for the terminal. */ + if (tcsetattr(fd, TCSANOW, &tio) == -1) + logit("Setting tty modes failed: %.100s", strerror(errno)); +} diff --git a/crypto/openssh-3.9p1/ttymodes.h b/crypto/openssh-3.9p1/ttymodes.h new file mode 100644 index 0000000000..481282cd70 --- /dev/null +++ b/crypto/openssh-3.9p1/ttymodes.h @@ -0,0 +1,175 @@ +/* $OpenBSD: ttymodes.h,v 1.13 2004/07/11 17:48:47 deraadt Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +/* + * SSH2 tty modes support by Kevin Steves. + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * SSH1: + * 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). + * + * SSH2: + * Differences between SSH1 and SSH2 terminal mode encoding include: + * 1. Encoded terminal modes are represented as a string, and a stream + * of bytes within that string. + * 2. Opcode arguments are uint32 (1-159); 160-255 remain undefined. + * 3. The values for TTY_OP_ISPEED and TTY_OP_OSPEED are different; + * 128 and 129 vs. 192 and 193 respectively. + * + * 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.c. + */ + +/* termios macro */ +/* name, op */ +TTYCHAR(VINTR, 1) +TTYCHAR(VQUIT, 2) +TTYCHAR(VERASE, 3) +#if defined(VKILL) +TTYCHAR(VKILL, 4) +#endif /* VKILL */ +TTYCHAR(VEOF, 5) +#if defined(VEOL) +TTYCHAR(VEOL, 6) +#endif /* VEOL */ +#ifdef VEOL2 +TTYCHAR(VEOL2, 7) +#endif /* VEOL2 */ +TTYCHAR(VSTART, 8) +TTYCHAR(VSTOP, 9) +#if defined(VSUSP) +TTYCHAR(VSUSP, 10) +#endif /* VSUSP */ +#if defined(VDSUSP) +TTYCHAR(VDSUSP, 11) +#endif /* VDSUSP */ +#if defined(VREPRINT) +TTYCHAR(VREPRINT, 12) +#endif /* VREPRINT */ +#if defined(VWERASE) +TTYCHAR(VWERASE, 13) +#endif /* VWERASE */ +#if defined(VLNEXT) +TTYCHAR(VLNEXT, 14) +#endif /* VLNEXT */ +#if defined(VFLUSH) +TTYCHAR(VFLUSH, 15) +#endif /* VFLUSH */ +#ifdef VSWTCH +TTYCHAR(VSWTCH, 16) +#endif /* VSWTCH */ +#if defined(VSTATUS) +TTYCHAR(VSTATUS, 17) +#endif /* VSTATUS */ +#ifdef VDISCARD +TTYCHAR(VDISCARD, 18) +#endif /* VDISCARD */ + +/* name, field, op */ +TTYMODE(IGNPAR, c_iflag, 30) +TTYMODE(PARMRK, c_iflag, 31) +TTYMODE(INPCK, c_iflag, 32) +TTYMODE(ISTRIP, c_iflag, 33) +TTYMODE(INLCR, c_iflag, 34) +TTYMODE(IGNCR, c_iflag, 35) +TTYMODE(ICRNL, c_iflag, 36) +#if defined(IUCLC) +TTYMODE(IUCLC, c_iflag, 37) +#endif +TTYMODE(IXON, c_iflag, 38) +TTYMODE(IXANY, c_iflag, 39) +TTYMODE(IXOFF, c_iflag, 40) +#ifdef IMAXBEL +TTYMODE(IMAXBEL,c_iflag, 41) +#endif /* IMAXBEL */ + +TTYMODE(ISIG, c_lflag, 50) +TTYMODE(ICANON, c_lflag, 51) +#ifdef XCASE +TTYMODE(XCASE, c_lflag, 52) +#endif +TTYMODE(ECHO, c_lflag, 53) +TTYMODE(ECHOE, c_lflag, 54) +TTYMODE(ECHOK, c_lflag, 55) +TTYMODE(ECHONL, c_lflag, 56) +TTYMODE(NOFLSH, c_lflag, 57) +TTYMODE(TOSTOP, c_lflag, 58) +#ifdef IEXTEN +TTYMODE(IEXTEN, c_lflag, 59) +#endif /* IEXTEN */ +#if defined(ECHOCTL) +TTYMODE(ECHOCTL,c_lflag, 60) +#endif /* ECHOCTL */ +#ifdef ECHOKE +TTYMODE(ECHOKE, c_lflag, 61) +#endif /* ECHOKE */ +#if defined(PENDIN) +TTYMODE(PENDIN, c_lflag, 62) +#endif /* PENDIN */ + +TTYMODE(OPOST, c_oflag, 70) +#if defined(OLCUC) +TTYMODE(OLCUC, c_oflag, 71) +#endif +#ifdef ONLCR +TTYMODE(ONLCR, c_oflag, 72) +#endif +#ifdef OCRNL +TTYMODE(OCRNL, c_oflag, 73) +#endif +#ifdef ONOCR +TTYMODE(ONOCR, c_oflag, 74) +#endif +#ifdef ONLRET +TTYMODE(ONLRET, c_oflag, 75) +#endif + +TTYMODE(CS7, c_cflag, 90) +TTYMODE(CS8, c_cflag, 91) +TTYMODE(PARENB, c_cflag, 92) +TTYMODE(PARODD, c_cflag, 93) diff --git a/crypto/openssh-3.9p1/uidswap.c b/crypto/openssh-3.9p1/uidswap.c new file mode 100644 index 0000000000..44c4cb626c --- /dev/null +++ b/crypto/openssh-3.9p1/uidswap.c @@ -0,0 +1,228 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Code for uid-swapping. + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: uidswap.c,v 1.24 2003/05/29 16:58:45 deraadt Exp $"); + +#include "log.h" +#include "uidswap.h" +#include "xmalloc.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. + */ + +#if defined(_POSIX_SAVED_IDS) && !defined(BROKEN_SAVED_UIDS) +/* 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 +/* Saved effective uid. */ +static uid_t saved_euid = 0; +static gid_t saved_egid = 0; +#endif + +/* Saved effective uid. */ +static int privileged = 0; +static int temporarily_use_uid_effective = 0; +static gid_t *saved_egroups = NULL, *user_groups = NULL; +static int saved_egroupslen = -1, user_groupslen = -1; + +/* + * 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(struct passwd *pw) +{ + /* Save the current euid, and egroups. */ +#ifdef SAVED_IDS_WORK_WITH_SETEUID + saved_euid = geteuid(); + saved_egid = getegid(); + debug("temporarily_use_uid: %u/%u (e=%u/%u)", + (u_int)pw->pw_uid, (u_int)pw->pw_gid, + (u_int)saved_euid, (u_int)saved_egid); + if (saved_euid != 0) { + privileged = 0; + return; + } +#else + if (geteuid() != 0) { + privileged = 0; + return; + } +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ + + privileged = 1; + temporarily_use_uid_effective = 1; + + saved_egroupslen = getgroups(0, NULL); + if (saved_egroupslen < 0) + fatal("getgroups: %.100s", strerror(errno)); + if (saved_egroupslen > 0) { + saved_egroups = xrealloc(saved_egroups, + saved_egroupslen * sizeof(gid_t)); + if (getgroups(saved_egroupslen, saved_egroups) < 0) + fatal("getgroups: %.100s", strerror(errno)); + } else { /* saved_egroupslen == 0 */ + if (saved_egroups != NULL) + xfree(saved_egroups); + } + + /* set and save the user's groups */ + if (user_groupslen == -1) { + if (initgroups(pw->pw_name, pw->pw_gid) < 0) + fatal("initgroups: %s: %.100s", pw->pw_name, + strerror(errno)); + + user_groupslen = getgroups(0, NULL); + if (user_groupslen < 0) + fatal("getgroups: %.100s", strerror(errno)); + if (user_groupslen > 0) { + user_groups = xrealloc(user_groups, + user_groupslen * sizeof(gid_t)); + if (getgroups(user_groupslen, user_groups) < 0) + fatal("getgroups: %.100s", strerror(errno)); + } else { /* user_groupslen == 0 */ + if (user_groups) + xfree(user_groups); + } + } + /* Set the effective uid to the given (unprivileged) uid. */ + if (setgroups(user_groupslen, user_groups) < 0) + fatal("setgroups: %.100s", strerror(errno)); +#ifndef SAVED_IDS_WORK_WITH_SETEUID + /* Propagate the privileged gid to all of our gids. */ + if (setgid(getegid()) < 0) + debug("setgid %u: %.100s", (u_int) getegid(), strerror(errno)); + /* Propagate the privileged uid to all of our uids. */ + if (setuid(geteuid()) < 0) + debug("setuid %u: %.100s", (u_int) geteuid(), strerror(errno)); +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ + if (setegid(pw->pw_gid) < 0) + fatal("setegid %u: %.100s", (u_int)pw->pw_gid, + strerror(errno)); + if (seteuid(pw->pw_uid) == -1) + fatal("seteuid %u: %.100s", (u_int)pw->pw_uid, + strerror(errno)); +} + +/* + * Restores to the original (privileged) uid. + */ +void +restore_uid(void) +{ + /* it's a no-op unless privileged */ + if (!privileged) { + debug("restore_uid: (unprivileged)"); + return; + } + if (!temporarily_use_uid_effective) + fatal("restore_uid: temporarily_use_uid not effective"); + +#ifdef SAVED_IDS_WORK_WITH_SETEUID + debug("restore_uid: %u/%u", (u_int)saved_euid, (u_int)saved_egid); + /* Set the effective uid back to the saved privileged uid. */ + if (seteuid(saved_euid) < 0) + fatal("seteuid %u: %.100s", (u_int)saved_euid, strerror(errno)); + if (setegid(saved_egid) < 0) + fatal("setegid %u: %.100s", (u_int)saved_egid, 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()); + setgid(getgid()); +#endif /* SAVED_IDS_WORK_WITH_SETEUID */ + + if (setgroups(saved_egroupslen, saved_egroups) < 0) + fatal("setgroups: %.100s", strerror(errno)); + temporarily_use_uid_effective = 0; +} + +/* + * Permanently sets all uids to the given uid. This cannot be + * called while temporarily_use_uid is effective. + */ +void +permanently_set_uid(struct passwd *pw) +{ + uid_t old_uid = getuid(); + gid_t old_gid = getgid(); + + if (temporarily_use_uid_effective) + fatal("permanently_set_uid: temporarily_use_uid effective"); + debug("permanently_set_uid: %u/%u", (u_int)pw->pw_uid, + (u_int)pw->pw_gid); + +#if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) + if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0) + fatal("setresgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); +#elif defined(HAVE_SETREGID) && !defined(BROKEN_SETREGID) + if (setregid(pw->pw_gid, pw->pw_gid) < 0) + fatal("setregid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); +#else + if (setegid(pw->pw_gid) < 0) + fatal("setegid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); + if (setgid(pw->pw_gid) < 0) + fatal("setgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); +#endif + +#if defined(HAVE_SETRESUID) && !defined(BROKEN_SETRESUID) + if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) + fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); +#elif defined(HAVE_SETREUID) && !defined(BROKEN_SETREUID) + if (setreuid(pw->pw_uid, pw->pw_uid) < 0) + fatal("setreuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); +#else +# ifndef SETEUID_BREAKS_SETUID + if (seteuid(pw->pw_uid) < 0) + fatal("seteuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); +# endif + if (setuid(pw->pw_uid) < 0) + fatal("setuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); +#endif + + /* Try restoration of GID if changed (test clearing of saved gid) */ + if (old_gid != pw->pw_gid && + (setgid(old_gid) != -1 || setegid(old_gid) != -1)) + fatal("%s: was able to restore old [e]gid", __func__); + + /* Verify GID drop was successful */ + if (getgid() != pw->pw_gid || getegid() != pw->pw_gid) { + fatal("%s: egid incorrect gid:%u egid:%u (should be %u)", + __func__, (u_int)getgid(), (u_int)getegid(), + (u_int)pw->pw_gid); + } + +#ifndef HAVE_CYGWIN + /* Try restoration of UID if changed (test clearing of saved uid) */ + if (old_uid != pw->pw_uid && + (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) + fatal("%s: was able to restore old [e]uid", __func__); +#endif + + /* Verify UID drop was successful */ + if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) { + fatal("%s: euid incorrect uid:%u euid:%u (should be %u)", + __func__, (u_int)getuid(), (u_int)geteuid(), + (u_int)pw->pw_uid); + } +} diff --git a/crypto/openssh-3.9p1/uidswap.h b/crypto/openssh-3.9p1/uidswap.h new file mode 100644 index 0000000000..0726980d08 --- /dev/null +++ b/crypto/openssh-3.9p1/uidswap.h @@ -0,0 +1,22 @@ +/* $OpenBSD: uidswap.h,v 1.9 2001/06/26 17:27:25 markus Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * + * 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". + */ + +#ifndef UIDSWAP_H +#define UIDSWAP_H + +void temporarily_use_uid(struct passwd *); +void restore_uid(void); +void permanently_set_uid(struct passwd *); + +#endif /* UIDSWAP_H */ diff --git a/crypto/openssh-3.9p1/uuencode.c b/crypto/openssh-3.9p1/uuencode.c new file mode 100644 index 0000000000..0a7c8d16af --- /dev/null +++ b/crypto/openssh-3.9p1/uuencode.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "includes.h" +RCSID("$OpenBSD: uuencode.c,v 1.17 2003/11/10 16:23:41 jakob Exp $"); + +#include "xmalloc.h" +#include "uuencode.h" + +int +uuencode(const u_char *src, u_int srclength, + char *target, size_t targsize) +{ + return __b64_ntop(src, srclength, target, targsize); +} + +int +uudecode(const char *src, u_char *target, size_t targsize) +{ + int len; + char *encoded, *p; + + /* copy the 'readonly' source */ + encoded = xstrdup(src); + /* skip whitespace and data */ + for (p = encoded; *p == ' ' || *p == '\t'; p++) + ; + for (; *p != '\0' && *p != ' ' && *p != '\t'; p++) + ; + /* and remove trailing whitespace because __b64_pton needs this */ + *p = '\0'; + len = __b64_pton(encoded, target, targsize); + xfree(encoded); + return len; +} + +void +dump_base64(FILE *fp, u_char *data, u_int len) +{ + char *buf = xmalloc(2*len); + int i, n; + + n = uuencode(data, len, buf, 2*len); + for (i = 0; i < n; i++) { + fprintf(fp, "%c", buf[i]); + if (i % 70 == 69) + fprintf(fp, "\n"); + } + if (i % 70 != 69) + fprintf(fp, "\n"); + xfree(buf); +} diff --git a/crypto/openssh-3.9p1/uuencode.h b/crypto/openssh-3.9p1/uuencode.h new file mode 100644 index 0000000000..08e87c4bcc --- /dev/null +++ b/crypto/openssh-3.9p1/uuencode.h @@ -0,0 +1,32 @@ +/* $OpenBSD: uuencode.h,v 1.10 2003/11/10 16:23:41 jakob Exp $ */ + +/* + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UUENCODE_H +#define UUENCODE_H +int uuencode(const u_char *, u_int, char *, size_t); +int uudecode(const char *, u_char *, size_t); +void dump_base64(FILE *, u_char *, u_int); +#endif diff --git a/crypto/openssh-3.9p1/xmalloc.c b/crypto/openssh-3.9p1/xmalloc.c new file mode 100644 index 0000000000..99c6ac3301 --- /dev/null +++ b/crypto/openssh-3.9p1/xmalloc.c @@ -0,0 +1,68 @@ +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Versions of malloc and friends that check their results, and never return + * failure (they call fatal if they encounter an error). + * + * 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". + */ + +#include "includes.h" +RCSID("$OpenBSD: xmalloc.c,v 1.16 2001/07/23 18:21:46 stevesk Exp $"); + +#include "xmalloc.h" +#include "log.h" + +void * +xmalloc(size_t size) +{ + void *ptr; + + if (size == 0) + fatal("xmalloc: zero size"); + ptr = malloc(size); + if (ptr == NULL) + fatal("xmalloc: out of memory (allocating %lu bytes)", (u_long) size); + return ptr; +} + +void * +xrealloc(void *ptr, size_t new_size) +{ + void *new_ptr; + + if (new_size == 0) + fatal("xrealloc: zero size"); + if (ptr == NULL) + new_ptr = malloc(new_size); + else + new_ptr = realloc(ptr, new_size); + if (new_ptr == NULL) + fatal("xrealloc: out of memory (new_size %lu bytes)", (u_long) 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) +{ + size_t len; + char *cp; + + len = strlen(str) + 1; + cp = xmalloc(len); + strlcpy(cp, str, len); + return cp; +} diff --git a/crypto/openssh-3.9p1/xmalloc.h b/crypto/openssh-3.9p1/xmalloc.h new file mode 100644 index 0000000000..7ac4b13d64 --- /dev/null +++ b/crypto/openssh-3.9p1/xmalloc.h @@ -0,0 +1,27 @@ +/* $OpenBSD: xmalloc.h,v 1.9 2002/06/19 00:27:55 deraadt Exp $ */ + +/* + * Author: Tatu Ylonen + * Copyright (c) 1995 Tatu Ylonen , 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). + * + * 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". + */ + +#ifndef XMALLOC_H +#define XMALLOC_H + +void *xmalloc(size_t); +void *xrealloc(void *, size_t); +void xfree(void *); +char *xstrdup(const char *); + +#endif /* XMALLOC_H */