2 * (c) Copyright 1992 by Panagiotis Tsirigotis
3 * (c) Sections Copyright 1998-2001 by Rob Braun
4 * All rights reserved. The file named COPYRIGHT specifies the terms
5 * and conditions for redistribution.
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
30 #include "connection.h"
36 static char *get_line( int sd, register char *buf, unsigned bufsize );
37 static char *verify_line( char *line, unsigned local_port, unsigned remote_port );
40 #define IBUFSIZE 1024 /* RFC-1413 suggests 1000 */
42 #define START_TIMER( t ) (void) alarm( t )
43 #define STOP_TIMER() (void) alarm( 0 )
47 static sigjmp_buf env ;
50 __attribute__ ((noreturn))
52 static void sigalrm_handler(int signum)
54 siglongjmp( env, 1 ) ;
59 * This function always runs in a forked process.
61 idresult_e log_remote_user( const struct server *serp, unsigned timeout )
63 static char buf[ IBUFSIZE ] ;
65 union xsockaddr sin_local, sin_remote, sin_contact, sin_bind;
66 volatile unsigned local_port;
67 volatile unsigned remote_port;
71 const char *func = "log_remote_user" ;
73 if ( timeout && signal( SIGALRM, sigalrm_handler ) == SIG_ERR )
75 msg( LOG_ERR, func, "signal: %m" ) ;
80 * Determine local and remote addresses
82 sin_len = sizeof( sin_local ) ;
83 if ( getsockname( SERVER_FD( serp ), &sin_local.sa, &sin_len ) == -1 )
85 msg( LOG_ERR, func, "(%d) getsockname: %m", getpid() ) ;
89 if ( CONN_XADDRESS( SERVER_CONNECTION( serp ) ) == NULL )
92 * This shouldn't happen since identification only works for
93 * connection-based services.
95 msg( LOG_ERR, func, "connection has no address" ) ;
100 sin_remote = *CONN_XADDRESS( SERVER_CONNECTION( serp ) ) ;
101 sin_contact = sin_remote;
102 memcpy( &sin_bind, &sin_local, sizeof(sin_bind) ) ;
105 if( sin_remote.sa.sa_family == AF_INET ) {
106 local_port = ntohs( sin_local.sa_in6.sin6_port ) ;
107 remote_port = ntohs( sin_remote.sa_in6.sin6_port ) ;
108 sin_contact.sa_in6.sin6_port = htons( IDENTITY_SERVICE_PORT ) ;
109 sin_bind.sa_in.sin_port = 0 ;
110 } else if( sin_remote.sa.sa_family == AF_INET6 ) {
111 local_port = ntohs( sin_local.sa_in.sin_port ) ;
112 remote_port = ntohs( sin_remote.sa_in.sin_port ) ;
113 sin_contact.sa_in.sin_port = htons( IDENTITY_SERVICE_PORT ) ;
114 sin_bind.sa_in6.sin6_port = 0 ;
118 * Create a socket, bind it, and set the close-on-exec flag on the
119 * descriptor. We set the flag in case we are called as part of a
120 * successful attempt to start a server (i.e. execve will follow).
121 * The socket must be bound to the receiving address or ident might
122 * fail for multi-homed hosts.
124 sd = socket( sin_remote.sa.sa_family, SOCK_STREAM, 0 ) ;
127 msg( LOG_ERR, func, "socket creation: %m" ) ;
128 return( IDR_ERROR ) ;
130 if ( bind(sd, &sin_bind.sa, sizeof(sin_bind.sa)) == -1 )
132 msg( LOG_ERR, func, "socket bind: %m" ) ;
133 (void) Sclose( sd ) ;
134 return( IDR_ERROR ) ;
136 if ( fcntl( sd, F_SETFD, FD_CLOEXEC ) == -1 )
138 msg( LOG_ERR, func, "fcntl F_SETFD: %m" ) ;
139 (void) Sclose( sd ) ;
140 return( IDR_ERROR ) ;
144 if ( sigsetjmp( env, 1 ) == 0 )
145 START_TIMER( timeout ) ;
148 return( IDR_TIMEDOUT ) ;
152 if ( connect( sd, &sin_contact.sa, sizeof( sin_contact ) ) == -1 )
156 signal ( SIGALRM, SIG_DFL ) ;
159 return( IDR_NOSERVER ) ;
162 cc = strx_nprint( buf, sizeof( buf ),
163 "%d,%d\r\n", remote_port, local_port ) ;
164 if ( write_buf( sd, buf, cc ) == FAILED )
168 signal ( SIGALRM, SIG_DFL ) ;
171 return( IDR_ERROR ) ;
174 p = get_line( sd, buf, sizeof( buf ) ) ;
178 signal ( SIGALRM, SIG_DFL ) ;
183 return( IDR_RESPERR ) ;
187 * Verify that the received line is OK
189 if ( ( p = verify_line( buf, local_port, remote_port ) ) == NULL )
191 msg(LOG_ERR, func, "Bad line received from identity server at %s: %s",
192 xaddrname( &sin_remote ), buf ) ;
194 return( IDR_BADRESP ) ;
197 svc_logprint( SERVER_CONNSERVICE( serp ), USERID_ENTRY, "%s", p ) ;
202 static char *verify_line( char *line,
204 unsigned remote_port )
211 * Verify port numbers
213 p = strchr( start, ',' ) ;
217 if ( parse_base10( start, &port ) ||
218 port < 0 || (unsigned)port != remote_port ) {
225 p = strchr( start, ':' ) ;
229 if ( parse_base10( start, &port ) ||
230 port < 0 || (unsigned)port != local_port ) {
237 * Look for the 'USERID' string
240 const char *line_id = "USERID" ;
241 unsigned int line_id_len = strlen( line_id ) ;
244 for ( p = start ; isspace( *p ) ; p++ ) ;
248 if ( strncmp( start, line_id, line_id_len ) != 0 )
250 start += line_id_len ; /* skip it */
253 for ( p = start ; isspace( *p ) ; p++ ) ; /* skip any white-space */
256 for ( p++ ; isspace( *p ) ; p++ ) ;
264 * Get a line terminated by CR-LF.
265 * Replace the CR-LF with NUL.
267 static char *get_line( int sd, char *buf, unsigned bufsize )
273 const char *func = "get_line" ;
275 for ( p = buf, size = bufsize ; size > 0 ; p += cc, size -= cc )
277 cc = read( sd, p, size ) ;
279 if ( errno == EINTR )
286 msg( LOG_ERR, func, "read: %m" ) ;
287 return( CHAR_NULL ) ;
293 msg( LOG_ERR, func, "identd server reply missing ending CR-LF" ) ;
294 return( CHAR_NULL ) ;
296 for ( s = p ; s < p + cc ; s++ )
298 if ( (*s == '\n') && (s != buf) && (*(s-1) == '\r') )
305 msg( LOG_ERR, func, "Too much input from identity server" ) ;
306 return( CHAR_NULL ) ;
310 const char *idresult_explain( idresult_e result )
312 const char *reason = "UNKNOWN" ;
317 reason = "no error" ;
321 reason = "no server" ;
329 reason = "system error" ;
333 reason = "error while receiving response" ;
337 reason = "bad response" ;