static void dgram_chargen( const struct server *serp ) { char buf[ BUFFER_SIZE ] ; char *p ; unsigned int len ; union xsockaddr lsin ; socklen_t sin_len = 0 ; int fd = SERVER_FD( serp ) ; unsigned int left = sizeof( buf ) ; const char *func = "dgram_chargen"; if ( SC_IPV4( SVC_CONF( SERVER_SERVICE( serp ) ) ) ) sin_len = sizeof( struct sockaddr_in ); else if ( SC_IPV6( SVC_CONF( SERVER_SERVICE( serp ) ) ) ) sin_len = sizeof( struct sockaddr_in6 ); if ( recvfrom( fd, buf, sizeof( buf ), 0, SA( &lsin ), &sin_len ) == -1 ) return ; #if BUFFER_SIZE < LINE_LENGTH+2 bad_variable = 1 ; /* this will cause a compilation error */ #endif for ( p = buf ; left > 2 ; left -= len, p += len ) { len = min( LINE_LENGTH+2, left ) ; if ( generate_line( p, len ) == NULL ) break ; } (void) sendto( fd, buf, p-buf, 0, SA( &lsin ), sin_len ) ; }
static void stream_discard( const struct server *serp ) { char buf[ BUFFER_SIZE ] ; int cc ; int descriptor = SERVER_FD( serp ) ; struct service *svc = SERVER_SERVICE( serp ) ;; if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } close_all_svc_descriptors(); for ( ;; ) { cc = read( descriptor, buf, sizeof( buf ) ) ; if ( (cc == 0) || ((cc == -1) && (errno != EINTR)) ) break ; } if( SVC_WAITS( svc ) ) /* Service forks, so close it */ Sclose(descriptor); }
static void stream_chargen( const struct server *serp ) { char line_buf[ LINE_LENGTH+2 ] ; int descriptor = SERVER_FD( serp ) ; struct service *svc = SERVER_SERVICE( serp ); if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } (void) shutdown( descriptor, 0 ) ; close_all_svc_descriptors(); for ( ;; ) { if ( generate_line( line_buf, sizeof( line_buf ) ) == NULL ) break ; if ( write_buf( descriptor, line_buf, sizeof( line_buf ) ) == FAILED ) break ; } if( SVC_WAITS( svc ) ) /* Service forks, so close it */ Sclose(descriptor); }
static void dgram_echo( const struct server *serp ) { char buf[ DATAGRAM_SIZE ] ; union xsockaddr lsin; ssize_t cc ; socklen_t sin_len = 0; int descriptor = SERVER_FD( serp ) ; if( SC_IPV4( SVC_CONF( SERVER_SERVICE( serp ) ) ) ) sin_len = sizeof( struct sockaddr_in ); else if( SC_IPV6( SVC_CONF( SERVER_SERVICE( serp ) ) ) ) sin_len = sizeof( struct sockaddr_in6 ); cc = recvfrom( descriptor, buf, sizeof( buf ), 0, (struct sockaddr *)( &lsin ), &sin_len ) ; if ( cc != (ssize_t)-1 ) { (void) sendto( descriptor, buf, (size_t)cc, 0, SA( &lsin ), sizeof( lsin ) ) ; } }
static void stream_daytime( const struct server *serp ) { char time_buf[ BUFFER_SIZE ] ; unsigned int buflen = sizeof( time_buf ) ; int descriptor = SERVER_FD( serp ) ; struct service *svc = SERVER_SERVICE( serp ) ;; if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } daytime_protocol( time_buf, &buflen ) ; (void) write_buf( descriptor, time_buf, buflen ) ; Sclose(descriptor); }
static void dgram_time( const struct server *serp ) { char buf[ 1 ] ; unsigned char time_buf[4]; union xsockaddr lsin ; socklen_t sin_len = 0 ; int fd = SERVER_FD( serp ) ; const char *func = "dgram_daytime"; if ( SC_IPV4( SVC_CONF( SERVER_SERVICE( serp ) ) ) ) sin_len = sizeof( struct sockaddr_in ); else if ( SC_IPV6( SVC_CONF( SERVER_SERVICE( serp ) ) ) ) sin_len = sizeof( struct sockaddr_in6 ); if ( recvfrom( fd, buf, sizeof( buf ), 0, SA( &lsin ), &sin_len ) == -1 ) return ; time_protocol( time_buf ) ; (void) sendto( fd, (char *) time_buf, 4, 0, SA( &lsin ), sin_len ) ; }
static void stream_time( const struct server *serp ) { unsigned char time_buf[4]; int descriptor = SERVER_FD( serp ); struct service *svc = SERVER_SERVICE( serp ); if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } time_protocol( time_buf ) ; (void) write_buf( descriptor, (char *) time_buf, 4 ) ; Sclose(descriptor); }
static void dgram_daytime( const struct server *serp ) { char time_buf[ BUFFER_SIZE ] ; union xsockaddr lsin ; socklen_t sin_len = 0 ; unsigned int buflen = sizeof( time_buf ) ; int descriptor = SERVER_FD( serp ) ; const char *func = "dgram_daytime"; if ( SC_IPV4( SVC_CONF( SERVER_SERVICE( serp ) ) ) ) sin_len = sizeof( struct sockaddr_in ); else if ( SC_IPV6( SVC_CONF( SERVER_SERVICE( serp ) ) ) ) sin_len = sizeof( struct sockaddr_in6 ); if ( recvfrom( descriptor, time_buf, sizeof( time_buf ), 0, SA( &lsin ), &sin_len ) == -1 ) return ; daytime_protocol( time_buf, &buflen ) ; (void) sendto( descriptor, time_buf, buflen, 0, SA(&lsin), sizeof( lsin ) ) ; }
static void stream_echo( const struct server *serp ) { char buf[ BUFFER_SIZE ] ; ssize_t cc ; int descriptor = SERVER_FD( serp ) ; struct service *svc = SERVER_SERVICE( serp ) ;; if( SVC_WAITS( svc ) ) { descriptor = accept(descriptor, NULL, NULL); if ( descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(svc, "no available descriptors"); return; } } close_all_svc_descriptors(); for ( ;; ) { cc = read( descriptor, buf, sizeof( buf ) ) ; if ( cc == 0 ) break ; if ( cc == (ssize_t)-1 ) { if ( errno == EINTR ) continue ; else break ; } if ( write_buf( descriptor, buf, cc ) == FAILED ) break ; } if( SVC_WAITS( svc ) ) /* Service forks, so close it */ Sclose(descriptor); }
/* This function gets called from child.c after we have been forked */ void redir_handler( struct server *serp ) { struct service *sp = SERVER_SERVICE( serp ); struct service_config *scp = SVC_CONF( sp ); int RedirDescrip = SERVER_FD( serp ); int maxfd, num_read, num_wrote=0, ret=0; unsigned int sin_len = 0; unsigned long bytes_in = 0, bytes_out = 0; int no_to_nagle = 1; int on = 1, v6on; char buff[NET_BUFFER]; fd_set rdfd, msfd; struct timeval *timep = NULL; const char *func = "redir_handler"; union xsockaddr serveraddr ; if( signal(SIGPIPE, redir_sigpipe) == SIG_ERR ) msg(LOG_ERR, func, "unable to setup signal handler"); close_all_svc_descriptors(); /* If it's a tcp service we are redirecting */ if( scp->sc_protocol.value == IPPROTO_TCP ) { memcpy(&serveraddr, scp->sc_redir_addr, sizeof(serveraddr)); if( serveraddr.sa_in.sin_family == AF_INET ) { sin_len = sizeof( struct sockaddr_in ); RedirServerFd = socket(AF_INET, SOCK_STREAM, 0); } else if( serveraddr.sa_in.sin_family == AF_INET6 ) { sin_len = sizeof( struct sockaddr_in6 ); RedirServerFd = socket(AF_INET6, SOCK_STREAM, 0); } else { msg(LOG_ERR, func, "not a valid protocol. Use IPv4 or IPv6."); exit(0); } if( RedirServerFd < 0 ) { msg(LOG_ERR, func, "cannot create socket: %m"); exit(0); } if( SC_IPV6( scp ) ) { if( SC_V6ONLY( scp ) ) { v6on = 1; } else { v6on = 0; } #ifdef IPV6_V6ONLY if( setsockopt(RedirServerFd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6on, sizeof(v6on)) < 0 ) { msg( LOG_ERR, func, "Setting IPV6_V6ONLY option failed (%m)" ); } #endif } if( SC_KEEPALIVE( scp ) ) if (setsockopt(RedirServerFd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof( on ) ) < 0 ) msg(LOG_ERR, func, "setsockopt SO_KEEPALIVE RedirServerFd failed: %m"); if( serveraddr.sa_in.sin_family == AF_INET ) serveraddr.sa_in.sin_port = htons(serveraddr.sa_in.sin_port); if( serveraddr.sa_in.sin_family == AF_INET6 ) serveraddr.sa_in6.sin6_port = htons(serveraddr.sa_in6.sin6_port); if( connect(RedirServerFd, &serveraddr.sa, sin_len) < 0 ) { msg(LOG_ERR, func, "can't connect to remote host %s: %m", xaddrname( &serveraddr ) ); exit(0); } /* connection now established */ if (setsockopt(RedirServerFd, IPPROTO_TCP, TCP_NODELAY, (char *) &no_to_nagle, sizeof( on ) ) < 0) { msg(LOG_ERR, func, "setsockopt RedirServerFd failed: %m"); } if (setsockopt(RedirDescrip, IPPROTO_TCP, TCP_NODELAY, (char *) &no_to_nagle, sizeof( on ) ) < 0) { msg(LOG_ERR, func, "setsockopt RedirDescrip failed: %m"); } maxfd = (RedirServerFd > RedirDescrip)?RedirServerFd:RedirDescrip; FD_ZERO(&msfd); FD_SET(RedirDescrip, &msfd); FD_SET(RedirServerFd, &msfd); while(1) { memcpy(&rdfd, &msfd, sizeof(rdfd)); if (select(maxfd + 1, &rdfd, (fd_set *)0, (fd_set *)0, timep) <= 0) { /* place for timeout code, currently does not time out */ break; } if (FD_ISSET(RedirDescrip, &rdfd)) { do { num_read = read(RedirDescrip, buff, sizeof(buff)); if (num_read == -1 && errno == EINTR) continue; if (num_read <= 0) goto REDIROUT; bytes_in += num_read; } while (num_read < 0); /* Loop until we have written everything * that was read */ num_wrote = 0; while( num_wrote < num_read ) { ret = write(RedirServerFd, buff + num_wrote, num_read - num_wrote); if (ret == -1 && errno == EINTR) continue; if (ret <= 0) goto REDIROUT; num_wrote += ret; } } if (FD_ISSET(RedirServerFd, &rdfd)) { do { num_read = read(RedirServerFd, buff, sizeof(buff)); if (num_read == -1 && errno == EINTR) continue; if (num_read <= 0) goto REDIROUT; bytes_out += num_read; } while (num_read < 0); /* Loop until we have written everything * that was read */ num_wrote = 0; while( num_wrote < num_read ) { ret = write(RedirDescrip, buff + num_wrote, num_read - num_wrote); if (ret == -1 && errno == EINTR) continue; if (ret <= 0) goto REDIROUT; num_wrote += ret; } } } REDIROUT: if( M_IS_SET( (scp)->sc_log_on_success, LO_TRAFFIC ) ) { svc_logprint( SERVER_CONNSERVICE( serp ), "TRAFFIC", "in=%lu(bytes) out=%lu(bytes)", bytes_in, bytes_out ); } exit(0); } msg(LOG_ERR, func, "redirect with any protocol other than tcp is not supported at this time."); exit(0); }
static void tcpmux_handler( const struct server *serp ) { char svc_name[ BUFFER_SIZE ] ; int cc ; int descriptor = SERVER_FD( serp ) ; const struct service *svc = SERVER_SERVICE( serp ) ; unsigned u; struct service *sp = NULL; struct server server, *nserp; struct service_config *scp = NULL; close_all_svc_descriptors(); /* Read in the name of the service in the format "svc_name\r\n". * * XXX: should loop on partial reads (could probably use Sread() if * it wasn't thrown out of xinetd source code a few revisions back). */ do { cc = read( descriptor, svc_name, sizeof( svc_name ) ) ; } while (cc == -1 && errno == EINTR); if ( cc <= 0 ) { msg(LOG_ERR, "tcpmux_handler", "read failed"); exit(0); } if ( ( cc <= 2 ) || ( ( svc_name[cc - 1] != '\n' ) || ( svc_name[cc - 2] != '\r' ) ) ) { if ( debug.on ) msg(LOG_DEBUG, "tcpmux_handler", "Invalid service name format."); exit(0); } svc_name[cc - 2] = '\0'; /* Remove \r\n for compare */ if ( debug.on ) { msg(LOG_DEBUG, "tcpmux_handler", "Input (%d bytes) %s as service name.", cc, svc_name); } /* Search the services for the a match on name. */ for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) { sp = SP( pset_pointer( SERVICES( ps ), u ) ) ; if ( strcasecmp( svc_name, SC_NAME( SVC_CONF( sp ) ) ) == 0 ) { /* Found the pointer. Validate its type. */ scp = SVC_CONF( sp ); /* if ( ! SVC_IS_MUXCLIENT( sp ) ) { if ( debug.on ) { msg(LOG_DEBUG, "tcpmux_handler", "Non-tcpmux service name: %s.", svc_name); } exit(0); } */ /* Send the accept string if we're a PLUS (+) client. */ if ( SVC_IS_MUXPLUSCLIENT( sp ) ) { if ( Swrite( descriptor, TCPMUX_ACK, sizeof( TCPMUX_ACK ) ) != sizeof( TCPMUX_ACK ) ) { msg(LOG_ERR, "tcpmux_handler", "Ack write failed for %s.", svc_name); exit(0); } } break; /* Time to get on with the service */ } continue; /* Keep looking */ } if ( u >= pset_count( SERVICES( ps ) ) ) { if ( debug.on ) { msg(LOG_DEBUG, "tcpmux_handler", "Service name %s not found.", svc_name); } exit(0); } if( SVC_WAITS( svc ) ) /* Service forks, so close it */ Sclose(descriptor); server.svr_sp = sp; server.svr_conn = SERVER_CONNECTION(serp); nserp = server_alloc(&server); if( SC_IS_INTERNAL( scp ) ) { SC_INTERNAL(scp, nserp); } else { exec_server(nserp); } }
static void dgram_discard( const struct server *serp ) { char buf[ 1 ] ; (void) recv( SERVER_FD( serp ), buf, sizeof( buf ), 0 ) ; }
/* * This function is running in the new process */ void exec_server( const struct server *serp ) { const struct service_config *scp = SVC_CONF( SERVER_SERVICE( serp ) ) ; struct rlimit rl ; int fd ; int descriptor = SERVER_FD( serp ) ; const char *server = SC_SERVER( scp ) ; const char *func = "exec_server" ; /* * The following code solves a problem with post-version-4.3 * Ultrix systems (the bug was reported, and a fix was provided by * [email protected]; a slightly modified version of this * fix is included here). * * If this is a 'nowait' service, we pass the service descriptor * to the server. Note that we have set the close-on-exec flag * on all service descriptors. It is unclear whether the dup2() * will create a descriptor with the close-on-exec flag set, * so we explicitly clear the flag (since we are doing this * after the fork, it does not affect the descriptor of the * parent process). */ if ( fcntl( descriptor, F_SETFD, 0 ) == -1 ) msg( LOG_WARNING, func, "fcntl( %d, clear close-on-exec ) failed: %m", descriptor ) ; if ( debug.on ) msg( LOG_DEBUG, func, "duping %d", descriptor ) ; for ( fd = 0 ; fd <= MAX_PASS_FD ; fd++ ) { if ( dup2( descriptor, fd ) == -1 ) { msg( LOG_ERR, func, "dup2( %d, %d ) failed: %m", descriptor, fd ) ; _exit( 1 ) ; } } #ifdef RLIMIT_NOFILE rl.rlim_max = ps.ros.orig_max_descriptors ; rl.rlim_cur = ps.ros.max_descriptors ; (void) setrlimit( RLIMIT_NOFILE, &rl ) ; #endif #ifdef RLIMIT_AS if (SC_RLIM_AS (scp)) { rl.rlim_cur = SC_RLIM_AS( scp ); rl.rlim_max = SC_RLIM_AS( scp ); (void) setrlimit( RLIMIT_AS, &rl ); } #endif #ifdef RLIMIT_CPU if (SC_RLIM_CPU (scp)) { rl.rlim_cur = SC_RLIM_CPU( scp ); rl.rlim_max = SC_RLIM_CPU( scp ); (void) setrlimit( RLIMIT_CPU, &rl ); } #endif #ifdef RLIMIT_DATA if (SC_RLIM_DATA (scp)) { rl.rlim_cur = SC_RLIM_DATA( scp ); rl.rlim_max = SC_RLIM_DATA( scp ); (void) setrlimit( RLIMIT_DATA, &rl ); } #endif #ifdef RLIMIT_RSS if (SC_RLIM_RSS (scp)) { rl.rlim_cur = SC_RLIM_RSS( scp ); rl.rlim_max = SC_RLIM_RSS( scp ); (void) setrlimit( RLIMIT_RSS, &rl ); } #endif #ifdef RLIMIT_STACK if (SC_RLIM_STACK (scp)) { rl.rlim_cur = SC_RLIM_STACK( scp ); rl.rlim_max = SC_RLIM_STACK( scp ); (void) setrlimit( RLIMIT_STACK, &rl ); } #endif (void) Sclose( descriptor ) ; #ifndef solaris no_control_tty() ; #endif msg_suspend() ; (void) execve( server, SC_SERVER_ARGV( scp ), env_getvars( SC_ENV( scp )->env_handle ) ) ; /* * The exec failed. Log the error and exit. */ msg_resume() ; msg( LOG_ERR, func, "execv( %s ) failed: %m", server ) ; _exit( 0 ) ; }
/* * This function always runs in a forked process. */ idresult_e log_remote_user( const struct server *serp, unsigned timeout ) { static char buf[ IBUFSIZE ] ; int cc ; union xsockaddr sin_local, sin_remote, sin_contact, sin_bind; volatile unsigned local_port; volatile unsigned remote_port; int sd ; socklen_t sin_len ; char *p ; const char *func = "log_remote_user" ; if ( timeout && signal( SIGALRM, sigalrm_handler ) == SIG_ERR ) { msg( LOG_ERR, func, "signal: %m" ) ; return( IDR_ERROR ) ; } /* * Determine local and remote addresses */ sin_len = sizeof( sin_local ) ; if ( getsockname( SERVER_FD( serp ), &sin_local.sa, &sin_len ) == -1 ) { msg( LOG_ERR, func, "(%d) getsockname: %m", getpid() ) ; return( IDR_ERROR ) ; } if ( CONN_XADDRESS( SERVER_CONNECTION( serp ) ) == NULL ) { /* * This shouldn't happen since identification only works for * connection-based services. */ msg( LOG_ERR, func, "connection has no address" ) ; return( IDR_ERROR ) ; } CLEAR( sin_contact ); sin_remote = *CONN_XADDRESS( SERVER_CONNECTION( serp ) ) ; sin_contact = sin_remote; memcpy( &sin_bind, &sin_local, sizeof(sin_bind) ) ; local_port = 0; remote_port = 0; if( sin_remote.sa.sa_family == AF_INET ) { local_port = ntohs( sin_local.sa_in6.sin6_port ) ; remote_port = ntohs( sin_remote.sa_in6.sin6_port ) ; sin_contact.sa_in6.sin6_port = htons( IDENTITY_SERVICE_PORT ) ; sin_bind.sa_in.sin_port = 0 ; } else if( sin_remote.sa.sa_family == AF_INET6 ) { local_port = ntohs( sin_local.sa_in.sin_port ) ; remote_port = ntohs( sin_remote.sa_in.sin_port ) ; sin_contact.sa_in.sin_port = htons( IDENTITY_SERVICE_PORT ) ; sin_bind.sa_in6.sin6_port = 0 ; } /* * Create a socket, bind it, and set the close-on-exec flag on the * descriptor. We set the flag in case we are called as part of a * successful attempt to start a server (i.e. execve will follow). * The socket must be bound to the receiving address or ident might * fail for multi-homed hosts. */ sd = socket( sin_remote.sa.sa_family, SOCK_STREAM, 0 ) ; if ( sd == -1 ) { msg( LOG_ERR, func, "socket creation: %m" ) ; return( IDR_ERROR ) ; } if ( bind(sd, &sin_bind.sa, sizeof(sin_bind.sa)) == -1 ) { msg( LOG_ERR, func, "socket bind: %m" ) ; (void) Sclose( sd ) ; return( IDR_ERROR ) ; } if ( fcntl( sd, F_SETFD, FD_CLOEXEC ) == -1 ) { msg( LOG_ERR, func, "fcntl F_SETFD: %m" ) ; (void) Sclose( sd ) ; return( IDR_ERROR ) ; } if ( timeout ) { if ( sigsetjmp( env, 1 ) == 0 ) START_TIMER( timeout ) ; else { Sclose( sd ) ; return( IDR_TIMEDOUT ) ; } } if ( connect( sd, &sin_contact.sa, sizeof( sin_contact ) ) == -1 ) { if ( timeout ) { STOP_TIMER() ; signal ( SIGALRM, SIG_DFL ) ; } Sclose( sd ); return( IDR_NOSERVER ) ; } cc = strx_nprint( buf, sizeof( buf ), "%d,%d\r\n", remote_port, local_port ) ; if ( write_buf( sd, buf, cc ) == FAILED ) { if ( timeout ) { STOP_TIMER() ; signal ( SIGALRM, SIG_DFL ) ; } Sclose( sd ); return( IDR_ERROR ) ; } p = get_line( sd, buf, sizeof( buf ) ) ; if ( timeout ) { STOP_TIMER() ; signal ( SIGALRM, SIG_DFL ) ; } if ( p == NULL ) { Sclose( sd ); return( IDR_RESPERR ) ; } /* * Verify that the received line is OK */ if ( ( p = verify_line( buf, local_port, remote_port ) ) == NULL ) { msg(LOG_ERR, func, "Bad line received from identity server at %s: %s", xaddrname( &sin_remote ), buf ) ; Sclose( sd ); return( IDR_BADRESP ) ; } svc_logprint( SERVER_CONNSERVICE( serp ), USERID_ENTRY, "%s", p ) ; return( IDR_OK ) ; }