144743Smarkm /* 244743Smarkm * rfc931() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and RFC 344743Smarkm * 1413 protocols. It queries an RFC 931 etc. compatible daemon on a remote 444743Smarkm * host to look up the owner of a connection. The information should not be 544743Smarkm * used for authentication purposes. This routine intercepts alarm signals. 644743Smarkm * 744743Smarkm * Diagnostics are reported through syslog(3). 844743Smarkm * 944743Smarkm * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 1056977Sshin * 1156977Sshin * $FreeBSD: stable/10/contrib/tcp_wrappers/rfc931.c 311814 2017-01-09 20:14:02Z dim $ 1244743Smarkm */ 1344743Smarkm 1444743Smarkm#ifndef lint 1544743Smarkmstatic char sccsid[] = "@(#) rfc931.c 1.10 95/01/02 16:11:34"; 1644743Smarkm#endif 1744743Smarkm 1844743Smarkm/* System libraries. */ 1944743Smarkm 2044743Smarkm#include <stdio.h> 2144743Smarkm#include <syslog.h> 2244743Smarkm#include <sys/types.h> 2344743Smarkm#include <sys/socket.h> 2444743Smarkm#include <netinet/in.h> 2544743Smarkm#include <setjmp.h> 2644743Smarkm#include <signal.h> 2744743Smarkm#include <string.h> 28311814Sdim#include <unistd.h> 2944743Smarkm 3063152Sdwmalone#ifndef SEEK_SET 3163152Sdwmalone#define SEEK_SET 0 3263152Sdwmalone#endif 3363152Sdwmalone 3444743Smarkm/* Local stuff. */ 3544743Smarkm 3644743Smarkm#include "tcpd.h" 3744743Smarkm 3844743Smarkm#define RFC931_PORT 113 /* Semi-well-known port */ 3944743Smarkm#define ANY_PORT 0 /* Any old port will do */ 4044743Smarkm 4144743Smarkmint rfc931_timeout = RFC931_TIMEOUT;/* Global so it can be changed */ 4244743Smarkm 4344743Smarkmstatic jmp_buf timebuf; 4444743Smarkm 4544743Smarkm/* fsocket - open stdio stream on top of socket */ 4644743Smarkm 4744743Smarkmstatic FILE *fsocket(domain, type, protocol) 4844743Smarkmint domain; 4944743Smarkmint type; 5044743Smarkmint protocol; 5144743Smarkm{ 5244743Smarkm int s; 5344743Smarkm FILE *fp; 5444743Smarkm 5544743Smarkm if ((s = socket(domain, type, protocol)) < 0) { 5644743Smarkm tcpd_warn("socket: %m"); 5744743Smarkm return (0); 5844743Smarkm } else { 5944743Smarkm if ((fp = fdopen(s, "r+")) == 0) { 6044743Smarkm tcpd_warn("fdopen: %m"); 6144743Smarkm close(s); 6244743Smarkm } 6344743Smarkm return (fp); 6444743Smarkm } 6544743Smarkm} 6644743Smarkm 6744743Smarkm/* timeout - handle timeouts */ 6844743Smarkm 6944743Smarkmstatic void timeout(sig) 7044743Smarkmint sig; 7144743Smarkm{ 7244743Smarkm longjmp(timebuf, sig); 7344743Smarkm} 7444743Smarkm 7544743Smarkm/* rfc931 - return remote user name, given socket structures */ 7644743Smarkm 7744743Smarkmvoid rfc931(rmt_sin, our_sin, dest) 7856977Sshin#ifdef INET6 7956977Sshinstruct sockaddr *rmt_sin; 8056977Sshinstruct sockaddr *our_sin; 8156977Sshin#else 8244743Smarkmstruct sockaddr_in *rmt_sin; 8344743Smarkmstruct sockaddr_in *our_sin; 8456977Sshin#endif 8544743Smarkmchar *dest; 8644743Smarkm{ 8744743Smarkm unsigned rmt_port; 8844743Smarkm unsigned our_port; 8956977Sshin#ifdef INET6 9056977Sshin struct sockaddr_storage rmt_query_sin; 9156977Sshin struct sockaddr_storage our_query_sin; 9256977Sshin int alen; 9356977Sshin#else 9444743Smarkm struct sockaddr_in rmt_query_sin; 9544743Smarkm struct sockaddr_in our_query_sin; 9656977Sshin#endif 9744743Smarkm char user[256]; /* XXX */ 9844743Smarkm char buffer[512]; /* XXX */ 9944743Smarkm char *cp; 10044743Smarkm char *result = unknown; 10144743Smarkm FILE *fp; 10244743Smarkm 10356977Sshin#ifdef INET6 10456977Sshin /* address family must be the same */ 10556977Sshin if (rmt_sin->sa_family != our_sin->sa_family) { 10656977Sshin STRN_CPY(dest, result, STRING_LENGTH); 10756977Sshin return; 10856977Sshin } 10956977Sshin switch (our_sin->sa_family) { 11056977Sshin case AF_INET: 11156977Sshin alen = sizeof(struct sockaddr_in); 11256977Sshin break; 11356977Sshin case AF_INET6: 11456977Sshin alen = sizeof(struct sockaddr_in6); 11556977Sshin break; 11656977Sshin default: 11756977Sshin STRN_CPY(dest, result, STRING_LENGTH); 11856977Sshin return; 11956977Sshin } 12056977Sshin#endif 12156977Sshin 12244743Smarkm /* 12363152Sdwmalone * If we use a single, buffered, bidirectional stdio stream ("r+" or 12463152Sdwmalone * "w+" mode) we may read our own output. Such behaviour would make sense 12544743Smarkm * with resources that support random-access operations, but not with 12663152Sdwmalone * sockets. ANSI C suggests several functions which can be called when 12763152Sdwmalone * you want to change IO direction, fseek seems the most portable. 12844743Smarkm */ 12944743Smarkm 13056977Sshin#ifdef INET6 13156977Sshin if ((fp = fsocket(our_sin->sa_family, SOCK_STREAM, 0)) != 0) { 13256977Sshin#else 13344743Smarkm if ((fp = fsocket(AF_INET, SOCK_STREAM, 0)) != 0) { 13456977Sshin#endif 13544743Smarkm /* 13644743Smarkm * Set up a timer so we won't get stuck while waiting for the server. 13744743Smarkm */ 13844743Smarkm 13944743Smarkm if (setjmp(timebuf) == 0) { 14044743Smarkm signal(SIGALRM, timeout); 14144743Smarkm alarm(rfc931_timeout); 14244743Smarkm 14344743Smarkm /* 14444743Smarkm * Bind the local and remote ends of the query socket to the same 14544743Smarkm * IP addresses as the connection under investigation. We go 14644743Smarkm * through all this trouble because the local or remote system 14744743Smarkm * might have more than one network address. The RFC931 etc. 14844743Smarkm * client sends only port numbers; the server takes the IP 14944743Smarkm * addresses from the query socket. 15044743Smarkm */ 15144743Smarkm 15256977Sshin#ifdef INET6 15356977Sshin memcpy(&our_query_sin, our_sin, alen); 15456977Sshin memcpy(&rmt_query_sin, rmt_sin, alen); 15556977Sshin switch (our_sin->sa_family) { 15656977Sshin case AF_INET: 15756977Sshin ((struct sockaddr_in *)&our_query_sin)->sin_port = htons(ANY_PORT); 15856977Sshin ((struct sockaddr_in *)&rmt_query_sin)->sin_port = htons(RFC931_PORT); 15956977Sshin break; 16056977Sshin case AF_INET6: 16156977Sshin ((struct sockaddr_in6 *)&our_query_sin)->sin6_port = htons(ANY_PORT); 16256977Sshin ((struct sockaddr_in6 *)&rmt_query_sin)->sin6_port = htons(RFC931_PORT); 16356977Sshin break; 16456977Sshin } 16556977Sshin 16656977Sshin if (bind(fileno(fp), (struct sockaddr *) & our_query_sin, 16756977Sshin alen) >= 0 && 16856977Sshin connect(fileno(fp), (struct sockaddr *) & rmt_query_sin, 16956977Sshin alen) >= 0) { 17056977Sshin#else 17144743Smarkm our_query_sin = *our_sin; 17244743Smarkm our_query_sin.sin_port = htons(ANY_PORT); 17344743Smarkm rmt_query_sin = *rmt_sin; 17444743Smarkm rmt_query_sin.sin_port = htons(RFC931_PORT); 17544743Smarkm 17644743Smarkm if (bind(fileno(fp), (struct sockaddr *) & our_query_sin, 17744743Smarkm sizeof(our_query_sin)) >= 0 && 17844743Smarkm connect(fileno(fp), (struct sockaddr *) & rmt_query_sin, 17944743Smarkm sizeof(rmt_query_sin)) >= 0) { 18056977Sshin#endif 18144743Smarkm 18244743Smarkm /* 18344743Smarkm * Send query to server. Neglect the risk that a 13-byte 18444743Smarkm * write would have to be fragmented by the local system and 18544743Smarkm * cause trouble with buggy System V stdio libraries. 18644743Smarkm */ 18744743Smarkm 18844743Smarkm fprintf(fp, "%u,%u\r\n", 18956977Sshin#ifdef INET6 19056977Sshin ntohs(((struct sockaddr_in *)rmt_sin)->sin_port), 19156977Sshin ntohs(((struct sockaddr_in *)our_sin)->sin_port)); 19256977Sshin#else 19344743Smarkm ntohs(rmt_sin->sin_port), 19444743Smarkm ntohs(our_sin->sin_port)); 19556977Sshin#endif 19644743Smarkm fflush(fp); 19763152Sdwmalone fseek(fp, 0, SEEK_SET); 19844743Smarkm 19944743Smarkm /* 20044743Smarkm * Read response from server. Use fgets()/sscanf() so we can 20144743Smarkm * work around System V stdio libraries that incorrectly 20244743Smarkm * assume EOF when a read from a socket returns less than 20344743Smarkm * requested. 20444743Smarkm */ 20544743Smarkm 20644743Smarkm if (fgets(buffer, sizeof(buffer), fp) != 0 20744743Smarkm && ferror(fp) == 0 && feof(fp) == 0 20844743Smarkm && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s", 20944743Smarkm &rmt_port, &our_port, user) == 3 21056977Sshin#ifdef INET6 21156977Sshin && ntohs(((struct sockaddr_in *)rmt_sin)->sin_port) == rmt_port 21256977Sshin && ntohs(((struct sockaddr_in *)our_sin)->sin_port) == our_port) { 21356977Sshin#else 21444743Smarkm && ntohs(rmt_sin->sin_port) == rmt_port 21544743Smarkm && ntohs(our_sin->sin_port) == our_port) { 21656977Sshin#endif 21744743Smarkm 21844743Smarkm /* 21944743Smarkm * Strip trailing carriage return. It is part of the 22044743Smarkm * protocol, not part of the data. 22144743Smarkm */ 22244743Smarkm 22344743Smarkm if (cp = strchr(user, '\r')) 22444743Smarkm *cp = 0; 22544743Smarkm result = user; 22644743Smarkm } 22744743Smarkm } 22844743Smarkm alarm(0); 22944743Smarkm } 23044743Smarkm fclose(fp); 23144743Smarkm } 23244743Smarkm STRN_CPY(dest, result, STRING_LENGTH); 23344743Smarkm} 234