summaryrefslogtreecommitdiff
path: root/rfc931.c
diff options
context:
space:
mode:
Diffstat (limited to 'rfc931.c')
-rw-r--r--rfc931.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/rfc931.c b/rfc931.c
new file mode 100644
index 0000000..8176417
--- /dev/null
+++ b/rfc931.c
@@ -0,0 +1,165 @@
+ /*
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) rfc931.c 1.10 95/01/02 16:11:34";
+#endif
+
+/* System libraries. */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <string.h>
+
+/* Local stuff. */
+
+#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 */
+
+static jmp_buf timebuf;
+
+/* fsocket - open stdio stream on top of socket */
+
+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);
+ }
+}
+
+/* timeout - handle timeouts */
+
+static void timeout(sig)
+int sig;
+{
+ longjmp(timebuf, sig);
+}
+
+/* rfc931 - return remote user name, given socket structures */
+
+void rfc931(rmt_sin, our_sin, dest)
+struct sockaddr_in *rmt_sin;
+struct sockaddr_in *our_sin;
+char *dest;
+{
+ unsigned rmt_port;
+ unsigned our_port;
+ struct sockaddr_in rmt_query_sin;
+ struct sockaddr_in our_query_sin;
+ char user[256]; /* XXX */
+ char buffer[512]; /* XXX */
+ char *cp;
+ char *result = unknown;
+ FILE *fp;
+
+ /*
+ * 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.
+ */
+
+ if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) {
+ setbuf(fp, (char *) 0);
+
+ /*
+ * Set up a timer so we won't get stuck while waiting for the server.
+ */
+
+ 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.
+ */
+
+ our_query_sin = *our_sin;
+ our_query_sin.sin_port = htons(ANY_PORT);
+ rmt_query_sin = *rmt_sin;
+ rmt_query_sin.sin_port = htons(RFC931_PORT);
+
+ if (bind(fileno(fp), (struct sockaddr *) & our_query_sin,
+ sizeof(our_query_sin)) >= 0 &&
+ connect(fileno(fp), (struct sockaddr *) & rmt_query_sin,
+ sizeof(rmt_query_sin)) >= 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_sin->sin_port),
+ ntohs(our_sin->sin_port));
+ 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_sin->sin_port) == rmt_port
+ && ntohs(our_sin->sin_port) == our_port) {
+
+ /*
+ * Strip trailing carriage return. It is part of the
+ * protocol, not part of the data.
+ */
+
+ if (cp = strchr(user, '\r'))
+ *cp = 0;
+ result = user;
+ }
+ }
+ alarm(0);
+ }
+ fclose(fp);
+ }
+ STRN_CPY(dest, result, STRING_LENGTH);
+}