diff options
author | 2001-02-16 02:15:58 +0000 | |
---|---|---|
committer | 2001-02-16 02:15:58 +0000 | |
commit | ba00bdac23ea527c5a35d0d59a61880abc003c8d (patch) | |
tree | d9e5a1298b1ab3b261b0262a9d151804b38a85ff | |
parent | Missing '.It' in a list, aaron@ ok (diff) | |
download | wireguard-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/Makefile | 4 | ||||
-rw-r--r-- | lib/libwrap/rfc1413.3 | 87 | ||||
-rw-r--r-- | lib/libwrap/rfc931.c | 420 | ||||
-rw-r--r-- | lib/libwrap/shlib_version | 2 | ||||
-rw-r--r-- | lib/libwrap/tcpd.h | 3 |
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_ |