summaryrefslogtreecommitdiffstats
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
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.
-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_