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