From 8d55d19095a73ae7a6c44effa92f447bccd4ac5c Mon Sep 17 00:00:00 2001 From: Brian Feldman Date: Thu, 13 Jan 2000 23:22:17 +0000 Subject: [PATCH] Update to a more current OpenSSH, including... IPv6 support!! Thank you very much, Sumikawa san. Submitted by: Munechika SUMIKAWA --- security/openssh/Makefile | 11 +- security/openssh/distinfo | 44 +- security/openssh/files/bindresvport.c | 151 +++ security/openssh/files/getaddrinfo.c | 1024 ++++++++++++++++++++ security/openssh/files/getnameinfo.c | 228 +++++ security/openssh/files/name6.c | 1262 +++++++++++++++++++++++++ security/openssh/files/netdb.h | 259 +++++ security/openssh/files/patch-ab | 9 +- security/openssh/files/patch-ac | 38 +- security/openssh/files/patch-ad | 12 +- security/openssh/files/patch-an | 78 +- security/openssh/files/patch-ao | 10 +- security/openssh/files/patch-at | 14 + security/openssh/files/rcmd.c | 653 +++++++++++++ 14 files changed, 3717 insertions(+), 76 deletions(-) create mode 100644 security/openssh/files/bindresvport.c create mode 100644 security/openssh/files/getaddrinfo.c create mode 100644 security/openssh/files/getnameinfo.c create mode 100644 security/openssh/files/name6.c create mode 100644 security/openssh/files/netdb.h create mode 100644 security/openssh/files/patch-at create mode 100644 security/openssh/files/rcmd.c diff --git a/security/openssh/Makefile b/security/openssh/Makefile index 5c6e61ac8445..052b25b1dcd3 100644 --- a/security/openssh/Makefile +++ b/security/openssh/Makefile @@ -23,7 +23,7 @@ CAT?= /bin/cat DISTFILES!= ${CAT} ${FILESDIR}/distfiles CVS_CMD?= cvs -z3 -CVS_DATE= Thu Dec 23 01:07:56 EST 1999 +CVS_DATE= Fri Jan 7 01:25:49 JST 2000 SED?= /usr/bin/sed CVS_DATE_!= ${ECHO} -n "${CVS_DATE}" | ${SED} 's/[ \t:]/_/g' CVS_SITES= anoncvs@anoncvs1.ca.openbsd.org:/cvs \ @@ -34,6 +34,9 @@ CRYPTOLIBS+= -lRSAglue -lrsaref .endif # Here, MANDIR is concetenated to DESTDIR which all forms the man install dir... MAKE_ENV= DESTDIR=${PREFIX} MANDIR=/man/man CRYPTOLIBS="${CRYPTOLIBS}" +.if defined(USE_INET6) +MAKE_ENV+= USET_INET6=yes +.endif .if !exists(/usr/include/tcpd.h) MAKE_ENV+= TCP_WRAPPERS=no .endif @@ -113,6 +116,12 @@ do-extract: @${MKDIR} ${WRKDIR} @${CP} -r ${DISTDIR}/${PKGNAME}/${DISTNAME} ${WRKDIR} @${CP} ${FILESDIR}/strlcat.c ${FILESDIR}/strlcpy.c ${WRKSRC}/lib/ +.if !defined(USE_INET6) + @${CP} ${FILESDIR}/getaddrinfo.c ${FILESDIR}/name6.c ${WRKSRC}/lib/ + @${CP} ${FILESDIR}/bindresvport.c ${FILESDIR}/rcmd.c ${WRKSRC}/lib/ + @${CP} ${FILESDIR}/getnameinfo.c ${FILESDIR}/rcmd.c ${WRKSRC}/lib/ + @${CP} ${FILESDIR}/netdb.h ${WRKSRC}/ +.endif @${MKDIR} ${WRKSRC}/pam_ssh @${CP} ${FILESDIR}/pam_ssh_Makefile ${WRKSRC}/pam_ssh/Makefile @${CP} ${FILESDIR}/pam_ssh.c ${WRKSRC}/pam_ssh/ diff --git a/security/openssh/distinfo b/security/openssh/distinfo index b1240d5bbf1c..8f75ea9de002 100644 --- a/security/openssh/distinfo +++ b/security/openssh/distinfo @@ -6,9 +6,9 @@ MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/README) = e54fb9189053db5ad25892054c8d0989 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/RFC.nroff) = 1615f30810a3d47716883b2eaddd712c MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/atomicio.c) = 765037b689925ccd476de647d4aaf9ed MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/auth-krb4.c) = e9f588343a4954004ecbf7ba805edde2 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/auth-passwd.c) = ad6e1b7a3e64d3de451b319a3bdda823 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/auth-passwd.c) = 176629d0f658f24120a5710c9b5a84d8 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/auth-rh-rsa.c) = a1c4177fb07f7dcc4dbe6c468bab608e -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/auth-rhosts.c) = 50c042e1a659782bba7e1edd7c43c233 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/auth-rhosts.c) = 2df099d85d31d7346cba663a45592c91 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/auth-rsa.c) = 1c3d74a611cda703b133112123a677c1 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/auth-skey.c) = 1c003cb98aea4e771a9ec3e67dd99096 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/authfd.c) = 08ebd5cb6fd9521ead44475a59880ea9 @@ -18,8 +18,8 @@ MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/bufaux.c) = 877a21dbdd68ef04a1e39a0e6d34450e MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/bufaux.h) = 46caf1274857d0bdc5eabe60d56f6aaf MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/buffer.c) = 6cea321387c23d5cfaefca38bc167c1f MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/buffer.h) = c284a258593ae4d8905d94ddae45f4b1 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/canohost.c) = d138b179904396b30bba07a3d96bc3f1 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/channels.c) = 21569b184aca98f6a53723b647ea2227 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/canohost.c) = 4ebd799aac04aa6c0e23d0c1e27e9ea6 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/channels.c) = a646f9209452b8993ff4b547e6e1f945 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/channels.h) = e597ecd2255e0f92fb5a92c40c99d8b4 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/cipher.c) = 2bf8f287540f2448b4af0b894aeacf8b MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/cipher.h) = e1b48bd7a4e37c1b106f968d8377b843 @@ -35,21 +35,21 @@ MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/deattack.h) = db63f71b6c19484dd8ce5041cc6b646 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/fingerprint.c) = 782318f23ec96a679f140a475ee38638 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/fingerprint.h) = 17d73906c4f0c1cddb3c1c7e98d02785 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/getput.h) = bf729289671363abc3882e1e0c34d270 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/hostfile.c) = df76ac8ab45dc2bd796b3b0af16fcbef +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/hostfile.c) = a165685e4989eb99d31a84eba3acb55c MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/includes.h) = 1dc9df93b0be59b6351755ea7817be09 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/lib/Makefile) = 66b181f50f06eb76ecc6c59acf0f3068 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/log-client.c) = a05d3671346fd5a958cc74d1e2416b63 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/log-server.c) = d1c4f02578b1a83c972b7acd04ea2fa2 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/log.c) = 8389216c70241d8858fd4b4029361166 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/login.c) = e6d2ed8545050d71606b4b857c35af5f +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/log.c) = 40cc9c89526c10ef6cb2c46c0258727e +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/login.c) = ab361f9b7f5bccae2ca67c55445353a0 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/match.c) = facc507e6b48d09f9df77c2a77b365c3 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/mpaux.c) = 50ebda88832e2852c1bab39e5e5ac5bb MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/mpaux.h) = 3dd5ddaa6baccf7f38964e69cd2f9e1c MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/nchan.c) = 63c2980438954303525580ebcebc0d11 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/nchan.h) = 884bb0c2b62f274ccbf9c0eafc9d37c2 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/nchan.ms) = 815e166dc85a329c3cfd98bd8cfda930 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/packet.c) = 280c43c49ee1ec3fa14f75268471d3fe -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/packet.h) = 52811069d035c6900113732bf22e1456 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/packet.c) = 12dbfde0eec29e953e5718469c756e65 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/packet.h) = a2889cb1db9ae9e8833a8746e7e3cc18 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/pty.c) = 42defbf1571c948865056a06d976235f MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/pty.h) = f2fb71af9954aebec8b3b69320dd6d12 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/radix.c) = 599f6349035451d48e36334b21696963 @@ -58,31 +58,31 @@ MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/readconf.h) = 9f40c6fa01b174149efbaad4bf21c33 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/readpass.c) = 282110d41691d426501a24a36c1efd03 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/rsa.c) = 3b47f0c260e26c118d971fafed604d3f MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/rsa.h) = ee65e38f1fcc22328c5d5f07b57d6e5f -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/scp.1) = a9144b2b272d8ac656b1d63c71644999 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/scp.c) = 29ced969b9c1d05f42bfb07b238a8543 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/scp.1) = 939fd8b3eb1965e081e557fcd069b89e +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/scp.c) = 84865c7072e67bab6900fc814e666e8d MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/scp/Makefile) = 5cb4c5fcabde5ccc4f9ca475ac3452f4 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/servconf.c) = 62079877f586c06b71c384e556a78be2 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/servconf.h) = 056da4377475fbcded1ca288a1faf26e +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/servconf.c) = 2a4ae4323190d562b1bf5406822c7f43 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/servconf.h) = 70595ee9c1fb106695343787e1696bce MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/serverloop.c) = b2282cf4f899b132134d783f691a2fca MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-add.1) = 46ee567cafbde041222984ddead7bd51 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-add.c) = b2bcb9fcac8725699faaf8f2d8e6894c MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-add/Makefile) = f780e2e9fb5c32d2118ba0e612d681e0 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-agent.1) = 33b62903d3aa452fa106b484b016bbc5 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-agent.c) = 20f70bcc11320a47fb847c4c83bd7d1a +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-agent.c) = 5bdf7f32d33ceb9dab8f3b0516e3b012 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-agent/Makefile) = c7ec7c4e61b4da3369980f197fdcb501 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-keygen.1) = 746734eab948fff84a44c3383f5a1701 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-keygen.1) = 81623b151c4a8090f6ea1151d8662f5a MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-keygen.c) = 439aac7630c0dc54b750ecbe314bc09b MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh-keygen/Makefile) = 2d597b6e6458d0c0246ba2563dd2498b -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh.1) = 3dc212df3c774ec6d50752590cbded15 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh.c) = 168eb32dadff717d7778975ac3fbf50a -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh.h) = 01527755013e7b8b1dd4756919e51eed +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh.1) = f832bb483c82b31f7487a9ac071abbb2 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh.c) = 13de482b362f050b3893b95514a6f56d +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh.h) = daa7778da5032e411ca567a79782a316 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh/Makefile) = 41b006d3c04b599619990b47da60f81e MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ssh_config) = 9658715526aeaf0bc43528d3159b475f -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/sshconnect.c) = d3e7c5124fb7a8570ed543cecf493095 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/sshd.8) = e08d1683e931a4b30e0e411d4d3576c8 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/sshd.c) = 7f3b23f9e982a63fead1e813ff079b9c +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/sshconnect.c) = 0cfc1cefe83aaa075380082920fc3de6 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/sshd.8) = 24e8c96c0eff5b2f21844345eb3458ff +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/sshd.c) = ffbdc65ddce95238c28a8f26dbb35432 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/sshd/Makefile) = d1d83d1ece775d3a5cbf8cfaaf2330f3 -MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/sshd_config) = e78b81c34da5c97eee1359cccda908d6 +MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/sshd_config) = f48bdabb5094cb6aaa1f398987cbf9b4 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/tildexpand.c) = 65ba9200404da3a094823605f57bca12 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ttymodes.c) = 570810b08bdb8bc962630c2fbb425a00 MD5 (OpenSSH-1.2.1/src/usr.bin/ssh/ttymodes.h) = a08ab0789c979c7942423e2ab3df79dd diff --git a/security/openssh/files/bindresvport.c b/security/openssh/files/bindresvport.c new file mode 100644 index 000000000000..258e8547b388 --- /dev/null +++ b/security/openssh/files/bindresvport.c @@ -0,0 +1,151 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)bindresvport.c 1.8 88/02/08 SMI";*/ +/*static char *sccsid = "from: @(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC";*/ +/*from: OpenBSD: bindresvport.c,v 1.7 1996/07/30 16:25:47 downsj Exp */ +static char *rcsid = "$FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/bindresvport.c,v 1.1 2000-01-13 23:22:12 green Exp $"; +#endif + +/* + * Copyright (c) 1987 by Sun Microsystems, Inc. + * + * Portions Copyright(C) 1996, Jason Downs. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include "includes.h" + +/* + * Bind a socket to a privileged IP port + */ +int +bindresvport(sd, sin) + int sd; + struct sockaddr_in *sin; +{ + struct sockaddr_in myaddr; + int sinlen = sizeof(struct sockaddr_in); + + if (sin == (struct sockaddr_in *)0) { + sin = &myaddr; + memset(sin, 0, sinlen); + sin->sin_len = sinlen; + sin->sin_family = AF_INET; + } else if (sin->sin_family != AF_INET) { + errno = EPFNOSUPPORT; + return (-1); + } + + return (bindresvport2(sd, sin, sinlen)); +} + +int +bindresvport2(sd, sa, addrlen) + int sd; + struct sockaddr *sa; + socklen_t addrlen; +{ + int on, old, error, level, optname; + u_short port; + + if (sa == NULL) { + errno = EINVAL; + return (-1); + } + switch (sa->sa_family) { + case AF_INET: + port = ntohs(((struct sockaddr_in *)sa)->sin_port); + level = IPPROTO_IP; + optname = IP_PORTRANGE; + on = IP_PORTRANGE_LOW; + break; +#ifdef INET6 + case AF_INET6: + port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); + level = IPPROTO_IPV6; + optname = IPV6_PORTRANGE; + on = IPV6_PORTRANGE_LOW; + break; +#endif + default: + errno = EAFNOSUPPORT; + return (-1); + } + + if (port == 0) { + int oldlen = sizeof(old); + error = getsockopt(sd, level, optname, &old, &oldlen); + if (error < 0) + return(error); + + error = setsockopt(sd, level, optname, &on, sizeof(on)); + if (error < 0) + return(error); + } + + error = bind(sd, sa, addrlen); + + switch (sa->sa_family) { + case AF_INET: + port = ntohs(((struct sockaddr_in *)sa)->sin_port); + break; +#ifdef INET6 + case AF_INET6: + port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); + break; +#endif + default: /* shoud not match here */ + errno = EAFNOSUPPORT; + return (-1); + } + if (port == 0) { + int saved_errno = errno; + + if (error) { + if (setsockopt(sd, level, optname, + &old, sizeof(old)) < 0) + errno = saved_errno; + return (error); + } + + /* Hmm, what did the kernel assign... */ + if (getsockname(sd, (struct sockaddr *)sa, &addrlen) < 0) + errno = saved_errno; + return (error); + } + return (error); +} diff --git a/security/openssh/files/getaddrinfo.c b/security/openssh/files/getaddrinfo.c new file mode 100644 index 000000000000..a09abd96dc60 --- /dev/null +++ b/security/openssh/files/getaddrinfo.c @@ -0,0 +1,1024 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 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. + * + * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/getaddrinfo.c,v 1.1 2000-01-13 23:22:12 green Exp $ + */ + +/* + * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. + * + * Issues to be discussed: + * - Thread safe-ness must be checked. + * - Return values. There are nonstandard return values defined and used + * in the source code. This is because RFC2553 is silent about which error + * code must be returned for which situation. + * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__KAME__) && defined(INET6) +# define FAITH +#endif + +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 + +static const char in_addrany[] = { 0, 0, 0, 0 }; +static const char in6_addrany[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const char in_loopback[] = { 127, 0, 0, 1 }; +static const char in6_loopback[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; + +static const struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; + const char *a_addrany; + const char *a_loopback; + int a_scoped; +} afdl [] = { +#ifdef INET6 +#define N_INET6 0 + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr), + in6_addrany, in6_loopback, 1}, +#define N_INET 1 +#else +#define N_INET 0 +#endif + {PF_INET, sizeof(struct in_addr), + sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr), + in_addrany, in_loopback, 0}, + {0, 0, 0, 0, NULL, NULL, 0}, +}; + +struct explore { + int e_af; + int e_socktype; + int e_protocol; + const char *e_protostr; + int e_wild; +#define WILD_AF(ex) ((ex)->e_wild & 0x01) +#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) +#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) +}; + +static const struct explore explore[] = { +#ifdef INET6 + { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, +#endif + { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, + { -1, 0, 0, NULL, 0 }, +}; + +#ifdef INET6 +#define PTON_MAX 16 +#else +#define PTON_MAX 4 +#endif + + +static int str_isnumber __P((const char *)); +static int explore_fqdn __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_null __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_numeric __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int explore_numeric_scope __P((const struct addrinfo *, const char *, + const char *, struct addrinfo **)); +static int get_name __P((const char *, const struct afd *, struct addrinfo **, + char *, const struct addrinfo *, const char *)); +static int get_canonname __P((const struct addrinfo *, + struct addrinfo *, const char *)); +static struct addrinfo *get_ai __P((const struct addrinfo *, + const struct afd *, const char *)); +static int get_portmatch __P((const struct addrinfo *, const char *)); +static int get_port __P((struct addrinfo *, const char *, int)); +static const struct afd *find_afd __P((int)); + +static char *ai_errlist[] = { + "Success", + "Address family for hostname not supported", /* EAI_ADDRFAMILY */ + "Temporary failure in name resolution", /* EAI_AGAIN */ + "Invalid value for ai_flags", /* EAI_BADFLAGS */ + "Non-recoverable failure in name resolution", /* EAI_FAIL */ + "ai_family not supported", /* EAI_FAMILY */ + "Memory allocation failure", /* EAI_MEMORY */ + "No address associated with hostname", /* EAI_NODATA */ + "hostname nor servname provided, or not known", /* EAI_NONAME */ + "servname not supported for ai_socktype", /* EAI_SERVICE */ + "ai_socktype not supported", /* EAI_SOCKTYPE */ + "System error returned in errno", /* EAI_SYSTEM */ + "Invalid value for hints", /* EAI_BADHINTS */ + "Resolved protocol is unknown", /* EAI_PROTOCOL */ + "Argument res is NULL", /* EAI_RESNULL */ + "Unknown error", /* EAI_MAX */ +}; + +/* XXX macros that make external reference is BAD. */ + +#define GET_AI(ai, afd, addr) \ +do { \ + /* external reference: pai, error, and label free */ \ + (ai) = get_ai(pai, (afd), (addr)); \ + if ((ai) == NULL) { \ + error = EAI_MEMORY; \ + goto free; \ + } \ +} while (0) + +#define GET_PORT(ai, serv) \ +do { \ + /* external reference: error and label free */ \ + error = get_port((ai), (serv), 0); \ + if (error != 0) \ + goto free; \ +} while (0) + +#define GET_CANONNAME(ai, str) \ +do { \ + /* external reference: pai, error and label free */ \ + error = get_canonname(pai, (ai), (str)); \ + if (error != 0) \ + goto free; \ +} while (0) + +#define ERR(err) \ +do { \ + /* external reference: error, and label bad */ \ + error = (err); \ + goto bad; \ +} while (0) + +#define MATCH_FAMILY(x, y, w) \ + ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) +#define MATCH(x, y, w) \ + ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY))) + +char * +gai_strerror(ecode) + int ecode; +{ + if (ecode < 0 || ecode > EAI_MAX) + ecode = EAI_MAX; + return ai_errlist[ecode]; +} + +void +freeaddrinfo(ai) + struct addrinfo *ai; +{ + struct addrinfo *next; + + do { + next = ai->ai_next; + if (ai->ai_canonname) + free(ai->ai_canonname); + /* no need to free(ai->ai_addr) */ + free(ai); + } while ((ai = next) != NULL); +} + +static int +str_isnumber(p) + const char *p; +{ + char *q = (char *)p; + while (*q) { + if (! isdigit(*q)) + return NO; + q++; + } + return YES; +} + +int +getaddrinfo(hostname, servname, hints, res) + const char *hostname, *servname; + const struct addrinfo *hints; + struct addrinfo **res; +{ + struct addrinfo sentinel; + struct addrinfo *cur; + int error = 0; + struct addrinfo ai; + struct addrinfo ai0; + struct addrinfo *pai; + const struct afd *afd; + const struct explore *ex; + + sentinel.ai_next = NULL; + cur = &sentinel; + pai = &ai; + pai->ai_flags = 0; + pai->ai_family = PF_UNSPEC; + pai->ai_socktype = ANY; + pai->ai_protocol = ANY; + pai->ai_addrlen = 0; + pai->ai_canonname = NULL; + pai->ai_addr = NULL; + pai->ai_next = NULL; + + if (hostname == NULL && servname == NULL) + return EAI_NONAME; + if (res == NULL) + return EAI_RESNULL; /* xxx */ + if (hints) { + /* error check for hints */ + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) + ERR(EAI_BADHINTS); /* xxx */ + if (hints->ai_flags & ~AI_MASK) + ERR(EAI_BADFLAGS); + switch (hints->ai_family) { + case PF_UNSPEC: + case PF_INET: +#ifdef INET6 + case PF_INET6: +#endif + break; + default: + ERR(EAI_FAMILY); + } + memcpy(pai, hints, sizeof(*pai)); + + /* + * if both socktype/protocol are specified, check if they + * are meaningful combination. + */ + if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { + int matched = 0; + + for (ex = explore; ex->e_af >= 0; ex++) { + if (pai->ai_family != ex->e_af) + continue; + if (ex->e_socktype == ANY) + continue; + if (ex->e_protocol == ANY) + continue; + if (pai->ai_socktype == ex->e_socktype + && pai->ai_protocol == ex->e_protocol) + matched = 1; + else + continue; + if (matched == 0) + ERR(EAI_BADHINTS); + } + } + } + + /* backup original pai contents */ + ai0 = *pai; + + /* + * special cases check for inet and inet6 sockets. + * (1) servname is disallowed for raw sockets. + * (2) numeric servname is disallowed if socktype/protocol is left + * unspecified. + */ + if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) +#ifdef INET6 + || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) +#endif + ) { + *pai = ai0; + + if (pai->ai_family == PF_UNSPEC) +#ifdef INET6 + pai->ai_family = PF_INET6; +#else + pai->ai_family = PF_INET; +#endif + error = get_portmatch(pai, servname); + if (error) + ERR(error); + } + + /* NULL hostname, or numeric hostname */ + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) + continue; + if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) + continue; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + if (hostname == NULL) + error = explore_null(pai, hostname, servname, &cur->ai_next); + else + error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); + + if (error) + goto free; + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + /* + * XXX + * If numreic representation of AF1 can be interpreted as FQDN + * representation of AF2, we need to think again about the code below. + */ + if (sentinel.ai_next) + goto good; + + if (pai->ai_flags & AI_NUMERICHOST) + ERR(EAI_NONAME); + if (hostname == NULL) + ERR(EAI_NONAME); + + /* + * hostname as alphabetical name. + * we would like to prefer AF_INET6 than AF_INET, so we'll make a + * outer loop by AFs. + */ + for (afd = afdl; afd->a_af; afd++) { + *pai = ai0; + + if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) + continue; + + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = afd->a_af; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, + WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, + WILD_SOCKTYPE(ex))) { + continue; + } + if (!MATCH(pai->ai_protocol, ex->e_protocol, + WILD_PROTOCOL(ex))) { + continue; + } + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + error = explore_fqdn(pai, hostname, servname, + &cur->ai_next); + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + } + + /* XXX: if any addrinfo found, SUCCESS return even if (error != 0) */ + if (sentinel.ai_next) { + good: + *res = sentinel.ai_next; + return SUCCESS; + } + /* else, failed */ + free: + bad: + if (error == 0) + error = EAI_FAIL; + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + *res = NULL; + return error; +} + +/* + * FQDN hostname, DNS lookup + */ +static int +explore_fqdn(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + int s; + struct hostent *hp; + int h_error; + int af; + char *ap; + struct addrinfo sentinel, *cur; + int i; + const struct afd *afd; + int error; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * filter out AFs that are not supported by the kernel + * XXX errno? + */ + s = socket(pai->ai_family, SOCK_DGRAM, 0); + if (s < 0) + return 0; + close(s); + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, + &h_error); + if (hp == NULL) { + switch (h_error) { + case HOST_NOT_FOUND: + case NO_DATA: + error = EAI_NODATA; + break; + case TRY_AGAIN: + error = EAI_AGAIN; + break; + case NO_RECOVERY: + case NETDB_INTERNAL: + default: + error = EAI_FAIL; + break; + } + } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0) + || (hp->h_addr_list[0] == NULL)) { + freehostent(hp); + hp = NULL; + error = EAI_FAIL; + } + + if (hp == NULL) + goto free; + + for (i = 0; hp->h_addr_list[i] != NULL; i++) { + af = hp->h_addrtype; + ap = hp->h_addr_list[i]; + + if (af != pai->ai_family) + continue; + + if ((pai->ai_flags & AI_CANONNAME) == 0) { + GET_AI(cur->ai_next, afd, ap); + GET_PORT(cur->ai_next, servname); + } else { + /* + * if AI_CANONNAME and if reverse lookup + * fail, return ai anyway to pacify + * calling application. + * + * XXX getaddrinfo() is a name->address + * translation function, and it looks + * strange that we do addr->name + * translation here. + */ + get_name(ap, afd, &cur->ai_next, + ap, pai, servname); + } + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + *res = sentinel.ai_next; + return 0; + +free: + if (hp) + freehostent(hp); + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * hostname == NULL. + * passive socket -> anyaddr (0.0.0.0 or ::) + * non-passive socket -> localhost (127.0.0.1 or ::1) + */ +static int +explore_null(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + int s; + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * filter out AFs that are not supported by the kernel + * XXX errno? + */ + s = socket(pai->ai_family, SOCK_DGRAM, 0); + if (s < 0) + return 0; + close(s); + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + GET_AI(cur->ai_next, afd, + (pai->ai_flags & AI_PASSIVE) ? afd->a_addrany : afd->a_loopback + ); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "anyaddr"); + * or + * GET_CANONNAME(cur->ai_next, "localhost"); + */ + /* if the servname does not match socktype/protocol, ignored */ + GET_PORT(cur->ai_next, servname); + + *res = sentinel.ai_next; + return 0; + +free: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * numeric hostname + */ +static int +explore_numeric(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ + const struct afd *afd; + struct addrinfo *cur; + struct addrinfo sentinel; + int error; + char pton[PTON_MAX]; + int flags; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + flags = pai->ai_flags; + + if (inet_pton(afd->a_af, hostname, pton) == 1) { + u_int32_t v4a; +#ifdef INET6 + struct in6_addr * v6a; +#endif + + switch (afd->a_af) { + case AF_INET: + v4a = (u_int32_t)ntohl(((struct in_addr *)pton)->s_addr); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags &= ~AI_CANONNAME; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + flags &= ~AI_CANONNAME; + break; +#ifdef INET6 + case AF_INET6: + v6a = (struct in6_addr *)pton; + if (IN6_IS_ADDR_MULTICAST(v6a)) + flags &= ~AI_CANONNAME; + if (IN6_IS_ADDR_UNSPECIFIED(v6a) || + IN6_IS_ADDR_LOOPBACK(v6a)) + flags &= ~AI_CANONNAME; + if (IN6_IS_ADDR_LINKLOCAL(v6a)) + flags &= ~AI_CANONNAME; + + /* should also do this for SITELOCAL ?? */ + + break; +#endif + } + + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + if ((flags & AI_CANONNAME) == 0) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + } else { + /* + * if AI_CANONNAME and if reverse lookup + * fail, return ai anyway to pacify + * calling application. + * + * XXX getaddrinfo() is a name->address + * translation function, and it looks + * strange that we do addr->name + * translation here. + */ + get_name(pton, afd, &cur->ai_next, + pton, pai, servname); + } + while (cur && cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + + *res = sentinel.ai_next; + return 0; + +free: +bad: + if (sentinel.ai_next) + freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * numeric hostname with scope + */ +static int +explore_numeric_scope(pai, hostname, servname, res) + const struct addrinfo *pai; + const char *hostname; + const char *servname; + struct addrinfo **res; +{ +#ifndef SCOPE_DELIMITER + return explore_numeric(pai, hostname, servname, res); +#else + const struct afd *afd; + struct addrinfo *cur; + int error; + char *cp, *hostname2 = NULL; + int scope; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + if (!afd->a_scoped) + return explore_numeric(pai, hostname, servname, res); + + cp = strchr(hostname, SCOPE_DELIMITER); + if (cp == NULL) + return explore_numeric(pai, hostname, servname, res); + + /* + * Handle special case of + */ + hostname2 = strdup(hostname); + if (hostname2 == NULL) + return EAI_MEMORY; + /* terminate at the delimiter */ + hostname2[cp - hostname] = '\0'; + + cp++; + switch (pai->ai_family) { +#ifdef INET6 + case AF_INET6: + scope = if_nametoindex(cp); + if (scope == 0) { + error = EAI_SYSTEM; + goto free; + } + break; +#endif + } + + error = explore_numeric(pai, hostname2, servname, res); + if (error == 0) { + for (cur = *res; cur; cur = cur->ai_next) { +#ifdef INET6 + if (cur->ai_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)cur->ai_addr; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) + sin6->sin6_scope_id = scope; +#endif + } + } + +#ifdef INET6 +free: +#endif + free(hostname2); + + return error; +#endif +} + +static int +get_name(addr, afd, res, numaddr, pai, servname) + const char *addr; + const struct afd *afd; + struct addrinfo **res; + char *numaddr; + const struct addrinfo *pai; + const char *servname; +{ + struct hostent *hp; + struct addrinfo *cur; + int error = 0; + int h_error; + + hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); + if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { + if (hp->h_addrtype == afd->a_af) + GET_AI(cur, afd, hp->h_addr_list[0]); + else /* IPv4 mapped IPv6 addr case */ + GET_AI(cur, afd, numaddr); + GET_PORT(cur, servname); + GET_CANONNAME(cur, hp->h_name); + } else { + GET_AI(cur, afd, numaddr); + GET_PORT(cur, servname); + } + + if (hp) + freehostent(hp); + *res = cur; + return SUCCESS; + free: + if (cur) + freeaddrinfo(cur); + if (hp) + freehostent(hp); + /* bad: */ + *res = NULL; + return error; +} + +static int +get_canonname(pai, ai, str) + const struct addrinfo *pai; + struct addrinfo *ai; + const char *str; +{ + if ((pai->ai_flags & AI_CANONNAME) != 0) { + ai->ai_canonname = (char *)malloc(strlen(str) + 1); + if (ai->ai_canonname == NULL) + return EAI_MEMORY; + strcpy(ai->ai_canonname, str); + } + return 0; +} + +static struct addrinfo * +get_ai(pai, afd, addr) + const struct addrinfo *pai; + const struct afd *afd; + const char *addr; +{ + char *p; + struct addrinfo *ai; +#ifdef FAITH + struct in6_addr faith_prefix; + char *fp_str; + int translate = 0; +#endif + +#ifdef FAITH + /* + * Transfrom an IPv4 addr into a special IPv6 addr format for + * IPv6->IPv4 translation gateway. (only TCP is supported now) + * + * +-----------------------------------+------------+ + * | faith prefix part (12 bytes) | embedded | + * | | IPv4 addr part (4 bytes) + * +-----------------------------------+------------+ + * + * faith prefix part is specified as ascii IPv6 addr format + * in environmental variable GAI. + * For FAITH to work correctly, routing to faith prefix must be + * setup toward a machine where a FAITH daemon operates. + * Also, the machine must enable some mechanizm + * (e.g. faith interface hack) to divert those packet with + * faith prefixed destination addr to user-land FAITH daemon. + */ + fp_str = getenv("GAI"); + if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 && + afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) { + u_int32_t v4a; + u_int8_t v4a_top; + + memcpy(&v4a, addr, sizeof v4a); + v4a_top = v4a >> IN_CLASSA_NSHIFT; + if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) && + v4a_top != 0 && v4a != IN_LOOPBACKNET) { + afd = &afdl[N_INET6]; + memcpy(&faith_prefix.s6_addr[12], addr, + sizeof(struct in_addr)); + translate = 1; + } + } +#endif + + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + + (afd->a_socklen)); + if (ai == NULL) + return NULL; + + memcpy(ai, pai, sizeof(struct addrinfo)); + ai->ai_addr = (struct sockaddr *)(ai + 1); + memset(ai->ai_addr, 0, afd->a_socklen); + ai->ai_addr->sa_len = afd->a_socklen; + ai->ai_addrlen = afd->a_socklen; + ai->ai_addr->sa_family = ai->ai_family = afd->a_af; + p = (char *)(ai->ai_addr); +#ifdef FAITH + if (translate == 1) + memcpy(p + afd->a_off, &faith_prefix, afd->a_addrlen); + else +#endif + memcpy(p + afd->a_off, addr, afd->a_addrlen); + + return ai; +} + +static int +get_portmatch(ai, servname) + const struct addrinfo *ai; + const char *servname; +{ + /* get_port does not touch first argument. when matchonly == 1. */ + return get_port((struct addrinfo *)ai, servname, 1); +} + +static int +get_port(ai, servname, matchonly) + struct addrinfo *ai; + const char *servname; + int matchonly; +{ + const char *proto; + struct servent *sp; + int port; + int allownumeric; + + if (servname == NULL) + return 0; + if (ai->ai_family != AF_INET +#ifdef INET6 + && ai->ai_family != AF_INET6 +#endif + ) + return 0; + + switch (ai->ai_socktype) { + case SOCK_RAW: + return EAI_SERVICE; + case SOCK_DGRAM: + case SOCK_STREAM: + allownumeric = 1; + break; + case ANY: + allownumeric = 0; + break; + default: + return EAI_SOCKTYPE; + } + + if (str_isnumber(servname)) { + if (!allownumeric) + return EAI_SERVICE; + port = htons(atoi(servname)); + if (port < 0 || port > 65535) + return EAI_SERVICE; + } else { + switch (ai->ai_socktype) { + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + default: + proto = NULL; + break; + } + + if ((sp = getservbyname(servname, proto)) == NULL) + return EAI_SERVICE; + port = sp->s_port; + } + + if (!matchonly) { + switch (ai->ai_family) { + case AF_INET: + ((struct sockaddr_in *)ai->ai_addr)->sin_port = port; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port; + break; +#endif + } + } + + return 0; +} + +static const struct afd * +find_afd(af) + int af; +{ + const struct afd *afd; + + if (af == PF_UNSPEC) + return NULL; + for (afd = afdl; afd->a_af; afd++) { + if (afd->a_af == af) + return afd; + } + return NULL; +} diff --git a/security/openssh/files/getnameinfo.c b/security/openssh/files/getnameinfo.c new file mode 100644 index 000000000000..67f2ea77fd81 --- /dev/null +++ b/security/openssh/files/getnameinfo.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 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. + * + * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/getnameinfo.c,v 1.1 2000-01-13 23:22:12 green Exp $ + */ + +/* + * Issues to be discussed: + * - Thread safe-ness must be checked + * - Return values. There seems to be no standard for return value (RFC2553) + * but INRIA implementation returns EAI_xxx defined for getaddrinfo(). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 + +static struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; +} afdl [] = { +#ifdef INET6 + {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr)}, +#endif + {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr)}, + {0, 0, 0}, +}; + +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; + +#define ENI_NOSOCKET 0 +#define ENI_NOSERVHOST 1 +#define ENI_NOHOSTNAME 2 +#define ENI_MEMORY 3 +#define ENI_SYSTEM 4 +#define ENI_FAMILY 5 +#define ENI_SALEN 6 + +int +getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) + const struct sockaddr *sa; + size_t salen; + char *host; + size_t hostlen; + char *serv; + size_t servlen; + int flags; +{ + struct afd *afd; + struct servent *sp; + struct hostent *hp; + u_short port; + int family, i; + char *addr, *p; + u_long v4a; + int h_error; + char numserv[512]; + char numaddr[512]; + int noserv = 0; + + if (sa == NULL) + return ENI_NOSOCKET; + + if (sa->sa_len != salen) + return ENI_SALEN; + + family = sa->sa_family; + for (i = 0; afdl[i].a_af; i++) + if (afdl[i].a_af == family) { + afd = &afdl[i]; + goto found; + } + return ENI_FAMILY; + + found: + if (salen != afd->a_socklen) + return ENI_SALEN; + + port = ((struct sockinet *)sa)->si_port; /* network byte order */ + addr = (char *)sa + afd->a_off; + + if (serv == NULL || servlen == 0) { + noserv = 1; + } else { + if (flags & NI_NUMERICSERV) + sp = NULL; + else { + sp = getservbyport(port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + } + if (sp) { + if (strlen(sp->s_name) > servlen) + return ENI_MEMORY; + strcpy(serv, sp->s_name); + } else { + snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); + if (strlen(numserv) > servlen) + return ENI_MEMORY; + strcpy(serv, numserv); + } + } + + switch (sa->sa_family) { + case AF_INET: + v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + flags |= NI_NUMERICHOST; + break; +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *sin6; + sin6 = (struct sockaddr_in6 *)sa; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; + } + break; +#endif + } + if (host == NULL || hostlen == 0) { + if (noserv == 1) + return ENI_NOSERVHOST; + } else if (flags & NI_NUMERICHOST) { + /* NUMERICHOST and NAMEREQD conflicts with each other */ + if (flags & NI_NAMEREQD) + return ENI_NOHOSTNAME; + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_SYSTEM; + if (strlen(numaddr) > hostlen) + return ENI_MEMORY; + strcpy(host, numaddr); +#ifdef INET6 + if (afd->a_af == AF_INET6 && + (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) || + IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) && + ((struct sockaddr_in6 *)sa)->sin6_scope_id) { + if (flags & NI_WITHSCOPEID) { + char *ep = strchr(host, '\0'); + unsigned int ifindex = + ((struct sockaddr_in6 *)sa)->sin6_scope_id; + char ifname[IF_NAMESIZE * 2 /* for safety */]; + + if ((if_indextoname(ifindex, ifname)) == NULL) + return ENI_SYSTEM; + if (strlen(host) + 1 /* SCOPE_DELIMITER */ + + strlen(ifname) > hostlen) + return ENI_MEMORY; + *ep = SCOPE_DELIMITER; + strcpy(ep + 1, ifname); + } + } +#endif /* INET6 */ + } else { + hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); + if (hp) { + if (flags & NI_NOFQDN) { + p = strchr(hp->h_name, '.'); + if (p) *p = '\0'; + } + if (strlen(hp->h_name) > hostlen) { + freehostent(hp); + return ENI_MEMORY; + } + strcpy(host, hp->h_name); + freehostent(hp); + } else { + if (flags & NI_NAMEREQD) + return ENI_NOHOSTNAME; + if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_NOHOSTNAME; + if (strlen(numaddr) > hostlen) + return ENI_MEMORY; + strcpy(host, numaddr); + } + } + return SUCCESS; +} diff --git a/security/openssh/files/name6.c b/security/openssh/files/name6.c new file mode 100644 index 000000000000..978796ad15b4 --- /dev/null +++ b/security/openssh/files/name6.c @@ -0,0 +1,1262 @@ +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 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. + * + * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/name6.c,v 1.1 2000-01-13 23:22:13 green Exp $ + */ +/* $Id: name6.c,v 1.9 1999/10/29 03:04:26 itojun Exp $ */ +/* + * Atsushi Onoe + */ + +/* + * TODO for thread safe + * use mutex for _hostconf, _hostconf_init. + * rewrite resolvers to be thread safe + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifndef _PATH_HOSTS +#define _PATH_HOSTS "/etc/hosts" +#endif + +#ifndef MAXALIASES +#define MAXALIASES 10 +#endif +#ifndef MAXADDRS +#define MAXADDRS 20 +#endif +#ifndef MAXDNAME +#define MAXDNAME 1025 +#endif + +#ifdef INET6 +#define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \ + sizeof(struct in_addr)) +#else +#define ADDRLEN(af) sizeof(struct in_addr) +#endif + +#define MAPADDR(ab, ina) \ +do { \ + memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \ + memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \ + memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \ +} while (0) +#define MAPADDRENABLED(flags) \ + (((flags) & AI_V4MAPPED) || \ + (((flags) & AI_V4MAPPED_CFG) && _mapped_addr_enabled())) + +union inx_addr { + struct in_addr in_addr; +#ifdef INET6 + struct in6_addr in6_addr; +#endif + struct { + u_char mau_zero[10]; + u_char mau_one[2]; + struct in_addr mau_inaddr; + } map_addr_un; +#define map_zero map_addr_un.mau_zero +#define map_one map_addr_un.mau_one +#define map_inaddr map_addr_un.mau_inaddr +}; + +static struct hostent *_hpcopy(struct hostent *hp, int *errp); +static struct hostent *_hpaddr(int af, const char *name, void *addr, int *errp); +static struct hostent *_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp); +#ifdef INET6 +static struct hostent *_hpmapv6(struct hostent *hp, int *errp); +#endif +static struct hostent *_hpsort(struct hostent *hp); +static struct hostent *_ghbyname(const char *name, int af, int flags, int *errp); +static char *_hgetword(char **pp); +static int _mapped_addr_enabled(void); + +static FILE *_files_open(int *errp); +static struct hostent *_files_ghbyname(const char *name, int af, int *errp); +static struct hostent *_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp); +static void _files_shent(int stayopen); +static void _files_ehent(void); +static struct hostent *_dns_ghbyname(const char *name, int af, int *errp); +static struct hostent *_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp); +static void _dns_shent(int stayopen); +static void _dns_ehent(void); +#ifdef ICMPNL +static struct hostent *_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp); +#endif /* ICMPNL */ + +/* + * Select order host function. + */ +#define MAXHOSTCONF 4 + +#ifndef HOSTCONF +# define HOSTCONF "/etc/host.conf" +#endif /* !HOSTCONF */ + +struct _hostconf { + struct hostent *(*byname)(const char *name, int af, int *errp); + struct hostent *(*byaddr)(const void *addr, int addrlen, int af, int *errp); +}; + +/* default order */ +static struct _hostconf _hostconf[MAXHOSTCONF] = { + { _dns_ghbyname, _dns_ghbyaddr }, + { _files_ghbyname, _files_ghbyaddr }, +#ifdef ICMPNL + { NULL, _icmp_ghbyaddr }, +#endif /* ICMPNL */ +}; + +static int _hostconf_init_done; +static void _hostconf_init(void); + +/* + * Initialize hostconf structure. + */ + +static void +_hostconf_init(void) +{ + FILE *fp; + int n; + char *p, *line; + char buf[BUFSIZ]; + + _hostconf_init_done = 1; + n = 0; + p = HOSTCONF; + if ((fp = fopen(p, "r")) == NULL) + return; + while (n < MAXHOSTCONF && fgets(buf, sizeof(buf), fp)) { + line = buf; + if ((p = _hgetword(&line)) == NULL) + continue; + do { + if (strcmp(p, "hosts") == 0 + || strcmp(p, "local") == 0 + || strcmp(p, "file") == 0 + || strcmp(p, "files") == 0) { + _hostconf[n].byname = _files_ghbyname; + _hostconf[n].byaddr = _files_ghbyaddr; + n++; + } + else if (strcmp(p, "dns") == 0 + || strcmp(p, "bind") == 0) { + _hostconf[n].byname = _dns_ghbyname; + _hostconf[n].byaddr = _dns_ghbyaddr; + n++; + } +#ifdef ICMPNL + else if (strcmp(p, "icmp") == 0) { + _hostconf[n].byname = NULL; + _hostconf[n].byaddr = _icmp_ghbyaddr; + n++; + } +#endif /* ICMPNL */ + } while ((p = _hgetword(&line)) != NULL); + } + fclose(fp); + if (n < 0) { + /* no keyword found. do not change default configuration */ + return; + } + for (; n < MAXHOSTCONF; n++) { + _hostconf[n].byname = NULL; + _hostconf[n].byaddr = NULL; + } +} + +/* + * Check if kernel supports mapped address. + * implementation dependent + */ +#ifdef __KAME__ +#include +#endif /* __KAME__ */ + +static int +_mapped_addr_enabled(void) +{ + /* implementation dependent check */ +#if defined(__KAME__) && defined(IPV6CTL_MAPPED_ADDR) + int mib[4]; + size_t len; + int val; + + mib[0] = CTL_NET; + mib[1] = PF_INET6; + mib[2] = IPPROTO_IPV6; + mib[3] = IPV6CTL_MAPPED_ADDR; + len = sizeof(val); + if (sysctl(mib, 4, &val, &len, 0, 0) == 0 && val != 0) + return 1; +#endif /* __KAME__ && IPV6CTL_MAPPED_ADDR */ + return 0; +} + +/* + * Functions defined in RFC2553 + * getipnodebyname, getipnodebyadr, freehostent + */ + +static struct hostent * +_ghbyname(const char *name, int af, int flags, int *errp) +{ + struct hostent *hp; + int i; + + if (flags & AI_ADDRCONFIG) { + int s; + + if ((s = socket(af, SOCK_DGRAM, 0)) < 0) + return NULL; + /* + * TODO: + * Note that implementation dependent test for address + * configuration should be done everytime called + * (or apropriate interval), + * because addresses will be dynamically assigned or deleted. + */ + close(s); + } + + for (i = 0; i < MAXHOSTCONF; i++) { + if (_hostconf[i].byname + && (hp = (*_hostconf[i].byname)(name, af, errp)) + != NULL) + return hp; + } + + return NULL; +} + +struct hostent * +getipnodebyname(const char *name, int af, int flags, int *errp) +{ + struct hostent *hp; + union inx_addr addrbuf; + + if (af != AF_INET +#ifdef INET6 + && af != AF_INET6 +#endif + ) + { + *errp = NO_RECOVERY; + return NULL; + } + +#ifdef INET6 + /* special case for literal address */ + if (inet_pton(AF_INET6, name, &addrbuf) == 1) { + if (af != AF_INET6) { + *errp = HOST_NOT_FOUND; + return NULL; + } + return _hpaddr(af, name, &addrbuf, errp); + } +#endif + if (inet_pton(AF_INET, name, &addrbuf) == 1) { + if (af != AF_INET) { + if (MAPADDRENABLED(flags)) { + MAPADDR(&addrbuf, &addrbuf.in_addr); + } else { + *errp = HOST_NOT_FOUND; + return NULL; + } + } + return _hpaddr(af, name, &addrbuf, errp); + } + + if (!_hostconf_init_done) + _hostconf_init(); + + *errp = HOST_NOT_FOUND; + hp = _ghbyname(name, af, flags, errp); + +#ifdef INET6 + if (af == AF_INET6 + && ((flags & AI_ALL) || hp == NULL) + && (MAPADDRENABLED(flags))) { + struct hostent *hp2 = _ghbyname(name, AF_INET, flags, errp); + if (hp == NULL) + hp = _hpmapv6(hp2, errp); + else { + if (hp2 && strcmp(hp->h_name, hp2->h_name) != 0) { + freehostent(hp2); + hp2 = NULL; + } + hp = _hpmerge(hp, hp2, errp); + } + } +#endif + return _hpsort(hp); +} + +struct hostent * +getipnodebyaddr(const void *src, size_t len, int af, int *errp) +{ + struct hostent *hp; + int i; +#ifdef INET6 + struct in6_addr addrbuf; +#else + struct in_addr addrbuf; +#endif + + *errp = HOST_NOT_FOUND; + + switch (af) { + case AF_INET: + if (len != sizeof(struct in_addr)) { + *errp = NO_RECOVERY; + return NULL; + } + if ((long)src & ~(sizeof(struct in_addr) - 1)) { + memcpy(&addrbuf, src, len); + src = &addrbuf; + } + if (((struct in_addr *)src)->s_addr == 0) + return NULL; + break; +#ifdef INET6 + case AF_INET6: + if (len != sizeof(struct in6_addr)) { + *errp = NO_RECOVERY; + return NULL; + } + if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) { /*XXX*/ + memcpy(&addrbuf, src, len); + src = &addrbuf; + } + if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src)) + return NULL; + if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src) + || IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) { + src = (char *)src + + (sizeof(struct in6_addr) - sizeof(struct in_addr)); + af = AF_INET; + len = sizeof(struct in_addr); + } + break; +#endif + default: + *errp = NO_RECOVERY; + return NULL; + } + + if (!_hostconf_init_done) + _hostconf_init(); + for (i = 0; i < MAXHOSTCONF; i++) { + if (_hostconf[i].byaddr + && (hp = (*_hostconf[i].byaddr)(src, len, af, errp)) != NULL) + return hp; + } + + return NULL; +} + +void +freehostent(struct hostent *ptr) +{ + free(ptr); +} + +#if 0 + +/* XXX: should be deprecated */ +struct hostent * +getnodebyname(const char *name, int af, int flags) +{ + return getipnodebyname(name, af, flags, &h_errno); +} + +#ifdef __warn_references +__warn_references(getnodebyname, + "warning: getnodebyname() deprecated, " + "should use getaddrinfo() or getipnodebyname()"); +#endif + +struct hostent * +getnodebyaddr(const void *src, size_t len, int af) +{ + return getipnodebyaddr(src, len, af, &h_errno); +} + +#ifdef __warn_references +__warn_references(getnodebyaddr, + "warning: getnodebyaddr() deprecated, " + "should use getnameinfo() or getipnodebyaddr()"); +#endif + +#endif + +/* + * Private utility functions + */ + +/* + * _hpcopy: allocate and copy hostent structure + */ +static struct hostent * +_hpcopy(struct hostent *hp, int *errp) +{ + struct hostent *nhp; + char *cp, **pp; + int size, addrsize; + int nalias = 0, naddr = 0; + int al_off; + int i; + + if (hp == NULL) + return hp; + + /* count size to be allocated */ + size = sizeof(struct hostent); + if (hp->h_name != NULL && *hp->h_name != '\0') + size += strlen(hp->h_name) + 1; + if ((pp = hp->h_aliases) != NULL) { + for (i = 0; *pp != NULL; i++, pp++) { + if (**pp != '\0') { + size += strlen(*pp) + 1; + nalias++; + } + } + } + /* adjust alignment */ + size = ALIGN(size); + al_off = size; + size += sizeof(char *) * (nalias + 1); + addrsize = ALIGN(hp->h_length); + if ((pp = hp->h_addr_list) != NULL) { + while (*pp++ != NULL) + naddr++; + } + size += addrsize * naddr; + size += sizeof(char *) * (naddr + 1); + + /* copy */ + if ((nhp = (struct hostent *)malloc(size)) == NULL) { + *errp = TRY_AGAIN; + return NULL; + } + cp = (char *)&nhp[1]; + if (hp->h_name != NULL && *hp->h_name != '\0') { + nhp->h_name = cp; + strcpy(cp, hp->h_name); + cp += strlen(cp) + 1; + } else + nhp->h_name = NULL; + nhp->h_aliases = (char **)((char *)nhp + al_off); + if ((pp = hp->h_aliases) != NULL) { + for (i = 0; *pp != NULL; pp++) { + if (**pp != '\0') { + nhp->h_aliases[i++] = cp; + strcpy(cp, *pp); + cp += strlen(cp) + 1; + } + } + } + nhp->h_aliases[nalias] = NULL; + cp = (char *)&nhp->h_aliases[nalias + 1]; + nhp->h_addrtype = hp->h_addrtype; + nhp->h_length = hp->h_length; + nhp->h_addr_list = (char **)cp; + if ((pp = hp->h_addr_list) != NULL) { + cp = (char *)&nhp->h_addr_list[naddr + 1]; + for (i = 0; *pp != NULL; pp++) { + nhp->h_addr_list[i++] = cp; + memcpy(cp, *pp, hp->h_length); + cp += addrsize; + } + } + nhp->h_addr_list[naddr] = NULL; + return nhp; +} + +/* + * _hpaddr: construct hostent structure with one address + */ +static struct hostent * +_hpaddr(int af, const char *name, void *addr, int *errp) +{ + struct hostent *hp, hpbuf; + char *addrs[2]; + + hp = &hpbuf; + hp->h_name = (char *)name; + hp->h_aliases = NULL; + hp->h_addrtype = af; + hp->h_length = ADDRLEN(af); + hp->h_addr_list = addrs; + addrs[0] = (char *)addr; + addrs[1] = NULL; + return _hpcopy(hp, errp); +} + +/* + * _hpmerge: merge 2 hostent structure, arguments will be freed + */ +static struct hostent * +_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp) +{ + int i, j; + int naddr, nalias; + char **pp; + struct hostent *hp, hpbuf; + char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1]; + union inx_addr addrbuf[MAXADDRS]; + + if (hp1 == NULL) + return hp2; + if (hp2 == NULL) + return hp1; + +#define HP(i) (i == 1 ? hp1 : hp2) + hp = &hpbuf; + hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name); + hp->h_aliases = aliases; + nalias = 0; + for (i = 1; i <= 2; i++) { + if ((pp = HP(i)->h_aliases) == NULL) + continue; + for (; nalias < MAXALIASES && *pp != NULL; pp++) { + /* check duplicates */ + for (j = 0; j < nalias; j++) + if (strcasecmp(*pp, aliases[j]) == 0) + break; + if (j == nalias) + aliases[nalias++] = *pp; + } + } + aliases[nalias] = NULL; +#ifdef INET6 + if (hp1->h_length != hp2->h_length) { + hp->h_addrtype = AF_INET6; + hp->h_length = sizeof(struct in6_addr); + } else { +#endif + hp->h_addrtype = hp1->h_addrtype; + hp->h_length = hp1->h_length; +#ifdef INET6 + } +#endif + hp->h_addr_list = addrs; + naddr = 0; + for (i = 1; i <= 2; i++) { + if ((pp = HP(i)->h_addr_list) == NULL) + continue; + if (HP(i)->h_length == hp->h_length) { + while (naddr < MAXADDRS && *pp != NULL) + addrs[naddr++] = *pp++; + } else { + /* copy IPv4 addr as mapped IPv6 addr */ + while (naddr < MAXADDRS && *pp != NULL) { + MAPADDR(&addrbuf[naddr], *pp++); + addrs[naddr] = (char *)&addrbuf[naddr]; + naddr++; + } + } + } + addrs[naddr] = NULL; + hp = _hpcopy(hp, errp); + freehostent(hp1); + freehostent(hp2); + return hp; +} + +/* + * _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses + */ +#ifdef INET6 +static struct hostent * +_hpmapv6(struct hostent *hp, int *errp) +{ + struct hostent *hp6; + + if (hp == NULL) + return NULL; + if (hp->h_addrtype == AF_INET6) + return hp; + + /* make dummy hostent to convert IPv6 address */ + if ((hp6 = (struct hostent *)malloc(sizeof(struct hostent))) == NULL) { + *errp = TRY_AGAIN; + return NULL; + } + hp6->h_name = NULL; + hp6->h_aliases = NULL; + hp6->h_addrtype = AF_INET6; + hp6->h_length = sizeof(struct in6_addr); + hp6->h_addr_list = NULL; + return _hpmerge(hp6, hp, errp); +} +#endif + +/* + * _hpsort: sort address by sortlist + */ +static struct hostent * +_hpsort(struct hostent *hp) +{ + int i, j, n; + u_char *ap, *sp, *mp, **pp; + char t; + char order[MAXADDRS]; + int nsort = _res.nsort; + + if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0) + return hp; + for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) { + for (j = 0; j < nsort; j++) { +#ifdef INET6 + if (_res_ext.sort_list[j].af != hp->h_addrtype) + continue; + sp = (u_char *)&_res_ext.sort_list[j].addr; + mp = (u_char *)&_res_ext.sort_list[j].mask; +#else + sp = (u_char *)&_res.sort_list[j].addr; + mp = (u_char *)&_res.sort_list[j].mask; +#endif + for (n = 0; n < hp->h_length; n++) { + if ((ap[n] & mp[n]) != sp[n]) + break; + } + if (n == hp->h_length) + break; + } + order[i] = j; + } + n = i; + pp = (u_char **)hp->h_addr_list; + for (i = 0; i < n - 1; i++) { + for (j = i + 1; j < n; j++) { + if (order[i] > order[j]) { + ap = pp[i]; + pp[i] = pp[j]; + pp[j] = ap; + t = order[i]; + order[i] = order[j]; + order[j] = t; + } + } + } + return hp; +} + +static char * +_hgetword(char **pp) +{ + char c, *p, *ret; + const char *sp; + static const char sep[] = "# \t\n"; + + ret = NULL; + for (p = *pp; (c = *p) != '\0'; p++) { + for (sp = sep; *sp != '\0'; sp++) { + if (c == *sp) + break; + } + if (c == '#') + p[1] = '\0'; /* ignore rest of line */ + if (ret == NULL) { + if (*sp == '\0') + ret = p; + } else { + if (*sp != '\0') { + *p++ = '\0'; + break; + } + } + } + *pp = p; + if (ret == NULL || *ret == '\0') + return NULL; + return ret; +} + +/* + * FILES (/etc/hosts) + */ + +static FILE * +_files_open(int *errp) +{ + FILE *fp; + fp = fopen(_PATH_HOSTS, "r"); + if (fp == NULL) + *errp = NO_RECOVERY; + return fp; +} + +static struct hostent * +_files_ghbyname(const char *name, int af, int *errp) +{ + int match, nalias; + char *p, *line, *addrstr, *cname; + FILE *fp; + struct hostent *rethp, *hp, hpbuf; + char *aliases[MAXALIASES + 1], *addrs[2]; + union inx_addr addrbuf; + char buf[BUFSIZ]; + + if ((fp = _files_open(errp)) == NULL) + return NULL; + rethp = hp = NULL; + + while (fgets(buf, sizeof(buf), fp)) { + line = buf; + if ((addrstr = _hgetword(&line)) == NULL + || (cname = _hgetword(&line)) == NULL) + continue; + match = (strcasecmp(cname, name) == 0); + nalias = 0; + while ((p = _hgetword(&line)) != NULL) { + if (!match) + match = (strcasecmp(p, name) == 0); + if (nalias < MAXALIASES) + aliases[nalias++] = p; + } + if (!match) + continue; + if (inet_pton(af, addrstr, &addrbuf) != 1) { + *errp = NO_DATA; /* name found */ + continue; + } + hp = &hpbuf; + hp->h_name = cname; + hp->h_aliases = aliases; + aliases[nalias] = NULL; + hp->h_addrtype = af; + hp->h_length = ADDRLEN(af); + hp->h_addr_list = addrs; + addrs[0] = (char *)&addrbuf; + addrs[1] = NULL; + hp = _hpcopy(hp, errp); + rethp = _hpmerge(rethp, hp, errp); + } + fclose(fp); + return rethp; +} + +static struct hostent * +_files_ghbyaddr(const void *addr, int addrlen, int af, int *errp) +{ + int nalias; + char *p, *line; + FILE *fp; + struct hostent *hp, hpbuf; + char *aliases[MAXALIASES + 1], *addrs[2]; + union inx_addr addrbuf; + char buf[BUFSIZ]; + + if ((fp = _files_open(errp)) == NULL) + return NULL; + hp = NULL; + while (fgets(buf, sizeof(buf), fp)) { + line = buf; + if ((p = _hgetword(&line)) == NULL + || inet_pton(af, p, &addrbuf) != 1 + || memcmp(addr, &addrbuf, addrlen) != 0 + || (p = _hgetword(&line)) == NULL) + continue; + hp = &hpbuf; + hp->h_name = p; + hp->h_aliases = aliases; + nalias = 0; + while ((p = _hgetword(&line)) != NULL) { + if (nalias < MAXALIASES) + aliases[nalias++] = p; + } + aliases[nalias] = NULL; + hp->h_addrtype = af; + hp->h_length = addrlen; + hp->h_addr_list = addrs; + addrs[0] = (char *)&addrbuf; + addrs[1] = NULL; + hp = _hpcopy(hp, errp); + break; + } + fclose(fp); + return hp; +} + +#ifdef DEBUG +#define DNS_ASSERT(X) if (!(X)) { fprintf(stderr, "ASSFAIL: %s %d: %s\n", __FILE__, __LINE__, #X); goto badanswer; } +#else +#define DNS_ASSERT(X) if (!(X)) { goto badanswer; } +#endif + +static struct hostent * +_dns_ghbyname(const char *name, int af, int *errp) +{ + int n; + u_char answer[BUFSIZ]; + char tbuf[MAXDNAME+1]; + HEADER *hp; + u_char *cp, *eom; + int qtype; + int type, class, ancount, qdcount; + u_long ttl; + char hostbuf[BUFSIZ]; + char *bp; + char *alist[MAXALIASES]; + char *hlist[MAXADDRS]; + struct hostent hbuf; + int buflen; + int na, nh; + + if ((_res.options & RES_INIT) == 0) { + if (res_init() < 0) { + *errp = h_errno; + return NULL; + } + } + hbuf.h_aliases = alist; + hbuf.h_addrtype = af; + hbuf.h_length = ADDRLEN(af); + hbuf.h_addr_list = hlist; + na = nh = 0; + +#ifdef INET6 + qtype = (af == AF_INET6 ? T_AAAA : T_A); +#else + qtype = T_A; +#endif + n = res_search(name, C_IN, qtype, answer, sizeof(answer)); + if (n < 0) { + *errp = h_errno; + return NULL; + } + hp = (HEADER *)answer; + eom = answer + n; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + DNS_ASSERT(qdcount == 1); + cp = answer + sizeof(HEADER); + bp = hostbuf; + buflen = sizeof(hostbuf); + + n = dn_expand(answer, eom, cp, bp, buflen); + DNS_ASSERT(n >= 0); + cp += n + QFIXEDSZ; + hbuf.h_name = bp; + n = strlen(bp) + 1; + bp += n; + buflen -= n; + while (ancount-- > 0 && cp < eom) { + n = dn_expand(answer, eom, cp, bp, buflen); + DNS_ASSERT(n >= 0); + cp += n; /* name */ + type = _getshort(cp); + cp += 2; /* type */ + class = _getshort(cp); + cp += 2; /* class */ + ttl = _getlong(cp); + cp += 4; /* ttl */ + n = _getshort(cp); + cp += 2; /* len */ + DNS_ASSERT(class == C_IN); + switch (type) { + case T_CNAME: + if (na >= MAXALIASES-1) { + cp += n; + break; + } + n = dn_expand(answer, eom, cp, tbuf, sizeof(tbuf)); + DNS_ASSERT(n >= 0); + cp += n; + /* alias */ + alist[na++] = bp; + n = strlen(bp) + 1; + bp += n; + buflen -= n; + /* canon */ + n = strlen(tbuf) + 1; + DNS_ASSERT(n < buflen); + strcpy(bp, tbuf); + hbuf.h_name = bp; + bp += n; + buflen -= n; + break; + case T_A: +#ifdef INET6 + case T_AAAA: +#endif + DNS_ASSERT(type == qtype); + bp = (char *)ALIGN(bp); + DNS_ASSERT(n == hbuf.h_length); + DNS_ASSERT(n < buflen); + if (nh < MAXADDRS-1) { + hlist[nh++] = bp; + memcpy(bp, cp, n); + bp += n; + buflen -= n; + } + cp += n; + break; + default: + DNS_ASSERT(0); + cp += n; + break; + } + } + if (nh == 0) { + badanswer: + *errp = NO_RECOVERY; + return NULL; + } + alist[na] = NULL; + hlist[nh] = NULL; + return _hpcopy(&hbuf, errp); +} + +static struct hostent * +_dns_ghbyaddr(const void *addr, int addrlen, int af, int *errp) +{ + int n; + u_char answer[BUFSIZ]; + HEADER *hp; + u_char c, *cp, *eom; + int type, class, ancount, qdcount; + u_long ttl; + char hostbuf[BUFSIZ]; + char *bp; + char *alist[MAXALIASES]; + char *hlist[2]; + struct hostent hbuf; + int buflen; + int na; +#ifdef INET6 + static const char hex[] = "0123456789abcdef"; +#endif + +#ifdef INET6 + /* XXX */ + if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr)) + return NULL; +#endif + + if ((_res.options & RES_INIT) == 0) { + if (res_init() < 0) { + *errp = h_errno; + return NULL; + } + } + hbuf.h_name = NULL; + hbuf.h_aliases = alist; + hbuf.h_addrtype = af; + hbuf.h_length = addrlen; + hbuf.h_addr_list = hlist; + hlist[0] = (char *)addr; + hlist[1] = NULL; + na = 0; + + n = 0; + bp = hostbuf; + cp = (u_char *)addr+addrlen-1; + switch (af) { +#ifdef INET6 + case AF_INET6: + for (; n < addrlen; n++, cp--) { + c = *cp; + *bp++ = hex[c & 0xf]; + *bp++ = '.'; + *bp++ = hex[c >> 4]; + *bp++ = '.'; + } + strcpy(bp, "ip6.int"); + break; +#endif + default: + for (; n < addrlen; n++, cp--) { + c = *cp; + if (c >= 100) + *bp++ = '0' + c / 100; + if (c >= 10) + *bp++ = '0' + (c % 100) / 10; + *bp++ = '0' + c % 10; + *bp++ = '.'; + } + strcpy(bp, "in-addr.arpa"); + break; + } + + n = res_query(hostbuf, C_IN, T_PTR, answer, sizeof(answer)); + if (n < 0) { + *errp = h_errno; + return NULL; + } + hp = (HEADER *)answer; + eom = answer + n; + ancount = ntohs(hp->ancount); + qdcount = ntohs(hp->qdcount); + DNS_ASSERT(qdcount == 1); + cp = answer + sizeof(HEADER); + bp = hostbuf; + buflen = sizeof(hostbuf); + + n = dn_expand(answer, eom, cp, bp, buflen); + DNS_ASSERT(n >= 0); + cp += n + QFIXEDSZ; + while (ancount-- > 0 && cp < eom) { + n = dn_expand(answer, eom, cp, bp, buflen); + DNS_ASSERT(n >= 0); + cp += n; /* name */ + type = _getshort(cp); + cp += 2; /* type */ + class = _getshort(cp); + cp += 2; /* class */ + ttl = _getlong(cp); + cp += 4; /* ttl */ + n = _getshort(cp); + cp += 2; /* len */ + DNS_ASSERT(class == C_IN); + switch (type) { + case T_PTR: + n = dn_expand(answer, eom, cp, bp, buflen); + DNS_ASSERT(n >= 0); + cp += n; + if (na >= MAXALIASES-1) + break; + if (hbuf.h_name == NULL) + hbuf.h_name = bp; + else + alist[na++] = bp; + n = strlen(bp) + 1; + bp += n; + buflen -= n; + break; + case T_CNAME: + cp += n; + break; + default: + badanswer: + *errp = NO_RECOVERY; + return NULL; + } + } + if (hbuf.h_name == NULL) { + *errp = h_errno; + return NULL; + } + alist[na] = NULL; + return _hpcopy(&hbuf, errp); +} + +#ifdef ICMPNL + +/* + * experimental: + * draft-ietf-ipngwg-icmp-namelookups-02.txt + * ifindex is assumed to be encoded in addr. + */ +#include +#include +#include + +struct _icmp_host_cache { + struct _icmp_host_cache *hc_next; + int hc_ifindex; + struct in6_addr hc_addr; + char *hc_name; +}; + +static char * +_icmp_fqdn_query(const struct in6_addr *addr, int ifindex) +{ + int s; + struct icmp6_filter filter; + struct msghdr msg; + struct cmsghdr *cmsg; + struct in6_pktinfo *pkt; + char cbuf[256]; + char buf[1024]; + int cc; + struct icmp6_fqdn_query *fq; + struct icmp6_fqdn_reply *fr; + struct _icmp_host_cache *hc; + struct sockaddr_in6 sin6; + struct iovec iov; + fd_set s_fds, fds; + struct timeval tout; + int len; + char *name; + static int pid; + static struct _icmp_host_cache *hc_head; + + for (hc = hc_head; hc; hc = hc->hc_next) { + if (hc->hc_ifindex == ifindex + && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) + return hc->hc_name; + } + + if (pid == 0) + pid = getpid(); + + ICMP6_FILTER_SETBLOCKALL(&filter); + ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter); + + FD_ZERO(&s_fds); + tout.tv_sec = 0; + tout.tv_usec = 200000; /*XXX: 200ms*/ + + fq = (struct icmp6_fqdn_query *)buf; + fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY; + fq->icmp6_fqdn_code = 0; + fq->icmp6_fqdn_cksum = 0; + fq->icmp6_fqdn_id = (u_short)pid; + fq->icmp6_fqdn_unused = 0; + fq->icmp6_fqdn_cookie[0] = 0; + fq->icmp6_fqdn_cookie[1] = 0; + + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = *addr; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = (caddr_t)&sin6; + msg.msg_namelen = sizeof(sin6); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + iov.iov_base = (caddr_t)buf; + iov.iov_len = sizeof(struct icmp6_fqdn_query); + + if (ifindex) { + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + pkt = (struct in6_pktinfo *)&cmsg[1]; + memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr)); + pkt->ipi6_ifindex = ifindex; + cmsg = CMSG_NXTHDR(&msg, cmsg); + msg.msg_controllen = (char *)cmsg - cbuf; + } + + if ((s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) + return NULL; + (void)setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, + (char *)&filter, sizeof(filter)); + cc = sendmsg(s, &msg, 0); + if (cc < 0) { + _libc_close(s); + return NULL; + } + FD_SET(s, &s_fds); + for (;;) { + fds = s_fds; + if (select(s + 1, &fds, NULL, NULL, &tout) <= 0) { + _libc_close(s); + return NULL; + } + len = sizeof(sin6); + cc = recvfrom(s, buf, sizeof(buf), 0, + (struct sockaddr *)&sin6, &len); + if (cc <= 0) { + _libc_close(s); + return NULL; + } + if (cc < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) + continue; + if (!IN6_ARE_ADDR_EQUAL(addr, &sin6.sin6_addr)) + continue; + fr = (struct icmp6_fqdn_reply *)(buf + sizeof(struct ip6_hdr)); + if (fr->icmp6_fqdn_type == ICMP6_FQDN_REPLY) + break; + } + _libc_close(s); + if (fr->icmp6_fqdn_cookie[1] != 0) { + /* rfc1788 type */ + name = buf + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr) + 4; + len = (buf + cc) - name; + } else { + len = fr->icmp6_fqdn_namelen; + name = fr->icmp6_fqdn_name; + } + if (len <= 0) + return NULL; + name[len] = 0; + + if ((hc = (struct _icmp_host_cache *)malloc(sizeof(*hc))) == NULL) + return NULL; + /* XXX: limit number of cached entries */ + hc->hc_ifindex = ifindex; + hc->hc_addr = *addr; + hc->hc_name = strdup(name); + hc->hc_next = hc_head; + hc_head = hc; + return hc->hc_name; +} + +static struct hostent * +_icmp_ghbyaddr(const void *addr, int addrlen, int af, int *errp) +{ + char *hname; + int ifindex; + struct in6_addr addr6; + + if (af != AF_INET6) { + /* + * Note: rfc1788 defines Who Are You for IPv4, + * but no one implements it. + */ + return NULL; + } + + memcpy(&addr6, addr, addrlen); + ifindex = (addr6.s6_addr[2] << 8) | addr6.s6_addr[3]; + addr6.s6_addr[2] = addr6.s6_addr[3] = 0; + + if (!IN6_IS_ADDR_LINKLOCAL(&addr6)) + return NULL; /*XXX*/ + + if ((hname = _icmp_fqdn_query(&addr6, ifindex)) == NULL) + return NULL; + return _hpaddr(af, hname, &addr6, errp); +} +#endif /* ICMPNL */ diff --git a/security/openssh/files/netdb.h b/security/openssh/files/netdb.h new file mode 100644 index 000000000000..1a6d68dc527d --- /dev/null +++ b/security/openssh/files/netdb.h @@ -0,0 +1,259 @@ +/*- + * Copyright (c) 1980, 1983, 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * - + * 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-- + */ + +/* + * @(#)netdb.h 8.1 (Berkeley) 6/2/93 + * From: Id: netdb.h,v 8.9 1996/11/19 08:39:29 vixie Exp $ + * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/netdb.h,v 1.1 2000-01-13 23:22:14 green Exp $ + */ + +#ifndef _NETDB_H_ +#define _NETDB_H_ + +#include +#include + +#ifndef _PATH_HEQUIV +# define _PATH_HEQUIV "/etc/hosts.equiv" +#endif +#define _PATH_HOSTS "/etc/hosts" +#define _PATH_NETWORKS "/etc/networks" +#define _PATH_PROTOCOLS "/etc/protocols" +#define _PATH_SERVICES "/etc/services" + +extern int h_errno; + +/* + * Structures returned by network data base library. All addresses are + * supplied in host order, and returned in network order (suitable for + * use in system calls). + */ +struct hostent { + char *h_name; /* official name of host */ + char **h_aliases; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + char **h_addr_list; /* list of addresses from name server */ +#define h_addr h_addr_list[0] /* address, for backward compatibility */ +}; + +/* + * Assumption here is that a network number + * fits in an unsigned long -- probably a poor one. + */ +struct netent { + char *n_name; /* official name of net */ + char **n_aliases; /* alias list */ + int n_addrtype; /* net address type */ + unsigned long n_net; /* network # */ +}; + +struct servent { + char *s_name; /* official service name */ + char **s_aliases; /* alias list */ + int s_port; /* port # */ + char *s_proto; /* protocol to use */ +}; + +struct protoent { + char *p_name; /* official protocol name */ + char **p_aliases; /* alias list */ + int p_proto; /* protocol # */ +}; + +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ + 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 */ +}; + +/* + * Error return codes from gethostbyname() and gethostbyaddr() + * (left in extern int h_errno). + */ + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +/* + * Error return codes from getaddrinfo() + */ +#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */ +#define EAI_AGAIN 2 /* temporary failure in name resolution */ +#define EAI_BADFLAGS 3 /* invalid value for ai_flags */ +#define EAI_FAIL 4 /* non-recoverable failure in name resolution */ +#define EAI_FAMILY 5 /* ai_family not supported */ +#define EAI_MEMORY 6 /* memory allocation failure */ +#define EAI_NODATA 7 /* no address associated with hostname */ +#define EAI_NONAME 8 /* hostname nor servname provided, or not known */ +#define EAI_SERVICE 9 /* servname not supported for ai_socktype */ +#define EAI_SOCKTYPE 10 /* ai_socktype not supported */ +#define EAI_SYSTEM 11 /* system error returned in errno */ +#define EAI_BADHINTS 12 +#define EAI_PROTOCOL 13 +#define EAI_RESNULL 14 +#define EAI_MAX 15 + +/* + * Flag values for getaddrinfo() + */ +#define AI_PASSIVE 0x00000001 /* get address to use bind() */ +#define AI_CANONNAME 0x00000002 /* fill ai_canonname */ +#define AI_NUMERICHOST 0x00000004 /* prevent name resolution */ +/* valid flags for addrinfo */ +#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST) + +#define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */ +#define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */ +#define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */ +#define AI_V4MAPPED 0x00000800 /* accept IPv4-mapped IPv6 address */ +/* special recommended flags for getipnodebyname */ +#define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG) + +/* + * Constants for getnameinfo() + */ +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 + +/* + * Flag values for getnameinfo() + */ +#define NI_NOFQDN 0x00000001 +#define NI_NUMERICHOST 0x00000002 +#define NI_NAMEREQD 0x00000004 +#define NI_NUMERICSERV 0x00000008 +#define NI_DGRAM 0x00000010 +#define NI_WITHSCOPEID 0x00000020 + +/* + * Scope delimit character + */ +#define SCOPE_DELIMITER '@' + +__BEGIN_DECLS +void endhostent __P((void)); +void endnetent __P((void)); +void endprotoent __P((void)); +void endservent __P((void)); +void freehostent __P((struct hostent *)); +struct hostent *gethostbyaddr __P((const char *, int, int)); +struct hostent *gethostbyname __P((const char *)); +struct hostent *gethostbyname2 __P((const char *, int)); +struct hostent *gethostent __P((void)); +struct hostent *getipnodebyaddr __P((const void *, size_t, int, int *)); +struct hostent *getipnodebyname __P((const char *, int, int, int *)); +struct netent *getnetbyaddr __P((unsigned long, int)); +struct netent *getnetbyname __P((const char *)); +struct netent *getnetent __P((void)); +struct protoent *getprotobyname __P((const char *)); +struct protoent *getprotobynumber __P((int)); +struct protoent *getprotoent __P((void)); +struct servent *getservbyname __P((const char *, const char *)); +struct servent *getservbyport __P((int, const char *)); +struct servent *getservent __P((void)); +void herror __P((const char *)); +__const char *hstrerror __P((int)); +void sethostent __P((int)); +/* void sethostfile __P((const char *)); */ +void setnetent __P((int)); +void setprotoent __P((int)); +int getaddrinfo __P((const char *, const char *, + const struct addrinfo *, struct addrinfo **)); +int getnameinfo __P((const struct sockaddr *, size_t, char *, + size_t, char *, size_t, int)); +void freeaddrinfo __P((struct addrinfo *)); +char *gai_strerror __P((int)); +void setservent __P((int)); + +/* + * PRIVATE functions specific to the FreeBSD implementation + */ + +/* DO NOT USE THESE, THEY ARE SUBJECT TO CHANGE AND ARE NOT PORTABLE!!! */ +void _sethosthtent __P((int)); +void _endhosthtent __P((void)); +void _sethostdnsent __P((int)); +void _endhostdnsent __P((void)); +void _setnethtent __P((int)); +void _endnethtent __P((void)); +void _setnetdnsent __P((int)); +void _endnetdnsent __P((void)); +struct hostent * _gethostbyhtname __P((const char *, int)); +struct hostent * _gethostbydnsname __P((const char *, int)); +struct hostent * _gethostbynisname __P((const char *, int)); +struct hostent * _gethostbyhtaddr __P((const char *, int, int)); +struct hostent * _gethostbydnsaddr __P((const char *, int, int)); +struct hostent * _gethostbynisaddr __P((const char *, int, int)); +struct netent * _getnetbyhtname __P((const char *)); +struct netent * _getnetbydnsname __P((const char *)); +struct netent * _getnetbynisname __P((const char *)); +struct netent * _getnetbyhtaddr __P((unsigned long, int)); +struct netent * _getnetbydnsaddr __P((unsigned long, int)); +struct netent * _getnetbynisaddr __P((unsigned long, int)); +void _map_v4v6_address __P((const char *src, char *dst)); +void _map_v4v6_hostent __P((struct hostent *hp, char **bp, int *len)); +__END_DECLS + +#endif /* !_NETDB_H_ */ diff --git a/security/openssh/files/patch-ab b/security/openssh/files/patch-ab index 60e0dd4334ee..e2da3f1e9758 100644 --- a/security/openssh/files/patch-ab +++ b/security/openssh/files/patch-ab @@ -1,6 +1,6 @@ ---- /usr/ports/distfiles/OpenSSH-1.2/src/usr.bin/ssh/Makefile.inc Mon Oct 25 16:27:26 1999 -+++ Makefile.inc Mon Nov 29 01:06:23 1999 -@@ -2,10 +2,14 @@ +--- Makefile.inc.orig Fri Jan 14 08:35:05 2000 ++++ Makefile.inc Fri Jan 14 08:40:03 2000 +@@ -2,10 +2,17 @@ .include @@ -16,6 +16,9 @@ +.if !defined(MAKEFILE_INC_FIRST_PASS) +MAKEFILE_INC_FIRST_PASS= 0 +CFLAGS+= -I${PREFIX}/include ++.if defined(USE_INET6) ++CFLAGS+= -DINET6 ++.endif LDADD+= -L${.CURDIR}/../lib -lssh DPADD+= ${.CURDIR}/../lib/libssh.a .endif diff --git a/security/openssh/files/patch-ac b/security/openssh/files/patch-ac index f6ad51c27c10..42a204e9484f 100644 --- a/security/openssh/files/patch-ac +++ b/security/openssh/files/patch-ac @@ -1,5 +1,5 @@ ---- /usr/ports/distfiles/OpenSSH-1.2/src/usr.bin/ssh/includes.h Tue Nov 2 16:21:02 1999 -+++ ./includes.h Tue Nov 23 19:20:38 1999 +--- /usr/ports/distfiles/OpenSSH-1.2.1/src/usr.bin/ssh/includes.h Sun Nov 28 16:37:35 1999 ++++ includes.h Thu Jan 13 18:03:48 2000 @@ -24,12 +24,12 @@ #include #include @@ -22,3 +22,37 @@ #include #include #include +@@ -65,5 +64,33 @@ + * client program. Socketpairs do not seem to work on all systems. + */ + #define USE_PIPES 1 ++ ++#if defined(__FreeBSD__) && __FreeBSD__ <= 3 ++/* ++ * Data types. ++ */ ++typedef u_char sa_family_t; ++typedef u_int32_t socklen_t; ++ ++/* ++ * bsd-api-new-02a: protocol-independent placeholder for socket addresses ++ */ ++#define _SS_MAXSIZE 128 ++#define _SS_ALIGNSIZE (sizeof(int64_t)) ++#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(u_char) * 2) ++#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(u_char) * 2 - \ ++ _SS_PAD1SIZE - _SS_ALIGNSIZE) ++ ++struct sockaddr_storage { ++ u_char __ss_len; /* address length */ ++ sa_family_t __ss_family; /* address family */ ++ char __ss_pad1[_SS_PAD1SIZE]; ++ int64_t __ss_align; /* force desired structure storage alignment */ ++ char __ss_pad2[_SS_PAD2SIZE]; ++}; ++#else ++#define ss_len __ss_len ++#define ss_family __ss_family ++#endif + + #endif /* INCLUDES_H */ diff --git a/security/openssh/files/patch-ad b/security/openssh/files/patch-ad index eb55f8ef07af..ee8482f484c0 100644 --- a/security/openssh/files/patch-ad +++ b/security/openssh/files/patch-ad @@ -1,16 +1,20 @@ ---- lib/Makefile.orig Tue Dec 7 22:50:49 1999 -+++ lib/Makefile Tue Dec 7 22:53:22 1999 -@@ -4,7 +4,8 @@ +--- lib/Makefile.orig Fri Jan 14 04:55:08 2000 ++++ lib/Makefile Fri Jan 14 08:01:17 2000 +@@ -4,7 +4,12 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \ cipher.c compat.c compress.c crc32.c deattack.c fingerprint.c \ hostfile.c log.c match.c mpaux.c nchan.c packet.c readpass.c \ - rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c + rsa.c tildexpand.c ttymodes.c uidswap.c xmalloc.c atomicio.c \ + strlcat.c strlcpy.c ++ ++.if !defined(USE_INET6) ++SRCS+= getaddrinfo.c getnameinfo.c name6.c rcmd.c bindresvport.c ++.endif NOPROFILE= yes NOPIC= yes -@@ -13,6 +14,7 @@ +@@ -13,6 +18,7 @@ @echo -n .include diff --git a/security/openssh/files/patch-an b/security/openssh/files/patch-an index 2c39339acaa0..9bbdf3348585 100644 --- a/security/openssh/files/patch-an +++ b/security/openssh/files/patch-an @@ -1,6 +1,6 @@ ---- sshd.c.orig Tue Dec 7 22:56:55 1999 -+++ sshd.c Tue Dec 7 22:58:36 1999 -@@ -24,6 +24,8 @@ +--- sshd.c.orig Fri Jan 7 01:32:03 2000 ++++ sshd.c Fri Jan 7 01:40:05 2000 +@@ -26,6 +26,8 @@ #include "servconf.h" #include "uidswap.h" #include "compat.h" @@ -9,7 +9,7 @@ #ifdef LIBWRAP #include -@@ -32,6 +34,16 @@ +@@ -34,6 +36,16 @@ int deny_severity = LOG_WARNING; #endif /* LIBWRAP */ @@ -26,7 +26,7 @@ #ifndef O_NOCTTY #define O_NOCTTY 0 #endif -@@ -118,6 +130,32 @@ +@@ -128,6 +140,32 @@ the private key. */ RSA *public_key; @@ -39,7 +39,7 @@ +const size_t MAGIC_CONNECTIONS_SIZE = 1; + +static __inline int -+magic_hash(struct sockaddr_in *sin) { ++magic_hash(struct sockaddr *sa) { + + return 0; +} @@ -59,17 +59,17 @@ /* Prototypes for various functions defined later in this file. */ void do_connection(); void do_authentication(char *user); -@@ -278,6 +316,7 @@ - extern char *optarg; +@@ -301,6 +339,7 @@ extern int optind; - int opt, aux, sock_in, sock_out, newsock, i, pid, on = 1; -+ int connections_per_period_exceeded = 0; + int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, pid, on = 1; + socklen_t fromlen; ++ int connections_per_period_exceeded = 0; int remote_major, remote_minor; int silentrsa = 0; - struct pollfd fds; -@@ -543,6 +582,12 @@ - /* Arrange SIGCHLD to be caught. */ - signal(SIGCHLD, main_sigchld_handler); + fd_set *fdset; +@@ -620,6 +659,12 @@ + fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)xmalloc(fdsetsz); + /* Initialize the magic_connections table. It's magical! */ + magic_connections = calloc(MAGIC_CONNECTIONS_SIZE, @@ -80,8 +80,8 @@ /* * Stay listening for connections until the system crashes or * the daemon is killed with a signal. -@@ -572,9 +617,31 @@ - error("accept: %.100s", strerror(errno)); +@@ -651,9 +696,31 @@ + error("newsock del O_NONBLOCK: %s", strerror(errno)); continue; } + if (options.connections_per_period != 0) { @@ -89,7 +89,7 @@ + struct magic_connection *mc; + + (void)gettimeofday(&connections_end, NULL); -+ mc = &magic_connections[magic_hash(&sin)]; ++ mc = &magic_connections[magic_hash(ai->ai_addr)]; + diff = timevaldiff(&mc->connections_begin, &connections_end); + if (diff.tv_sec >= options.connections_period) { + /* @@ -114,7 +114,7 @@ */ if (debug_flag) { /* -@@ -588,6 +655,12 @@ +@@ -667,6 +734,12 @@ sock_out = newsock; pid = getpid(); break; @@ -122,12 +122,12 @@ + log("Connection rate limit of %u/%us has been exceeded; " + "dropping connection from %s.", + options.connections_per_period, options.connections_period, -+ inet_ntoa(sin.sin_addr)); ++ ntop); + connections_per_period_exceeded = 0; } else { /* * Normal production daemon. Fork, and have -@@ -1065,6 +1138,14 @@ +@@ -1152,6 +1225,14 @@ return 0; } } @@ -142,7 +142,7 @@ /* We found no reason not to let this user try to log on... */ return 1; } -@@ -1100,6 +1181,9 @@ +@@ -1187,6 +1268,9 @@ pwcopy.pw_gid = pw->pw_gid; pwcopy.pw_dir = xstrdup(pw->pw_dir); pwcopy.pw_shell = xstrdup(pw->pw_shell); @@ -152,9 +152,9 @@ pw = &pwcopy; /* -@@ -1889,6 +1973,10 @@ - struct sockaddr_in from; - int fromlen; +@@ -1983,6 +2067,10 @@ + struct sockaddr_storage from; + socklen_t fromlen; struct pty_cleanup_context cleanup_context; +#ifdef LOGIN_CAP + login_cap_t *lc; @@ -163,7 +163,7 @@ /* Get remote host name. */ hostname = get_canonical_hostname(); -@@ -1953,6 +2041,12 @@ +@@ -2047,6 +2135,12 @@ /* Check if .hushlogin exists. */ snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir); quiet_login = stat(line, &st) >= 0; @@ -176,7 +176,7 @@ /* * If the user has logged in before, display the time of last -@@ -1976,6 +2070,20 @@ +@@ -2070,6 +2164,20 @@ else printf("Last login: %s from %s\r\n", time_string, buf); } @@ -197,7 +197,7 @@ /* * Print /etc/motd unless a command was specified or printing * it was disabled in server options or login(1) will be -@@ -1984,14 +2092,22 @@ +@@ -2078,14 +2186,22 @@ */ if (command == NULL && options.print_motd && !quiet_login && !options.use_login) { @@ -221,7 +221,7 @@ /* Do common processing for the child, such as execing the command. */ do_child(command, pw, term, display, auth_proto, auth_data, ttyname); /* NOTREACHED */ -@@ -2127,7 +2243,8 @@ +@@ -2221,7 +2337,8 @@ const char *display, const char *auth_proto, const char *auth_data, const char *ttyname) { @@ -231,7 +231,7 @@ char buf[256]; FILE *f; unsigned int envsize, i; -@@ -2135,15 +2252,34 @@ +@@ -2229,15 +2346,34 @@ extern char **environ; struct stat st; char *argv[10]; @@ -271,7 +271,7 @@ } /* Set login name in the kernel. */ if (setlogin(pw->pw_name) < 0) -@@ -2153,6 +2289,13 @@ +@@ -2247,6 +2383,13 @@ /* 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) { @@ -285,7 +285,7 @@ if (getuid() == 0 || geteuid() == 0) { if (setgid(pw->pw_gid) < 0) { perror("setgid"); -@@ -2175,7 +2318,14 @@ +@@ -2269,7 +2412,14 @@ * Get the shell from the password data. An empty shell field is * legal, and means /bin/sh. */ @@ -300,7 +300,7 @@ #ifdef AFS /* Try to get AFS tokens for the local cell. */ -@@ -2199,7 +2349,12 @@ +@@ -2293,7 +2443,12 @@ child_set_env(&env, &envsize, "USER", pw->pw_name); child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); child_set_env(&env, &envsize, "HOME", pw->pw_dir); @@ -313,17 +313,17 @@ snprintf(buf, sizeof buf, "%.200s/%.50s", _PATH_MAILDIR, pw->pw_name); -@@ -2289,6 +2444,9 @@ +@@ -2383,13 +2538,17 @@ */ endpwent(); - endhostent(); -+#ifdef LOGIN_CAP -+ login_close(lc); -+#endif /* LOGIN_CAP */ ++#ifdef LOGIN_CAP ++ login_close(lc); ++#endif /* LOGIN_CAP */ ++ /* * Close any extra open file descriptors so that we don\'t have them -@@ -2296,7 +2454,7 @@ + * 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. */ @@ -332,7 +332,7 @@ close(i); /* Change current directory to the user\'s home directory. */ -@@ -2315,6 +2473,26 @@ +@@ -2408,6 +2567,26 @@ * in this order). */ if (!options.use_login) { diff --git a/security/openssh/files/patch-ao b/security/openssh/files/patch-ao index 7ca746e1fb3a..0e5eac8dee2b 100644 --- a/security/openssh/files/patch-ao +++ b/security/openssh/files/patch-ao @@ -1,9 +1,9 @@ ---- /usr/ports/distfiles/OpenSSH-1.2/src/usr.bin/ssh/sshd_config Thu Nov 11 17:58:39 1999 -+++ sshd_config Sun Dec 5 13:37:20 1999 -@@ -2,12 +2,13 @@ - +--- sshd_config.orig Fri Jan 7 01:27:30 2000 ++++ sshd_config Fri Jan 7 01:31:01 2000 +@@ -3,12 +3,13 @@ Port 22 - ListenAddress 0.0.0.0 + #ListenAddress 0.0.0.0 + #ListenAddress :: -HostKey /etc/ssh_host_key +HostKey __PREFIX__/etc/ssh_host_key ServerKeyBits 768 diff --git a/security/openssh/files/patch-at b/security/openssh/files/patch-at new file mode 100644 index 000000000000..fbb18bc12079 --- /dev/null +++ b/security/openssh/files/patch-at @@ -0,0 +1,14 @@ +--- sshconnect.c- Fri Jan 14 08:44:43 2000 ++++ sshconnect.c Fri Jan 14 08:44:56 2000 +@@ -1078,9 +1078,11 @@ + case AF_INET: + local = (ntohl(((struct sockaddr_in *)hostaddr)->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; + break; ++#ifdef INET6 + case AF_INET6: + local = IN6_IS_ADDR_LOOPBACK(&(((struct sockaddr_in6 *)hostaddr)->sin6_addr)); + break; ++#endif + default: + local = 0; + break; diff --git a/security/openssh/files/rcmd.c b/security/openssh/files/rcmd.c new file mode 100644 index 000000000000..b33e44967e3e --- /dev/null +++ b/security/openssh/files/rcmd.c @@ -0,0 +1,653 @@ +/* + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: /tmp/pcvs/ports/security/openssh/files/Attic/rcmd.c,v 1.1 2000-01-13 23:22:15 green Exp $ + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef YP +#include +#include +#include +#endif + +#include "includes.h" + +/* wrapper for KAME-special getnameinfo() */ +#ifndef NI_WITHSCOPEID +#define NI_WITHSCOPEID 0 +#endif + +extern int innetgr __P(( const char *, const char *, const char *, const char * )); + +#define max(a, b) ((a > b) ? a : b) + +int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *)); +static int __icheckhost __P((void *, char *, int, int)); + +#define INET6_ADDRSTRLEN 46 +char paddr[INET6_ADDRSTRLEN]; + +int +rcmd(ahost, rport, locuser, remuser, cmd, fd2p) + char **ahost; + u_short rport; + const char *locuser, *remuser, *cmd; + int *fd2p; +{ + struct addrinfo hints, *res, *ai; + struct sockaddr_storage from; + fd_set reads; + long oldmask; + pid_t pid; + int s, aport, lport, timo, error; + char c; + int refused; + char num[8]; + + pid = getpid(); + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + (void)snprintf(num, sizeof(num), "%d", ntohs(rport)); + error = getaddrinfo(*ahost, num, &hints, &res); + if (error) { + fprintf(stderr, "rcmd: getaddrinfo: %s\n", + gai_strerror(error)); + if (error == EAI_SYSTEM) + fprintf(stderr, "rcmd: getaddrinfo: %s\n", + strerror(errno)); + return (-1); + } + if (res->ai_canonname) + *ahost = res->ai_canonname; + ai = res; + refused = 0; + oldmask = sigblock(sigmask(SIGURG)); + for (timo = 1, lport = IPPORT_RESERVED - 1;;) { + s = rresvport_af(&lport, ai->ai_family); + if (s < 0) { + if (errno == EAGAIN) + (void)fprintf(stderr, + "rcmd: socket: All ports in use\n"); + else + (void)fprintf(stderr, "rcmd: socket: %s\n", + strerror(errno)); + sigsetmask(oldmask); + freeaddrinfo(res); + return (-1); + } + fcntl(s, F_SETOWN, pid); + if (connect(s, ai->ai_addr, ai->ai_addrlen) >= 0) + break; + (void)close(s); + if (errno == EADDRINUSE) { + lport--; + continue; + } + if (errno == ECONNREFUSED) + refused = 1; + if (ai->ai_next != NULL) { + int oerrno = errno; + + getnameinfo(ai->ai_addr, ai->ai_addrlen, + paddr, sizeof(paddr), + NULL, 0, + NI_NUMERICHOST|NI_WITHSCOPEID); + (void)fprintf(stderr, "connect to address %s: ", + paddr); + errno = oerrno; + perror(0); + ai = ai->ai_next; + getnameinfo(ai->ai_addr, ai->ai_addrlen, + paddr, sizeof(paddr), + NULL, 0, + NI_NUMERICHOST|NI_WITHSCOPEID); + fprintf(stderr, "Trying %s...\n", paddr); + continue; + } + if (refused && timo <= 16) { + (void)sleep(timo); + timo *= 2; + ai = res; + refused = 0; + continue; + } + freeaddrinfo(res); + (void)fprintf(stderr, "%s: %s\n", *ahost, strerror(errno)); + sigsetmask(oldmask); + return (-1); + } + lport--; + if (fd2p == 0) { + write(s, "", 1); + lport = 0; + } else { + char num[8]; + int s2 = rresvport_af(&lport, ai->ai_family), s3; + int len = ai->ai_addrlen; + int nfds; + + if (s2 < 0) + goto bad; + listen(s2, 1); + (void)snprintf(num, sizeof(num), "%d", lport); + if (write(s, num, strlen(num)+1) != strlen(num)+1) { + (void)fprintf(stderr, + "rcmd: write (setting up stderr): %s\n", + strerror(errno)); + (void)close(s2); + goto bad; + } + nfds = max(s, s2)+1; + if(nfds > FD_SETSIZE) { + fprintf(stderr, "rcmd: too many files\n"); + (void)close(s2); + goto bad; + } +again: + FD_ZERO(&reads); + FD_SET(s, &reads); + FD_SET(s2, &reads); + errno = 0; + if (select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){ + if (errno != 0) + (void)fprintf(stderr, + "rcmd: select (setting up stderr): %s\n", + strerror(errno)); + else + (void)fprintf(stderr, + "select: protocol failure in circuit setup\n"); + (void)close(s2); + goto bad; + } + s3 = accept(s2, (struct sockaddr *)&from, &len); + switch (from.ss_family) { + case AF_INET: + aport = ntohs(((struct sockaddr_in *)&from)->sin_port); + break; +#ifdef INET6 + case AF_INET6: + aport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port); + break; +#endif + default: + aport = 0; /* error */ + break; + } + /* + * XXX careful for ftp bounce attacks. If discovered, shut them + * down and check for the real auxiliary channel to connect. + */ + if (aport == 20) { + close(s3); + goto again; + } + (void)close(s2); + if (s3 < 0) { + (void)fprintf(stderr, + "rcmd: accept: %s\n", strerror(errno)); + lport = 0; + goto bad; + } + *fd2p = s3; + if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) { + (void)fprintf(stderr, + "socket: protocol failure in circuit setup.\n"); + goto bad2; + } + } + (void)write(s, locuser, strlen(locuser)+1); + (void)write(s, remuser, strlen(remuser)+1); + (void)write(s, cmd, strlen(cmd)+1); + if (read(s, &c, 1) != 1) { + (void)fprintf(stderr, + "rcmd: %s: %s\n", *ahost, strerror(errno)); + goto bad2; + } + if (c != 0) { + while (read(s, &c, 1) == 1) { + (void)write(STDERR_FILENO, &c, 1); + if (c == '\n') + break; + } + goto bad2; + } + sigsetmask(oldmask); + freeaddrinfo(res); + return (s); +bad2: + if (lport) + (void)close(*fd2p); +bad: + (void)close(s); + sigsetmask(oldmask); + freeaddrinfo(res); + return (-1); +} + +int +rresvport(port) + int *port; +{ + return rresvport_af(port, AF_INET); +} + +int +rresvport_af(alport, family) + int *alport, family; +{ + int i, s, len, err; + struct sockaddr_storage ss; + u_short *sport; + + memset(&ss, 0, sizeof(ss)); + ss.ss_family = family; + switch (family) { + case AF_INET: + ss.ss_len = sizeof(struct sockaddr_in); + sport = &((struct sockaddr_in *)&ss)->sin_port; + ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY; + break; +#ifdef INET6 + case AF_INET6: + ss.ss_len = sizeof(struct sockaddr_in6); + sport = &((struct sockaddr_in6 *)&ss)->sin6_port; + ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any; + break; +#endif + default: + errno = EAFNOSUPPORT; + return -1; + } + + s = socket(ss.ss_family, SOCK_STREAM, 0); + if (s < 0) + return (-1); +#if 0 /* compat_exact_traditional_rresvport_semantics */ + sin.sin_port = htons((u_short)*alport); + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + return (s); + if (errno != EADDRINUSE) { + (void)close(s); + return (-1); + } +#endif + *sport = 0; + if (bindresvport2(s, (struct sockaddr *)&ss, ss.ss_len) == -1) { + (void)close(s); + return (-1); + } + *alport = (int)ntohs(*sport); + return (s); +} + +int __check_rhosts_file = 1; +char *__rcmd_errstr; + +int +ruserok(rhost, superuser, ruser, luser) + const char *rhost, *ruser, *luser; + int superuser; +{ + return ruserok_af(rhost, superuser, ruser, luser, AF_INET); +} + +int +ruserok_af(rhost, superuser, ruser, luser, af) + const char *rhost, *ruser, *luser; + int superuser, af; +{ + struct hostent *hp; + union { + struct in_addr addr_in; +#ifdef INET6 + struct in6_addr addr_in6; +#endif + } addr; + char **ap; + int ret, h_error; + + if ((hp = getipnodebyname(rhost, af, AI_DEFAULT, &h_error)) == NULL) + return (-1); + ret = -1; + for (ap = hp->h_addr_list; *ap; ++ap) { + bcopy(*ap, &addr, hp->h_length); + if (iruserok_af(&addr, superuser, ruser, luser, af) == 0) { + ret = 0; + break; + } + } + freehostent(hp); + return (ret); +} + +/* + * New .rhosts strategy: We are passed an ip address. We spin through + * hosts.equiv and .rhosts looking for a match. When the .rhosts only + * has ip addresses, we don't have to trust a nameserver. When it + * contains hostnames, we spin through the list of addresses the nameserver + * gives us and look for a match. + * + * Returns 0 if ok, -1 if not ok. + */ +int +iruserok(raddr, superuser, ruser, luser) + unsigned long raddr; + int superuser; + const char *ruser, *luser; +{ + return iruserok_af(&raddr, superuser, ruser, luser, AF_INET); +} + +int +iruserok_af(raddr, superuser, ruser, luser, af) + void *raddr; + int superuser; + const char *ruser, *luser; + int af; +{ + register char *cp; + struct stat sbuf; + struct passwd *pwd; + FILE *hostf; + uid_t uid; + int first; + char pbuf[MAXPATHLEN]; + int len = 0; + + switch (af) { + case AF_INET: + len = sizeof(struct in_addr); + break; +#ifdef INET6 + case AF_INET6: + len = sizeof(struct in6_addr); + break; +#endif + } + + first = 1; + hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); +again: + if (hostf) { + if (__ivaliduser_af(hostf, raddr, luser, ruser, af, len) + == 0) { + (void)fclose(hostf); + return (0); + } + (void)fclose(hostf); + } + if (first == 1 && (__check_rhosts_file || superuser)) { + first = 0; + if ((pwd = getpwnam(luser)) == NULL) + return (-1); + (void)strcpy(pbuf, pwd->pw_dir); + (void)strcat(pbuf, "/.rhosts"); + + /* + * Change effective uid while opening .rhosts. If root and + * reading an NFS mounted file system, can't read files that + * are protected read/write owner only. + */ + uid = geteuid(); + (void)seteuid(pwd->pw_uid); + hostf = fopen(pbuf, "r"); + (void)seteuid(uid); + + if (hostf == NULL) + return (-1); + /* + * If not a regular file, or is owned by someone other than + * user or root or if writeable by anyone but the owner, quit. + */ + cp = NULL; + if (lstat(pbuf, &sbuf) < 0) + cp = ".rhosts lstat failed"; + else if (!S_ISREG(sbuf.st_mode)) + cp = ".rhosts not regular file"; + else if (fstat(fileno(hostf), &sbuf) < 0) + cp = ".rhosts fstat failed"; + else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) + cp = "bad .rhosts owner"; + else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) + cp = ".rhosts writeable by other than owner"; + /* If there were any problems, quit. */ + if (cp) { + __rcmd_errstr = cp; + (void)fclose(hostf); + return (-1); + } + goto again; + } + return (-1); +} + +/* + * XXX + * Don't make static, used by lpd(8). + * + * Returns 0 if ok, -1 if not ok. + */ +int +__ivaliduser(hostf, raddr, luser, ruser) + FILE *hostf; + u_int32_t raddr; + const char *luser, *ruser; +{ + return __ivaliduser_af(hostf, &raddr, luser, ruser, AF_INET, + sizeof(raddr)); +} + +int +__ivaliduser_af(hostf, raddr, luser, ruser, af, len) + FILE *hostf; + void *raddr; + const char *luser, *ruser; + int af, len; +{ + register char *user, *p; + int ch; + char buf[MAXHOSTNAMELEN + 128]; /* host + login */ + char hname[MAXHOSTNAMELEN]; + struct hostent *hp; + /* Presumed guilty until proven innocent. */ + int userok = 0, hostok = 0; + int h_error; +#ifdef YP + char *ypdomain; + + if (yp_get_default_domain(&ypdomain)) + ypdomain = NULL; +#else +#define ypdomain NULL +#endif + /* We need to get the damn hostname back for netgroup matching. */ + if ((hp = getipnodebyaddr((char *)raddr, len, af, &h_error)) == NULL) + return (-1); + strncpy(hname, hp->h_name, sizeof(hname)); + hname[sizeof(hname) - 1] = '\0'; + freehostent(hp); + + while (fgets(buf, sizeof(buf), hostf)) { + p = buf; + /* Skip lines that are too long. */ + if (strchr(p, '\n') == NULL) { + while ((ch = getc(hostf)) != '\n' && ch != EOF); + continue; + } + if (*p == '\n' || *p == '#') { + /* comment... */ + continue; + } + while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { + *p = isupper((unsigned char)*p) ? tolower((unsigned char)*p) : *p; + p++; + } + if (*p == ' ' || *p == '\t') { + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + user = p; + while (*p != '\n' && *p != ' ' && + *p != '\t' && *p != '\0') + p++; + } else + user = p; + *p = '\0'; + /* + * Do +/- and +@/-@ checking. This looks really nasty, + * but it matches SunOS's behavior so far as I can tell. + */ + switch(buf[0]) { + case '+': + if (!buf[1]) { /* '+' matches all hosts */ + hostok = 1; + break; + } + if (buf[1] == '@') /* match a host by netgroup */ + hostok = innetgr((char *)&buf[2], + (char *)&hname, NULL, ypdomain); + else /* match a host by addr */ + hostok = __icheckhost(raddr,(char *)&buf[1], + af, len); + break; + case '-': /* reject '-' hosts and all their users */ + if (buf[1] == '@') { + if (innetgr((char *)&buf[2], + (char *)&hname, NULL, ypdomain)) + return(-1); + } else { + if (__icheckhost(raddr,(char *)&buf[1],af,len)) + return(-1); + } + break; + default: /* if no '+' or '-', do a simple match */ + hostok = __icheckhost(raddr, buf, af, len); + break; + } + switch(*user) { + case '+': + if (!*(user+1)) { /* '+' matches all users */ + userok = 1; + break; + } + if (*(user+1) == '@') /* match a user by netgroup */ + userok = innetgr(user+2, NULL, ruser, ypdomain); + else /* match a user by direct specification */ + userok = !(strcmp(ruser, user+1)); + break; + case '-': /* if we matched a hostname, */ + if (hostok) { /* check for user field rejections */ + if (!*(user+1)) + return(-1); + if (*(user+1) == '@') { + if (innetgr(user+2, NULL, + ruser, ypdomain)) + return(-1); + } else { + if (!strcmp(ruser, user+1)) + return(-1); + } + } + break; + default: /* no rejections: try to match the user */ + if (hostok) + userok = !(strcmp(ruser,*user ? user : luser)); + break; + } + if (hostok && userok) + return(0); + } + return (-1); +} + +/* + * Returns "true" if match, 0 if no match. + */ +static int +__icheckhost(raddr, lhost, af, len) + void *raddr; + register char *lhost; + int af, len; +{ + register struct hostent *hp; + char laddr[BUFSIZ]; /* xxx */ + register char **pp; + int h_error; + int match; + + /* Try for raw ip address first. */ + if (inet_pton(af, lhost, laddr) == 1) { + if (memcmp(raddr, laddr, len) == 0) + return (1); + else + return (0); + } + + /* Better be a hostname. */ + if ((hp = getipnodebyname(lhost, af, AI_DEFAULT, &h_error)) == NULL) + return (0); + + /* Spin through ip addresses. */ + match = 0; + for (pp = hp->h_addr_list; *pp; ++pp) + if (!bcmp(raddr, *pp, len)) { + match = 1; + break; + } + + freehostent(hp); + return (match); +}