/* * rfc931_user() speaks a common subset of the RFC 931, AUTH, TAP and IDENT * protocols. It consults an RFC 931 etc. compatible daemon on the client * host to look up the remote user name. The information should not be used * for authentication purposes. * * Diagnostics are reported through syslog(3). * * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. * * Inspired by the authutil package (comp.sources.unix volume 22) by Dan * Bernstein (brnstnd@kramden.acf.nyu.edu). */ #ifndef lint static char sccsid[] = "@(#) rfc931.c 1.4 93/03/07 22:47:52"; #endif #include #include #include #include #include #include #include /*#include "log_tcp.h"*/ #define RFC931_PORT 113 /* Semi-well-known port */ #ifndef RFC931_TIMEOUT #define RFC931_TIMEOUT 30 /* wait for at most 30 seconds */ #endif extern char *strchr(); extern char *inet_ntoa(); static jmp_buf timebuf; /* timeout - handle timeouts */ static void timeout(sig) int sig; { longjmp(timebuf, sig); } /* rfc931_name - return remote user name */ char *my_rfc931_name(herefd,there) int herefd; struct sockaddr_in *there; /* remote link information */ { struct sockaddr_in here; /* local link information */ struct sockaddr_in sin; /* for talking to RFC931 daemon */ int length; int s; unsigned remote; unsigned local; static char user[256]; /* XXX */ char buffer[512]; /* YYY */ FILE *fp; char *cp; char *result = "unknown"; /* Find out local address and port number of stdin. */ length = sizeof(here); if (getsockname(herefd, (struct sockaddr *) & here, &length) == -1) { syslog(LOG_ERR, "getsockname: %m"); return (result); } /* * The socket that will be used for user name lookups should be bound to * the same local IP address as stdin. This will automagically happen on * hosts that have only one IP network address. When the local host has * more than one IP network address, we must do an explicit bind() call. */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) return (result); sin = here; sin.sin_port = 0; if (bind(s, (struct sockaddr *) & sin, sizeof sin) < 0) { syslog(LOG_ERR, "bind: %s: %m", inet_ntoa(here.sin_addr)); return (result); } /* Set up timer so we won't get stuck. */ signal(SIGALRM, timeout); if (setjmp(timebuf)) { close(s); /* not: fclose(fp) */ return (result); } alarm(RFC931_TIMEOUT); /* Connect to the RFC931 daemon. */ sin = *there; sin.sin_port = htons(RFC931_PORT); if (connect(s, (struct sockaddr *) & sin, sizeof(sin)) == -1 || (fp = fdopen(s, "w+")) == 0) { close(s); alarm(0); return (result); } /* * Use unbuffered I/O or we may read back our own query. setbuf() must be * called before doing any I/O on the stream. Thanks for the reminder, * Paul Kranenburg ! */ setbuf(fp, (char *) 0); /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */ fprintf(fp, "%u,%u\r\n", ntohs(there->sin_port), ntohs(here.sin_port)); fflush(fp); /* * Read response from server. Use fgets()/sscanf() instead of fscanf() * because there is no buffer for pushback. Thanks, Chris Turbeville * . */ if (fgets(buffer, sizeof(buffer), fp) != 0 && ferror(fp) == 0 && feof(fp) == 0 && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3 && ntohs(there->sin_port) == remote && ntohs(here.sin_port) == local) { /* Strip trailing carriage return. */ if (cp = strchr(user, '\r')) *cp = 0; result = user; } alarm(0); fclose(fp); return (result); }