/*
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <setjmp.h>
#include <signal.h>
#include "osdep.h"
/* #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, (socklen_t *) &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 <pk@cs.few.eur.nl>!
*/
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
* <turbo@cse.uta.edu>.
*/
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);
}