1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate /* 9*7c478bd9Sstevel@tonic-gate * rfc931() speaks a common subset of the RFC 931, AUTH, TAP, IDENT and RFC 10*7c478bd9Sstevel@tonic-gate * 1413 protocols. It queries an RFC 931 etc. compatible daemon on a remote 11*7c478bd9Sstevel@tonic-gate * host to look up the owner of a connection. The information should not be 12*7c478bd9Sstevel@tonic-gate * used for authentication purposes. This routine intercepts alarm signals. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * Diagnostics are reported through syslog(3). 15*7c478bd9Sstevel@tonic-gate * 16*7c478bd9Sstevel@tonic-gate * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. 17*7c478bd9Sstevel@tonic-gate */ 18*7c478bd9Sstevel@tonic-gate 19*7c478bd9Sstevel@tonic-gate #ifndef lint 20*7c478bd9Sstevel@tonic-gate static char sccsid[] = "@(#) rfc931.c 1.10 95/01/02 16:11:34"; 21*7c478bd9Sstevel@tonic-gate #endif 22*7c478bd9Sstevel@tonic-gate 23*7c478bd9Sstevel@tonic-gate /* System libraries. */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate #include <stdio.h> 26*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 27*7c478bd9Sstevel@tonic-gate #include <unistd.h> 28*7c478bd9Sstevel@tonic-gate #include <syslog.h> 29*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 31*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 32*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 33*7c478bd9Sstevel@tonic-gate #include <signal.h> 34*7c478bd9Sstevel@tonic-gate #include <string.h> 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate /* Local stuff. */ 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #include "tcpd.h" 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #define RFC931_PORT 113 /* Semi-well-known port */ 41*7c478bd9Sstevel@tonic-gate #define ANY_PORT 0 /* Any old port will do */ 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate int rfc931_timeout = RFC931_TIMEOUT;/* Global so it can be changed */ 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate static jmp_buf timebuf; 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* fsocket - open stdio stream on top of socket */ 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate static FILE *fsocket(domain, type, protocol) 50*7c478bd9Sstevel@tonic-gate int domain; 51*7c478bd9Sstevel@tonic-gate int type; 52*7c478bd9Sstevel@tonic-gate int protocol; 53*7c478bd9Sstevel@tonic-gate { 54*7c478bd9Sstevel@tonic-gate int s; 55*7c478bd9Sstevel@tonic-gate FILE *fp; 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate if ((s = socket(domain, type, protocol)) < 0) { 58*7c478bd9Sstevel@tonic-gate tcpd_warn("socket: %m"); 59*7c478bd9Sstevel@tonic-gate return (0); 60*7c478bd9Sstevel@tonic-gate } else { 61*7c478bd9Sstevel@tonic-gate if ((fp = fdopen(s, "r+")) == 0) { 62*7c478bd9Sstevel@tonic-gate tcpd_warn("fdopen: %m"); 63*7c478bd9Sstevel@tonic-gate close(s); 64*7c478bd9Sstevel@tonic-gate } 65*7c478bd9Sstevel@tonic-gate return (fp); 66*7c478bd9Sstevel@tonic-gate } 67*7c478bd9Sstevel@tonic-gate } 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate /* timeout - handle timeouts */ 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate static void timeout(sig) 72*7c478bd9Sstevel@tonic-gate int sig; 73*7c478bd9Sstevel@tonic-gate { 74*7c478bd9Sstevel@tonic-gate longjmp(timebuf, sig); 75*7c478bd9Sstevel@tonic-gate } 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* rfc931 - return remote user name, given socket structures */ 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate void rfc931(rmt_sin, our_sin, dest) 80*7c478bd9Sstevel@tonic-gate struct sockaddr_gen *rmt_sin; 81*7c478bd9Sstevel@tonic-gate struct sockaddr_gen *our_sin; 82*7c478bd9Sstevel@tonic-gate char *dest; 83*7c478bd9Sstevel@tonic-gate { 84*7c478bd9Sstevel@tonic-gate unsigned rmt_port; 85*7c478bd9Sstevel@tonic-gate unsigned our_port; 86*7c478bd9Sstevel@tonic-gate struct sockaddr_gen rmt_query_sin; 87*7c478bd9Sstevel@tonic-gate struct sockaddr_gen our_query_sin; 88*7c478bd9Sstevel@tonic-gate char user[256]; /* XXX */ 89*7c478bd9Sstevel@tonic-gate char buffer[512]; /* XXX */ 90*7c478bd9Sstevel@tonic-gate char *cp; 91*7c478bd9Sstevel@tonic-gate char *result = unknown; 92*7c478bd9Sstevel@tonic-gate FILE *fp; 93*7c478bd9Sstevel@tonic-gate unsigned saved_timeout = 0; 94*7c478bd9Sstevel@tonic-gate struct sigaction nact, oact; 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate * Use one unbuffered stdio stream for writing to and for reading from 98*7c478bd9Sstevel@tonic-gate * the RFC931 etc. server. This is done because of a bug in the SunOS 99*7c478bd9Sstevel@tonic-gate * 4.1.x stdio library. The bug may live in other stdio implementations, 100*7c478bd9Sstevel@tonic-gate * too. When we use a single, buffered, bidirectional stdio stream ("r+" 101*7c478bd9Sstevel@tonic-gate * or "w+" mode) we read our own output. Such behaviour would make sense 102*7c478bd9Sstevel@tonic-gate * with resources that support random-access operations, but not with 103*7c478bd9Sstevel@tonic-gate * sockets. 104*7c478bd9Sstevel@tonic-gate */ 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate if ((fp = fsocket(SGFAM(rmt_sin), SOCK_STREAM, 0)) != 0) { 107*7c478bd9Sstevel@tonic-gate setbuf(fp, (char *) 0); 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate /* 110*7c478bd9Sstevel@tonic-gate * Set up a timer so we won't get stuck while waiting for the server. 111*7c478bd9Sstevel@tonic-gate */ 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate if (setjmp(timebuf) == 0) { 114*7c478bd9Sstevel@tonic-gate /* 115*7c478bd9Sstevel@tonic-gate * save the pending time in case the caller has armed an alarm. 116*7c478bd9Sstevel@tonic-gate */ 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate saved_timeout = alarm(0); 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate /* 121*7c478bd9Sstevel@tonic-gate * It's guaranteed to enter this 'if' condition on the direct 122*7c478bd9Sstevel@tonic-gate * invocation of setjmp and hence no additional checks while 123*7c478bd9Sstevel@tonic-gate * restoring the signal handler. 124*7c478bd9Sstevel@tonic-gate * Now, get the old handler and set the new one 125*7c478bd9Sstevel@tonic-gate */ 126*7c478bd9Sstevel@tonic-gate nact.sa_handler = timeout; 127*7c478bd9Sstevel@tonic-gate nact.sa_flags = 0; 128*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&nact.sa_mask); 129*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &nact, &oact); 130*7c478bd9Sstevel@tonic-gate alarm(rfc931_timeout); 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* 133*7c478bd9Sstevel@tonic-gate * Bind the local and remote ends of the query socket to the same 134*7c478bd9Sstevel@tonic-gate * IP addresses as the connection under investigation. We go 135*7c478bd9Sstevel@tonic-gate * through all this trouble because the local or remote system 136*7c478bd9Sstevel@tonic-gate * might have more than one network address. The RFC931 etc. 137*7c478bd9Sstevel@tonic-gate * client sends only port numbers; the server takes the IP 138*7c478bd9Sstevel@tonic-gate * addresses from the query socket. 139*7c478bd9Sstevel@tonic-gate */ 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate our_query_sin = *our_sin; 142*7c478bd9Sstevel@tonic-gate SGPORT(&our_query_sin) = htons(ANY_PORT); 143*7c478bd9Sstevel@tonic-gate rmt_query_sin = *rmt_sin; 144*7c478bd9Sstevel@tonic-gate SGPORT(&rmt_query_sin) = htons(RFC931_PORT); 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate if (bind(fileno(fp), (struct sockaddr *) &our_query_sin, 147*7c478bd9Sstevel@tonic-gate SGSOCKADDRSZ(&our_query_sin)) >= 0 && 148*7c478bd9Sstevel@tonic-gate connect(fileno(fp), (struct sockaddr *) &rmt_query_sin, 149*7c478bd9Sstevel@tonic-gate SGSOCKADDRSZ(&rmt_query_sin)) >= 0) { 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate /* 152*7c478bd9Sstevel@tonic-gate * Send query to server. Neglect the risk that a 13-byte 153*7c478bd9Sstevel@tonic-gate * write would have to be fragmented by the local system and 154*7c478bd9Sstevel@tonic-gate * cause trouble with buggy System V stdio libraries. 155*7c478bd9Sstevel@tonic-gate */ 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate fprintf(fp, "%u,%u\r\n", 158*7c478bd9Sstevel@tonic-gate ntohs(SGPORT(rmt_sin)), 159*7c478bd9Sstevel@tonic-gate ntohs(SGPORT(our_sin))); 160*7c478bd9Sstevel@tonic-gate fflush(fp); 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * Read response from server. Use fgets()/sscanf() so we can 164*7c478bd9Sstevel@tonic-gate * work around System V stdio libraries that incorrectly 165*7c478bd9Sstevel@tonic-gate * assume EOF when a read from a socket returns less than 166*7c478bd9Sstevel@tonic-gate * requested. 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate if (fgets(buffer, sizeof(buffer), fp) != 0 170*7c478bd9Sstevel@tonic-gate && ferror(fp) == 0 && feof(fp) == 0 171*7c478bd9Sstevel@tonic-gate && sscanf(buffer, "%u , %u : USERID :%*[^:]:%255s", 172*7c478bd9Sstevel@tonic-gate &rmt_port, &our_port, user) == 3 173*7c478bd9Sstevel@tonic-gate && ntohs(SGPORT(rmt_sin)) == rmt_port 174*7c478bd9Sstevel@tonic-gate && ntohs(SGPORT(our_sin)) == our_port) { 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate /* 177*7c478bd9Sstevel@tonic-gate * Strip trailing carriage return. It is part of the 178*7c478bd9Sstevel@tonic-gate * protocol, not part of the data. 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate 181*7c478bd9Sstevel@tonic-gate if (cp = strchr(user, '\r')) 182*7c478bd9Sstevel@tonic-gate *cp = 0; 183*7c478bd9Sstevel@tonic-gate result = user; 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate alarm(0); 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate /* Restore the old handler */ 189*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &oact, NULL); 190*7c478bd9Sstevel@tonic-gate if (saved_timeout > 0) 191*7c478bd9Sstevel@tonic-gate alarm(saved_timeout); 192*7c478bd9Sstevel@tonic-gate fclose(fp); 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate STRN_CPY(dest, result, STRING_LENGTH); 195*7c478bd9Sstevel@tonic-gate } 196