summaryrefslogtreecommitdiffstats
path: root/lib/libwrap
diff options
context:
space:
mode:
authorbeck <beck@openbsd.org>2001-02-16 02:15:58 +0000
committerbeck <beck@openbsd.org>2001-02-16 02:15:58 +0000
commitba00bdac23ea527c5a35d0d59a61880abc003c8d (patch)
treed9e5a1298b1ab3b261b0262a9d151804b38a85ff /lib/libwrap
parentMissing '.It' in a list, aaron@ ok (diff)
downloadwireguard-openbsd-ba00bdac23ea527c5a35d0d59a61880abc003c8d.tar.xz
wireguard-openbsd-ba00bdac23ea527c5a35d0d59a61880abc003c8d.zip
Rewrite rfc931.c to eliminate problematic setjmp/longjmp and stdio usage
on sockets. Adds new documented rfc1413 routine to do client side ident stuff. leaves compatible rfc931() routine in lib which calls new routine, incremenent shlib minor.
Diffstat (limited to 'lib/libwrap')
-rw-r--r--lib/libwrap/Makefile4
-rw-r--r--lib/libwrap/rfc1413.387
-rw-r--r--lib/libwrap/rfc931.c420
-rw-r--r--lib/libwrap/shlib_version2
-rw-r--r--lib/libwrap/tcpd.h3
5 files changed, 313 insertions, 203 deletions
diff --git a/lib/libwrap/Makefile b/lib/libwrap/Makefile
index 99cba9a7137..daf071de9b9 100644
--- a/lib/libwrap/Makefile
+++ b/lib/libwrap/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.4 2000/10/14 00:56:15 itojun Exp $
+# $OpenBSD: Makefile,v 1.5 2001/02/16 02:15:58 beck Exp $
LIB= wrap
SRCS= hosts_access.c options.c shell_cmd.c rfc931.c eval.c \
@@ -14,7 +14,7 @@ CFLAGS+=-DPROCESS_OPTIONS -DFACILITY=LOG_AUTH -DSEVERITY=LOG_INFO \
-DNETGROUP -DSYS_ERRLIST_DEFINED -D_TCPD_PRIVATE
CFLAGS+=-DINET6
-MAN= hosts_access.3 hosts_access.5 hosts_options.5
+MAN= hosts_access.3 hosts_access.5 hosts_options.5 rfc1413.3
MLINKS+=hosts_access.5 hosts.allow.5
MLINKS+=hosts_access.5 hosts.deny.5
MLINKS+=hosts_access.3 hosts_ctl.3
diff --git a/lib/libwrap/rfc1413.3 b/lib/libwrap/rfc1413.3
new file mode 100644
index 00000000000..f4b56f0e0e6
--- /dev/null
+++ b/lib/libwrap/rfc1413.3
@@ -0,0 +1,87 @@
+.\" $OpenBSD: rfc1413.3,v 1.1 2001/02/16 02:15:59 beck Exp $
+.\"
+.\" Copyright (c) 2001, Bob Beck. 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 Bob Beck for the
+.\" OpenBSD system.
+.\" 4. Neither the name(s) of the author(s) nor the name OpenBSD
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd Feb 10, 2001
+.Dt RFC1413 3
+.Os
+.Sh NAME
+.Nm rfc1413
+.Nd libwrap client side ident implementation.
+.Sh SYNOPSIS
+.Fd #include <tcpd.h>
+.Ft int
+.Fn rfc1413 "struct sockaddr *rmt_sin" "struct sockaddr *our_sin" "char *dest" "size_t dsize" "int ident_timeout_time"
+.Sh DESCRIPTION
+.Fn rfc1413
+retrieves a user name from a remote system using the
+.Nm ident
+protocol described in rfc 1413. It is implenented in the
+.Nm libwrap.a
+library.
+.Pp
+.Fn rfc1413
+takes two sockaddr pointers as parameters:
+.Nm rmt_sin
+for the remote host end of a connected TCP socket, and
+.Nm our_sin
+for the local end.
+.Nm dest
+should be allocated by the caller to store the found username,
+and must be of length at least
+.Nm dsize.
+.Nm ident_timeout_time
+is a timeout in seconds on the entire ident query, used to ensure
+that you don't wait forever for a slow or unresponsive remote host
+to answer the ident query.
+.Sh RETURN VALUES
+When username lookup is successful,
+.Fn rfc1413
+strips the trailing CRLF from the returned value and stores up to
+.Nm "dsize - 1"
+bytes of the returned username into
+.Nm dest,
+always terminating with a nul byte. In this case 0 is returned.
+.Fn rfc1413
+returns -1 if any failure occurs such that it was unable to
+retrieve the remote username.
+.Sh SEE ALSO
+.Xr hosts_access 3 ,
+.Sh BUGS
+.Pp
+The ident protocol only works on TCP sockets.
+.Pp
+Ident connections are made unencrypted, and nothing prevents the
+remote server from lying about who the user is. Consequently, ident
+should never be used to authenticate users. ident is however, quite
+useful for logging users of connections from multiuser machines that
+can be trusted not to lie about it.
+\" @(#) hosts_access.3 1.8 96/02/11 17:01:26
diff --git a/lib/libwrap/rfc931.c b/lib/libwrap/rfc931.c
index d5fbd128bcc..dc952f2bfdd 100644
--- a/lib/libwrap/rfc931.c
+++ b/lib/libwrap/rfc931.c
@@ -1,237 +1,259 @@
-/* $OpenBSD: rfc931.c,v 1.3 2001/02/15 20:55:12 beck Exp $ */
-
- /*
- * rfc931() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and RFC
- * 1413 protocols. It queries an RFC 931 etc. compatible daemon on a remote
- * host to look up the owner of a connection. The information should not be
- * used for authentication purposes. This routine intercepts alarm signals.
- *
- * Diagnostics are reported through syslog(3).
- *
- * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
- */
+/* $OpenBSD: rfc931.c,v 1.4 2001/02/16 02:15:59 beck Exp $ */
+
+/* rfc1413 does an attempt at an ident query to a client. Originally written
+ * by Wietse Venema, rewritten by Bob Beck <beck@openbsd.org> to avoid
+ * potential longjmp problems and get rid of stdio usage on sockets.
+ */
#ifndef lint
-#if 0
-static char sccsid[] = "@(#) rfc931.c 1.10 95/01/02 16:11:34";
-#else
-static char rcsid[] = "$OpenBSD: rfc931.c,v 1.3 2001/02/15 20:55:12 beck Exp $";
-#endif
+static char rcsid[] = "$OpenBSD: rfc931.c,v 1.4 2001/02/16 02:15:59 beck Exp $";
#endif
-/* System libraries. */
-
#include <stdio.h>
-#include <syslog.h>
#include <sys/types.h>
+#include <sys/time.h>
#include <sys/socket.h>
+#include <sys/uio.h>
#include <netinet/in.h>
-#include <setjmp.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
-/* Local stuff. */
+/* Local stuff for tcpd. */
#include "tcpd.h"
-#define RFC931_PORT 113 /* Semi-well-known port */
-#define ANY_PORT 0 /* Any old port will do */
-
-int rfc931_timeout = RFC931_TIMEOUT;/* Global so it can be changed */
+#define IDENT_PORT 113
-static jmp_buf timebuf;
+static sig_atomic_t ident_timeout;
-/* fsocket - open stdio stream on top of socket */
+int rfc931_timeout = RFC931_TIMEOUT; /* global, legacy from tcpwrapper stuff */
-static FILE *fsocket(domain, type, protocol)
-int domain;
-int type;
-int protocol;
-{
- int s;
- FILE *fp;
-
- if ((s = socket(domain, type, protocol)) < 0) {
- tcpd_warn("socket: %m");
- return (0);
- } else {
- if ((fp = fdopen(s, "r+")) == 0) {
- tcpd_warn("fdopen: %m");
- close(s);
- }
- return (fp);
- }
+static void
+timeout(s)
+ int s;
+{
+ ident_timeout = 1;
}
-/* timeout - handle timeouts */
+/*
+ * The old rfc931 from original libwrap for compatiblity. Now it calls
+ * rfc1413 with the default global parameters, but puts in the string
+ * "unknown" (from global unknown) on failure just like the original.
+ */
-static void timeout(sig)
-int sig;
+void
+rfc931(rmt_sin, our_sin, dest)
+ struct sockaddr *rmt_sin;
+ struct sockaddr *our_sin;
+ char *dest;
{
- longjmp(timebuf, sig);
+ if (rfc1413(rmt_sin, our_sin, dest, STRING_LENGTH, rfc931_timeout) ==
+ -1)
+ strlcpy(dest, unknown, STRING_LENGTH);
}
-/* rfc931 - return remote user name, given socket structures */
-void rfc931(rmt_sin, our_sin, dest)
-struct sockaddr *rmt_sin;
-struct sockaddr *our_sin;
-char *dest;
-{
- unsigned rmt_port;
- unsigned our_port;
- struct sockaddr_storage rmt_query_sin;
- struct sockaddr_storage our_query_sin;
- char user[256]; /* XXX */
- char buffer[512]; /* XXX */
- char *cp;
- char *result = unknown;
- FILE *fp;
- int salen;
- u_short *rmt_portp;
- u_short *our_portp;
-
- /* address family must be the same */
- if (rmt_sin->sa_family != our_sin->sa_family) {
- STRN_CPY(dest, result, STRING_LENGTH);
- return;
- }
- switch (rmt_sin->sa_family) {
- case AF_INET:
- salen = sizeof(struct sockaddr_in);
- rmt_portp = &(((struct sockaddr_in *)rmt_sin)->sin_port);
- break;
-#ifdef INET6
- case AF_INET6:
- salen = sizeof(struct sockaddr_in6);
- rmt_portp = &(((struct sockaddr_in6 *)rmt_sin)->sin6_port);
- break;
-#endif
- default:
- STRN_CPY(dest, result, STRING_LENGTH);
- return;
- }
- switch (our_sin->sa_family) {
- case AF_INET:
- our_portp = &(((struct sockaddr_in *)our_sin)->sin_port);
- break;
-#ifdef INET6
- case AF_INET6:
- our_portp = &(((struct sockaddr_in6 *)our_sin)->sin6_port);
- break;
-#endif
- default:
- STRN_CPY(dest, result, STRING_LENGTH);
- return;
- }
-
-#ifdef __GNUC__
- (void)&result; /* Avoid longjmp clobbering */
- (void)&fp; /* XXX gcc */
-#endif
+/*
+ * rfc1413, an rfc1413 client request for user name given a socket
+ * structure, with a timeout in seconds on the whole operation. On
+ * success returns 0 and saves dsize-1 characters of the username
+ * provided by remote ident daemon into "dest", stripping off any
+ * terminating CRLF, and terminating with a nul byte. Returns -1 on
+ * failure (timeout, remote daemon didn't answer, etc).
+ */
- /*
- * Use one unbuffered stdio stream for writing to and for reading from
- * the RFC931 etc. server. This is done because of a bug in the SunOS
- * 4.1.x stdio library. The bug may live in other stdio implementations,
- * too. When we use a single, buffered, bidirectional stdio stream ("r+"
- * or "w+" mode) we read our own output. Such behaviour would make sense
- * with resources that support random-access operations, but not with
- * sockets.
- */
+int
+rfc1413(rmt_sin, our_sin, dest, dsize, ident_timeout_time)
+ struct sockaddr *rmt_sin;
+ struct sockaddr *our_sin;
+ char *dest;
+ size_t dsize;
+ int ident_timeout_time;
+{
+ u_short rmt_port, our_port;
+ int s, i, gotit, salen;
+ char *cp;
+ u_short *rmt_portp;
+ u_short *our_portp;
+ fd_set *readfds = NULL;
+ fd_set *writefds = NULL;
+ struct sockaddr_storage rmt_query_sin;
+ struct sockaddr_storage our_query_sin;
+ struct sigaction new_sa, old_sa;
+ char user[256];
+ char tbuf[1024];
+
+ gotit = 0;
+ s = -1;
+
+ /* address family must be the same */
+ if (rmt_sin->sa_family != our_sin->sa_family)
+ goto out1;
+ switch (rmt_sin->sa_family) {
+ case AF_INET:
+ salen = sizeof(struct sockaddr_in);
+ rmt_portp = &(((struct sockaddr_in *)rmt_sin)->sin_port);
+ break;
+ case AF_INET6:
+ salen = sizeof(struct sockaddr_in6);
+ rmt_portp = &(((struct sockaddr_in6 *)rmt_sin)->sin6_port);
+ break;
+ default:
+ goto out1;
+ }
+ switch (our_sin->sa_family) {
+ case AF_INET:
+ our_portp = &(((struct sockaddr_in *)our_sin)->sin_port);
+ break;
+ case AF_INET6:
+ our_portp = &(((struct sockaddr_in6 *)our_sin)->sin6_port);
+ break;
+ default:
+ goto out1;
+ }
- if ((fp = fsocket(rmt_sin->sa_family, SOCK_STREAM, 0)) != 0) {
- setbuf(fp, (char *) 0);
+ if ((s = socket(rmt_sin->sa_family, SOCK_STREAM, 0)) == -1)
+ goto out1;
/*
* Set up a timer so we won't get stuck while waiting for the server.
+ * timer sets sig_atomic_t ident_timeout when it fires.
+ * this has to be checked after system calls in case we timed out.
*/
-
- if (setjmp(timebuf) == 0) {
- signal(SIGALRM, timeout);
- alarm(rfc931_timeout);
-
- /*
- * Bind the local and remote ends of the query socket to the same
- * IP addresses as the connection under investigation. We go
- * through all this trouble because the local or remote system
- * might have more than one network address. The RFC931 etc.
- * client sends only port numbers; the server takes the IP
- * addresses from the query socket.
- */
-
- memcpy(&our_query_sin, our_sin, salen);
- switch (our_query_sin.ss_family) {
- case AF_INET:
- ((struct sockaddr_in *)&our_query_sin)->sin_port =
- htons(ANY_PORT);
+
+ ident_timeout = 0;
+ memset(&new_sa, 0, sizeof(new_sa));
+ new_sa.sa_handler = timeout;
+ new_sa.sa_flags = SA_RESTART;
+ if (sigemptyset(&new_sa.sa_mask) == -1)
+ goto out1;
+ if (sigaction(SIGALRM, &new_sa, &old_sa) == -1)
+ goto out1;
+ alarm(ident_timeout_time);
+
+ /*
+ * Bind the local and remote ends of the query socket to the same
+ * IP addresses as the connection under investigation. We go
+ * through all this trouble because the local or remote system
+ * might have more than one network address. The IDENT etc.
+ * client sends only port numbers; the server takes the IP
+ * addresses from the query socket.
+ */
+
+ memcpy(&our_query_sin, our_sin, salen);
+ switch (our_query_sin.ss_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)&our_query_sin)->sin_port = htons(0);
break;
-#ifdef INET6
- case AF_INET6:
- ((struct sockaddr_in6 *)&our_query_sin)->sin6_port =
- htons(ANY_PORT);
+ case AF_INET6:
+ ((struct sockaddr_in6 *)&our_query_sin)->sin6_port = htons(0);
break;
-#endif
- }
- memcpy(&rmt_query_sin, rmt_sin, salen);
- switch (rmt_query_sin.ss_family) {
- case AF_INET:
+ }
+ memcpy(&rmt_query_sin, rmt_sin, salen);
+ switch (rmt_query_sin.ss_family) {
+ case AF_INET:
((struct sockaddr_in *)&rmt_query_sin)->sin_port =
- htons(RFC931_PORT);
+ htons(IDENT_PORT);
break;
-#ifdef INET6
- case AF_INET6:
- ((struct sockaddr_in6 *)&rmt_query_sin)->sin6_port =
- htons(RFC931_PORT);
+ case AF_INET6:
+ ((struct sockaddr_in6 *)&rmt_query_sin)->sin6_port =
+ htons(IDENT_PORT);
break;
-#endif
- }
-
- if (bind(fileno(fp), (struct sockaddr *) & our_query_sin,
- salen) >= 0 &&
- connect(fileno(fp), (struct sockaddr *) & rmt_query_sin,
- salen) >= 0) {
-
- /*
- * Send query to server. Neglect the risk that a 13-byte
- * write would have to be fragmented by the local system and
- * cause trouble with buggy System V stdio libraries.
- */
-
- fprintf(fp, "%u,%u\r\n",
- ntohs(*rmt_portp),
- ntohs(*our_portp));
- fflush(fp);
-
- /*
- * Read response from server. Use fgets()/sscanf() so we can
- * work around System V stdio libraries that incorrectly
- * assume EOF when a read from a socket returns less than
- * requested.
- */
-
- if (fgets(buffer, sizeof(buffer), fp) != 0
- && ferror(fp) == 0 && feof(fp) == 0
- && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s",
- &rmt_port, &our_port, user) == 3
- && ntohs(*rmt_portp) == rmt_port
- && ntohs(*our_portp) == our_port) {
-
- /*
- * Strip trailing carriage return. It is part of the
- * protocol, not part of the data.
- */
-
- cp = strchr(user, '\r');
- if (cp)
- *cp = 0;
- result = user;
- }
- }
- alarm(0);
}
- fclose(fp);
- }
- STRN_CPY(dest, result, STRING_LENGTH);
+
+ if (bind(s, (struct sockaddr *) & our_query_sin, salen) == -1)
+ goto out;
+ if ((connect(s, (struct sockaddr *) & rmt_query_sin, salen) == -1) ||
+ ident_timeout)
+ goto out;
+
+ /* We are connected, build an ident query and send it. */
+
+ readfds = calloc(howmany(s+1, NFDBITS), sizeof(fd_mask));
+ if (readfds == NULL)
+ goto out;
+ writefds = calloc(howmany(s+1, NFDBITS), sizeof(fd_mask));
+ if (writefds == NULL)
+ goto out;
+ snprintf(tbuf, sizeof(tbuf), "%u,%u\r\n", ntohs(*rmt_portp),
+ ntohs(*our_portp));
+ i = 0;
+ while (i < strlen(tbuf)) {
+ int j;
+
+ FD_ZERO(writefds);
+ FD_SET(s, writefds);
+ do {
+ j = select(s + 1, NULL, writefds, NULL, NULL);
+ if (ident_timeout)
+ goto out;
+ } while ( j == -1 && (errno == EAGAIN || errno == EINTR ));
+ if (j == -1)
+ goto out;
+ if (FD_ISSET(s, writefds)) {
+ j = write(s, tbuf + i, strlen(tbuf + i));
+ if ((j == -1 && errno != EAGAIN && errno != EINTR) ||
+ ident_timeout)
+ goto out;
+ if (j != -1)
+ i += j;
+ } else
+ goto out;
+ }
+
+
+ /* Read the answer back. */
+ i = 0;
+ tbuf[0] = '\0';
+ while ((cp = strchr(tbuf, '\n')) == NULL && i < sizeof(tbuf) - 1) {
+ int j;
+
+ FD_ZERO(readfds);
+ FD_SET(s, readfds);
+ do {
+ j = select(s + 1, readfds, NULL, NULL, NULL);
+ if (ident_timeout)
+ goto out;
+ } while ( j == -1 && (errno == EAGAIN || errno == EINTR ));
+ if (j == -1)
+ goto out;
+ if (FD_ISSET(s, readfds)) {
+ j = read(s, tbuf + i, sizeof(tbuf) - 1 - i);
+ if ((j == -1 && errno != EAGAIN && errno != EINTR) ||
+ j == 0 || ident_timeout)
+ goto out;
+ if (j != -1)
+ i += j;
+ tbuf[i] = '\0';
+ } else
+ goto out;
+ }
+
+ if ((sscanf(tbuf,"%u , %u : USERID :%*[^:]:%255s", &rmt_port,
+ &our_port, user) == 3) &&
+ (ntohs(*rmt_portp) == rmt_port) &&
+ (ntohs(*our_portp) == our_port)) {
+ if ((cp = strchr(user, '\r')) != NULL)
+ *cp = '\0';
+ gotit = 1;
+ }
+
+out:
+ alarm(0);
+ sigaction(SIGALRM, &old_sa, NULL);
+ if (readfds != NULL)
+ free(readfds);
+ if (writefds != NULL)
+ free(writefds);
+out1:
+ if (s != -1)
+ close(s);
+ if (gotit) {
+ strlcpy(dest, user, dsize);
+ return(0);
+ }
+ return(-1);
}
diff --git a/lib/libwrap/shlib_version b/lib/libwrap/shlib_version
index 893819d18ff..c8860078e50 100644
--- a/lib/libwrap/shlib_version
+++ b/lib/libwrap/shlib_version
@@ -1,2 +1,2 @@
major=1
-minor=1
+minor=2
diff --git a/lib/libwrap/tcpd.h b/lib/libwrap/tcpd.h
index 9c524c8749f..d4416327dbb 100644
--- a/lib/libwrap/tcpd.h
+++ b/lib/libwrap/tcpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcpd.h,v 1.8 2000/10/14 00:56:15 itojun Exp $ */
+/* $OpenBSD: tcpd.h,v 1.9 2001/02/16 02:15:59 beck Exp $ */
/*
* Copyright (c) 1997, Jason Downs. All rights reserved.
@@ -109,6 +109,7 @@ extern void shell_cmd __P((char *));
extern char *percent_m __P((char *, char *));
extern char *percent_x __P((char *, int, char *, struct request_info *));
extern void rfc931 __P((struct sockaddr *, struct sockaddr *, char *));
+extern int rfc1413 __P((struct sockaddr *, struct sockaddr *, char *, size_t, int));
extern void clean_exit __P((struct request_info *));
extern void refuse __P((struct request_info *));
#ifdef _STDIO_H_