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 ) ; }
/* * Steps: * 1. Deactivate the service * 2. Free all memory used by the service and free the service itself * * Since this function may free all memory associated with the service as * well as the memory pointed by sp, only the value of sp should be used * after this call if the return value is 0 (i.e. no dereferencing of sp). * * Special services are never deactivated. */ int svc_release( struct service *sp ) { char *sid = SVC_ID( sp ) ; const char *func = "svc_release" ; if ( SVC_REFCOUNT(sp) == 0 ) { msg( LOG_ERR, func, "%s: svc_release with 0 count", sid ) ; return( 0 ) ; } SVC_REFCOUNT(sp)-- ; if ( SVC_REFCOUNT(sp) == 0 ) { if ( debug.on ) msg( LOG_DEBUG, func, "ref count of service %s dropped to 0", sid ) ; if ( ! SC_IS_SPECIAL( SVC_CONF( sp ) ) ) { if ( SVC_LOG(sp) ) log_end( SC_LOG( SVC_CONF( sp ) ), SVC_LOG(sp) ) ; svc_deactivate( sp ) ; svc_free( sp ) ; sp = NULL; } else /* this shouldn't happen */ msg( LOG_WARNING, func, "ref count of special service %s dropped to 0", sid ) ; return( 0 ) ; } else return( SVC_REFCOUNT(sp) ) ; }
static status_e get_incoming_packet( struct intercept_s *ip, packet_s *pp ) { socklen_t from_len = 0; const char *func = "get_incoming_packet" ; if( SC_IPV4( SVC_CONF( SERVER_SERVICE( INT_SERVER( ip ) ) ) ) ) from_len = sizeof( struct sockaddr_in ); if( SC_IPV6( SVC_CONF( SERVER_SERVICE( INT_SERVER( ip ) ) ) ) ) from_len = sizeof( struct sockaddr_in6 ); for ( ;; ) { int cc ; from_len = sizeof( pp->from ) ; cc = recvfrom( INT_REMOTE( ip ), pp->data, pp->size, 0, SA( &pp->from ), &from_len ) ; if ( cc == -1 ) { if ( errno != EINTR ) { msg( LOG_ERR, func, "recvfrom error: %m" ) ; return( FAILED ) ; } } else if ( cc == 0 ) return( FAILED ) ; else { pp->size = cc ; IDP( ip->int_priv )->received_packets++ ; break ; } } if ( from_len == 0 ) { msg( LOG_ERR, func, "incoming packet had 0 length address" ) ; return( FAILED ) ; } #ifdef DEBUG_UDPINT if ( debug.on ) msg( LOG_DEBUG, func, "Received %d bytes from address: %s,%d", pp->size, xaddrname( &pp->from ), ntohs( xaddrport(&pp->from) ) ); #endif return( OK ) ; }
void svc_dump( const struct service *sp, int fd ) { tabprint( fd, 0, "Service = %s\n", SC_NAME( SVC_CONF( sp ) ) ) ; tabprint( fd, 1, "State = %s\n", nv_get_name( service_states, (int) SVC_STATE(sp) ) ) ; sc_dump( SVC_CONF( sp ), fd, 1, FALSE ) ; if ( SVC_IS_ACTIVE(sp) ) { tabprint( fd, 1, "running servers = %d\n", SVC_RUNNING_SERVERS(sp) ) ; tabprint( fd, 1, "retry servers = %d\n", SVC_RETRIES(sp) ) ; tabprint( fd, 1, "attempts = %d\n", SVC_ATTEMPTS(sp) ) ; tabprint( fd, 1, "service fd = %d\n", SVC_FD(sp) ) ; } Sputchar( fd, '\n' ) ; }
void svc_request( struct service *sp ) { connection_s *cp ; status_e ret_code; cp = conn_new( sp ) ; if ( cp == CONN_NULL ) return ; /* * Output the banner now that the connection is established. The * other banners come later. */ banner_always(sp, cp); if (SVC_NOT_GENERIC(sp)) ret_code = spec_service_handler(sp, cp); else ret_code = svc_generic_handler(sp, cp); if( (SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM) && (SVC_IS_ACTIVE( sp )) ) drain( cp->co_descriptor ) ; /* Prevents looping next time */ if ( ret_code != OK ) { if ( SVC_LOGS_USERID_ON_FAILURE( sp ) ) { if( spec_service_handler( LOG_SERVICE( ps ), cp ) == FAILED ) conn_free( cp, 1 ) ; else if (!SC_WAITS( SVC_CONF( sp ) ) ) { /* The logging service will gen SIGCHLD thus freeing connection */ CONN_CLOSE(cp) ; } return; } if (!SC_WAITS( SVC_CONF( sp ) )) conn_free( cp, 1 ); else { if( (SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM) && (SVC_IS_ACTIVE( sp )) ) drain( cp->co_descriptor ) ; /* Prevents looping next time */ free( cp ); } } else if ((SVC_NOT_GENERIC(sp)) || (!SC_FORKS( SVC_CONF( sp ) ) ) ) free( cp ); }
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 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 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 deactivate( const struct service *sp ) { (void) Sclose( SVC_FD( sp ) ) ; #ifdef HAVE_MDNS xinetd_mdns_deregister(SVC_CONF(sp)); #endif if (debug.on) msg(LOG_DEBUG, "deactivate", "%d Service %s deactivated", getpid(), SC_NAME( SVC_CONF(sp) ) ); #ifndef NO_RPC if ( SC_IS_RPC( SVC_CONF( sp ) ) ) { unsigned long vers ; const struct rpc_data *rdp = SC_RPCDATA( SVC_CONF( sp ) ) ; for ( vers = RD_MINVERS( rdp ) ; vers <= RD_MAXVERS( rdp ) ; vers++ ) { (void) pmap_unset( RD_PROGNUM( rdp ), vers ) ; } } #endif /* ! NO_RPC */ }
/* * Allocate a new struct service and initialize it from scp */ struct service *svc_new( struct service_config *scp ) { struct service *sp ; const char *func = "svc_new" ; sp = NEW_SVC() ; if ( sp == NULL ) { out_of_memory( func ) ; return( NULL ) ; } CLEAR( *sp ) ; SVC_CONF(sp) = scp ; return( sp ) ; }
static int banner_fail( const struct service *sp, const connection_s *cp ) { const char *func = "banner_fail"; const struct service_config *scp = SVC_CONF( sp ) ; if ( SC_BANNER_FAIL(scp) != NULL ) { char tmpbuf[TMPSIZE]; int retval; int bannerfd = open(SC_BANNER_FAIL(scp), O_RDONLY); if( bannerfd < 0 ) { msg( LOG_ERR, func, "service = %s, open of banner %s failed", SVC_ID( sp ), SC_BANNER_FAIL(scp)); return(-1); } while( (retval = read(bannerfd, tmpbuf, sizeof(tmpbuf))) ) { if (retval == -1) { if (errno == EINTR) continue; else { msg(LOG_ERR, func, "service %s, Error %m reading banner %s", SVC_ID( sp ), SC_BANNER(scp)); break; } } Swrite(cp->co_descriptor, tmpbuf, retval); } Sclose(bannerfd); Sflush ( cp->co_descriptor ); } return(0); }
/* * Get a new connection request and initialize 'cp' appropriately */ static status_e get_connection( struct service *sp, connection_s *cp ) { struct service_config *scp = SVC_CONF( sp ); socklen_t sin_len; const char *func = "get_connection" ; int on = 1; if( SC_IPV4(scp) ) sin_len = sizeof(struct sockaddr_in); if( SC_IPV6(scp) ) sin_len = sizeof(struct sockaddr_in6); if ( SVC_SOCKET_TYPE( sp ) == SOCK_STREAM ) { /* If it's a TCP socket, and we're set to wait, the accept is * done by the child process. Don't set NEW_DESCRIPTOR, since * there isn't one. The descriptor will be/was removed from * the descriptor set in svc_suspend and re-enabled in svc_resume. */ if( SC_WAITS( scp ) ) { cp->co_descriptor = SVC_FD( sp ); } else { cp->co_descriptor = accept( SVC_FD( sp ), &(cp->co_remote_address.sa), &sin_len ) ; if (cp->co_descriptor != -1) M_SET( cp->co_flags, COF_NEW_DESCRIPTOR ) ; } if ( cp->co_descriptor == -1 ) { if ((errno == EMFILE) || (errno == ENFILE)) cps_service_stop(sp, "no available descriptors"); else msg( LOG_ERR, func, "service %s, accept: %m", SVC_ID( sp ) ) ; return( FAILED ) ; } if( SC_NODELAY( scp ) && (SC_PROTOVAL( scp ) == IPPROTO_TCP) ) if( setsockopt(SVC_FD(sp), IPPROTO_TCP, TCP_NODELAY, (char *)&on, sizeof( on ) ) < 0 ) msg( LOG_WARNING, func, "service %s, setsockopt: %m", SVC_ID(sp)); if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL( scp ) == IPPROTO_TCP) ) { if( setsockopt(SVC_FD(sp), SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof( on ) ) < 0 ) msg( LOG_WARNING, func, "service %s, setsockopt: %m", SVC_ID(sp)); } if( SC_IPV6(scp) && !(SC_V6ONLY( scp )) && (IN6_IS_ADDR_V4MAPPED(&cp->co_remote_address.sa_in6.sin6_addr) || IN6_IS_ADDR_V4COMPAT(&cp->co_remote_address.sa_in6.sin6_addr)) ) { int af = AF_INET; if( setsockopt(cp->co_descriptor, IPPROTO_IPV6, IPV6_ADDRFORM, &af, sizeof( af ) ) ) { if( debug.on ) msg( LOG_WARNING, func, "service %s, IPV6_ADDRFORM setsockopt() failed: %m", SVC_ID( sp) ); } } M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ; } else { if ( SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM ) { char t_ch ; ssize_t val; /* * This trick is done to get the remote address. * select(2) guaranteed that we won't block on the recvfrom */ val = recvfrom( SVC_FD( sp ), &t_ch, 1, MSG_PEEK, &cp->co_remote_address.sa, &sin_len ); if ( val == (ssize_t)-1 ) { msg( LOG_ERR, func, "service %s, recvfrom: %m", SVC_ID( sp ) ) ; return( FAILED ) ; } M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ; } cp->co_descriptor = SVC_FD( sp ) ; } return( OK ) ; }
/* 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); }
/* * 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 ) ; }
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); } }
/* * This function runs in the parent context and updates the global_no_access * list. */ void process_sensor( const struct service *sp, const union xsockaddr *addr) { const char *func = "process_sensor"; if (SC_DENY_TIME(SVC_CONF(sp)) != 0) /* 0 simply logs it */ { if ( pset_count( global_no_access ) < MAX_GLOBAL_NO_ACCESS) { int item_matched = addrlist_match( global_no_access, SA(addr) ); if ( item_matched == 0) { /* no match...adding to the list */ char *dup_addr = new_string(xaddrname( addr ) ); if (dup_addr == NULL ) return ; if (addrlist_add(global_no_access, dup_addr) == FAILED) msg(LOG_ERR, func, "Failed adding %s to the global_no_access list", dup_addr); else { time_t nowtime; char time_buf[40], *tmp; nowtime = time(NULL); msg(LOG_CRIT, func, "Adding %s to the global_no_access list for %d minutes", dup_addr, SC_DENY_TIME(SVC_CONF(sp))); if (SC_DENY_TIME(SVC_CONF(sp)) == -1) strcpy(time_buf, "-1"); else strx_nprint(time_buf, 38, "%ld", (time_t)nowtime+(60*SC_DENY_TIME(SVC_CONF(sp)))); tmp = new_string(time_buf); if (tmp != NULL) { if (pset_add(global_no_access_time, tmp) == NULL) { msg(LOG_ERR, func, "Failed adding %s to the global_no_access_time list. " "global_no_access list is broken, xinetd needs " "restarting.", dup_addr); /* ideally, we should rollback the previous addr addition. */ } } if (pset_count(global_no_access) && (timer_id == 0) ) timer_id = xtimer_add( scrub_global_access_list, 60 ); } free(dup_addr); } else { /* Here again, eh?...update time stamp. */ char *exp_time; time_t stored_time; item_matched--; /* Is # plus 1, to even get here must be >= 1 */ exp_time = pset_pointer( global_no_access_time, item_matched ) ; if (exp_time == NULL) return ; if ( parse_base10(exp_time, (int *)&stored_time) ) { /* if never let them off, bypass */ if (stored_time != -1) { time_t nowtime, new_time; nowtime = time(NULL); new_time = (time_t)nowtime+(60*SC_DENY_TIME(SVC_CONF(sp))); if (difftime(new_time, (time_t)stored_time) > 0.0) { /* new_time is longer save it */ char time_buf[40], *new_exp_time; strx_nprint(time_buf, 38, "%ld", (long)new_time); new_exp_time = new_string(time_buf); if ( new_exp_time ) { free(exp_time); global_no_access_time->ptrs[ (unsigned)item_matched ] = new_exp_time; } } } } } } else msg(LOG_ERR, func, "Maximum global_no_access count reached."); } }
static status_e failed_service(struct service *sp, connection_s *cp, access_e result) { struct service_config *scp = SVC_CONF( sp ) ; if ( result != AC_OK ) { bool_int report_failure = TRUE ; /* * Try to avoid reporting multiple times a failed attempt to access * a datagram-based service from a bad address. We do this because * the clients of such services usually send multiple datagrams * before reporting a timeout (we have no way of telling them that * their request has been denied). */ if ( result == AC_ADDRESS && SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM ) { if( SC_IPV4( scp ) ) { struct sockaddr_in *sinp = SAIN(CONN_ADDRESS( cp )) ; struct sockaddr_in *last = SAIN(SVC_LAST_DGRAM_ADDR(sp)) ; time_t current_time ; if (sinp == NULL ) return FAILED; if ( last == NULL ) { last = SAIN( calloc( 1, sizeof(union xsockaddr) ) ); SVC_LAST_DGRAM_ADDR(sp) = (union xsockaddr *)last; } (void) time( ¤t_time ) ; if ( sinp->sin_addr.s_addr == last->sin_addr.s_addr && sinp->sin_port == last->sin_port ) { if( current_time - SVC_LAST_DGRAM_TIME(sp) <= DGRAM_IGNORE_TIME ) report_failure = FALSE ; else SVC_LAST_DGRAM_TIME(sp) = current_time ; } else { memcpy(SVC_LAST_DGRAM_ADDR(sp), sinp,sizeof(struct sockaddr_in)); SVC_LAST_DGRAM_TIME(sp) = current_time ; } } else if( SC_IPV6( scp ) ) { struct sockaddr_in6 *sinp = SAIN6(CONN_ADDRESS( cp )) ; struct sockaddr_in6 *last = SAIN6(SVC_LAST_DGRAM_ADDR(sp)) ; time_t current_time ; if (sinp == NULL ) return FAILED; if( last == NULL ) { last = SAIN6(calloc( 1, sizeof(union xsockaddr) ) ); SVC_LAST_DGRAM_ADDR( sp ) = (union xsockaddr *)last; } (void) time( ¤t_time ) ; if ( IN6_ARE_ADDR_EQUAL(&(sinp->sin6_addr), &(last->sin6_addr)) && sinp->sin6_port == last->sin6_port ) { if((current_time - SVC_LAST_DGRAM_TIME(sp)) <= DGRAM_IGNORE_TIME) report_failure = FALSE ; else SVC_LAST_DGRAM_TIME(sp) = current_time ; } else { memcpy(SVC_LAST_DGRAM_ADDR(sp),sinp,sizeof(struct sockaddr_in6)); SVC_LAST_DGRAM_TIME(sp) = current_time ; } } } if ( report_failure ) svc_log_failure( sp, cp, result ) ; banner_fail(sp, cp); return( FAILED ) ; } return( OK ); }
/* * This function is invoked in a forked process to run a server. * If the service is internal the appropriate function is invoked * otherwise the server program is exec'ed. * This function also logs the remote user id if appropriate */ void child_process( struct server *serp ) { struct service *sp = SERVER_SERVICE( serp ) ; connection_s *cp = SERVER_CONNECTION( serp ) ; struct service_config *scp = SVC_CONF( sp ) ; const char *func = "child_process" ; signal_default_state(); if ((signals_pending[0] >= 0 && Sclose(signals_pending[0])) || (signals_pending[1] >= 0 && Sclose(signals_pending[1]))) { msg(LOG_ERR, func, "Failed to close the signal pipe: %m"); _exit(1); } signals_pending[0] = -1; signals_pending[1] = -1; Sclose(0); Sclose(1); Sclose(2); #ifdef DEBUG_SERVER if ( debug.on ) { msg( LOG_DEBUG, func, "Process %d is sleeping", getpid() ) ; sleep( 10 ) ; } #endif if ( ! SC_IS_INTERCEPTED( scp ) ) { set_credentials( scp ) ; if ( SC_SPECIFIED( scp, A_NICE ) ) (void) nice( SC_NICE( scp ) ) ; } if ( svc_child_access_control(sp, cp) != OK ) exit(0); if ( SERVER_LOGUSER( serp ) ) { unsigned timeout ; idresult_e result ; /* * We use LOGUSER_SUCCESS_TIMEOUT unless the service requires * identification, in which case we use an infinite timeout */ timeout = SC_MUST_IDENTIFY( scp ) ? 0 : LOGUSER_SUCCESS_TIMEOUT ; result = log_remote_user( serp, timeout ) ; if ( result != IDR_OK && SC_MUST_IDENTIFY( scp ) ) { svc_logprint( sp, NOID_ENTRY, "%s %s", conn_addrstr( SERVER_CONNECTION( serp ) ), idresult_explain( result ) ) ; _exit( 0 ) ; } } #ifdef HAVE_SESSIONCREATE if ( scp->sc_sessioncreate == YES ) { if ( SessionCreate(0, sessionHasTTY|sessionIsRemote) != noErr ) svc_logprint( sp, "SessionCreate", "SessionCreate() failed!" ); } #endif /* this is where the server gets executed -bbraun */ if ( ! SC_IS_INTERNAL( scp ) ) { if( scp->sc_redir_addr != NULL ) { redir_handler( serp ); } else { #if defined(HAVE_SETENV) char buff[1024]; strx_sprint(buff, sizeof(buff)-1, "REMOTE_HOST=%s", conn_addrstr(cp)); if( env_addstr(SC_ENV(scp)->env_handle, buff) != ENV_OK ) { msg( LOG_ERR, func, "Error adding REMOTE_HOST variable for %s: %m", SC_NAME(scp) ); _exit( 1 ) ; } #endif exec_server( serp ) ; } } else { char name[ 180 ] ; /* * We don't bother to disassociate from the controlling terminal * (we have a controlling terminal only if debug.on is TRUE) * * Also, for interceptor processes, we give them the name: * <program_name> <service-id> interceptor */ if ( SC_IS_INTERCEPTED( scp ) ) strx_print( INT_NULL, name, sizeof( name ) - 1, "%s %s interceptor", program_name, SC_ID( scp ) ) ; else { int namelen = sizeof( name ) - 1 ; /* leave space for the NUL */ char host[NI_MAXHOST]; size_t hostlen = NI_MAXHOST; socklen_t addrlen = 0; union xsockaddr *sinp = CONN_XADDRESS(SERVER_CONNECTION(serp)); int len; if( sinp == NULL ) exit(0); if( SC_IPV6(scp) ) addrlen = sizeof(struct sockaddr_in6); else if( SC_IPV4(scp) ) addrlen = sizeof(struct sockaddr_in); len = strx_nprint(name, namelen, "(%s service) %s", program_name, SC_ID( scp ) ) ; if( getnameinfo( SA(sinp), addrlen, host, hostlen, NULL, 0, 0) != 0 ) strcpy(host, "unknown"); if ( SC_IPV6(scp) && SC_ACCEPTS_CONNECTIONS( scp ) && !IN6_IS_ADDR_UNSPECIFIED(&sinp->sa_in6.sin6_addr) ) strx_print( INT_NULL, &name[ len ], namelen - len, " %s" , host ) ; if ( SC_IPV4(scp) && SC_ACCEPTS_CONNECTIONS( scp ) ) strx_print( INT_NULL, &name[ len ], namelen - len, " %s", host ) ; } rename_process( name ) ; SVC_INTERNAL( sp, serp ) ; } _exit( 0 ) ; /* NOTREACHED */ }
void svc_free( struct service *sp ) { sc_free( SVC_CONF(sp) ) ; CLEAR( *sp ) ; FREE_SVC( sp ) ; }
static status_e activate_rpc( struct service *sp ) { union xsockaddr tsin; socklen_t sin_len = sizeof(tsin); unsigned long vers ; struct service_config *scp = SVC_CONF( sp ) ; struct rpc_data *rdp = SC_RPCDATA( scp ) ; char *sid = SC_ID( scp ) ; unsigned registered_versions = 0 ; int sd = SVC_FD( sp ) ; const char *func = "activate_rpc" ; if( SC_BIND_ADDR(scp) != 0 ) memcpy( &tsin, SC_BIND_ADDR(scp), sizeof(tsin) ); else memset( &tsin, 0, sizeof(tsin)); if ( SC_PROTOVAL ( scp ) == IPPROTO_TCP ) { M_SET ( scp->sc_xflags, SF_NOLIBWRAP ); } if( SC_IPV4( scp ) ) { tsin.sa_in.sin_family = AF_INET ; sin_len = sizeof(struct sockaddr_in); } else if( SC_IPV6( scp ) ) { tsin.sa_in6.sin6_family = AF_INET6 ; sin_len = sizeof(struct sockaddr_in6); } if ( bind( sd, &tsin.sa, sin_len ) == -1 ) { msg( LOG_ERR, func, "bind failed (%m). service = %s", sid ) ; return( FAILED ) ; } /* * Find the port number that was assigned to the socket */ if ( getsockname( sd, &tsin.sa, &sin_len ) == -1 ) { msg( LOG_ERR, func, "getsockname failed (%m). service = %s", sid ) ; return( FAILED ) ; } if( tsin.sa.sa_family == AF_INET ) SC_SET_PORT( scp, ntohs( tsin.sa_in.sin_port ) ) ; else if( tsin.sa.sa_family == AF_INET6 ) SC_SET_PORT( scp, ntohs( tsin.sa_in6.sin6_port ) ) ; /* * Try to register as many versions as possible */ for ( vers = RD_MINVERS( rdp ) ; vers <= RD_MAXVERS( rdp ) ; vers++ ) { /* Is this right? For instance, if we have both tcp and udp services, * this will unregister the previously registered protocol. * pmap_unset(RD_PROGNUM(rdp), vers); */ if ( pmap_set( RD_PROGNUM( rdp ), vers, SC_PROTOVAL( scp ), SC_PORT( scp ) ) ) registered_versions++ ; else msg( LOG_ERR, func, "pmap_set failed. service=%s program=%ld version=%ld", sid, RD_PROGNUM( rdp ), vers ) ; sleep(1); } if ( debug.on ) msg( LOG_DEBUG, func, "Registered %d versions of %s", registered_versions, sid ) ; return( ( registered_versions == 0 ) ? FAILED : OK ) ; }
/* * Activate a service. */ status_e svc_activate( struct service *sp ) { struct service_config *scp = SVC_CONF( sp ) ; status_e status ; const char *func = "svc_activate" ; /* No activation for MUXCLIENTS. */ if (SC_IS_MUXCLIENT( scp )) { return( OK ); } if( SC_IPV4( scp ) ) { SVC_FD(sp) = socket( AF_INET, SC_SOCKET_TYPE( scp ), SC_PROTOVAL( scp ) ) ; } else if( SC_IPV6( scp ) ) { SVC_FD(sp) = socket( AF_INET6, SC_SOCKET_TYPE( scp ), SC_PROTOVAL( scp ) ) ; } if ( SVC_FD(sp) == -1 ) { msg( LOG_ERR, func, "socket creation failed (%m). service = %s", SC_ID( scp ) ) ; return( FAILED ) ; } if ( set_fd_modes( sp ) == FAILED ) { (void) Sclose( SVC_FD(sp) ) ; return( FAILED ) ; } #ifndef NO_RPC if ( SC_IS_RPC( scp ) ) status = activate_rpc( sp ) ; else #endif /* ! NO_RPC */ status = activate_normal( sp ) ; if ( status == FAILED ) { (void) Sclose( SVC_FD(sp) ) ; return( FAILED ) ; } #ifdef HAVE_MDNS xinetd_mdns_register(scp); #endif if ( log_start( sp, &SVC_LOG(sp) ) == FAILED ) { deactivate( sp ) ; return( FAILED ) ; } /* * Initialize the service data */ SVC_RUNNING_SERVERS(sp) = SVC_RETRIES(sp) = 0 ; if ( SC_MUST_LISTEN( scp ) ) (void) listen( SVC_FD(sp), LISTEN_BACKLOG ) ; ps.rws.descriptors_free-- ; SVC_STATE(sp) = SVC_ACTIVE ; FD_SET( SVC_FD(sp), &ps.rws.socket_mask ) ; if ( SVC_FD(sp) > ps.rws.mask_max ) ps.rws.mask_max = SVC_FD(sp) ; ps.rws.active_services++ ; ps.rws.available_services++ ; return( OK ) ; }
static status_e activate_normal( struct service *sp ) { union xsockaddr tsin; int sd = SVC_FD( sp ) ; struct service_config *scp = SVC_CONF( sp ) ; uint16_t service_port = SC_PORT( scp ) ; char *sid = SC_ID( scp ) ; const char *func = "activate_normal" ; unsigned int sin_len = sizeof(tsin); int on = 1; #ifdef IPV6_V6ONLY int v6on = 0; #endif if( SC_BIND_ADDR(scp) != NULL ) memcpy(&tsin, SC_BIND_ADDR(scp), sin_len); else memset(&tsin, 0, sin_len); if( SC_IPV4( scp ) ) { tsin.sa_in.sin_family = AF_INET ; tsin.sa_in.sin_port = htons( service_port ) ; sin_len = sizeof(struct sockaddr_in); } else if( SC_IPV6( scp ) ) { tsin.sa_in6.sin6_family = AF_INET6; tsin.sa_in6.sin6_port = htons( service_port ); sin_len = sizeof(struct sockaddr_in6); } #ifdef IPV6_V6ONLY if( SC_IPV6(scp) ) { if( SC_SPECIFIED(scp, A_V6ONLY) ) { v6on = 1; } else { v6on = 0; } if( setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6on, sizeof(v6on)) < 0 ) { msg( LOG_ERR, func, "Setting IPV6_V6ONLY option failed (%m)" ); } } #endif if ( setsockopt( sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof( on ) ) == -1 ) msg( LOG_WARNING, func, "setsockopt SO_REUSEADDR failed (%m). service = %s", sid ) ; if( SC_NODELAY( scp ) && (SC_PROTOVAL(scp) == IPPROTO_TCP) ) { if ( setsockopt( sd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof( on ) ) == -1 ) msg( LOG_WARNING, func, "setsockopt TCP_NODELAY failed (%m). service = %s", sid ) ; } if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL(scp) == IPPROTO_TCP) ) { if( setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof( on ) ) < 0 ) msg( LOG_WARNING, func, "setsockopt SO_KEEPALIVE failed (%m). service = %s", sid ) ; } if ( bind( sd, &tsin.sa, sin_len ) == -1 ) { msg( LOG_ERR, func, "bind failed (%m). service = %s", sid ) ; return( FAILED ) ; } #ifdef IN_MULTICAST if( SC_IPV4(scp) && IN_MULTICAST( ntohl(tsin.sa_in.sin_addr.s_addr) ) ) { struct ifaddrs *addrs, *addr; struct ip_mreq mreq; if (getifaddrs(&addrs) == 0) { addr = addrs; while (addr) { if (addr->ifa_addr && (addr->ifa_flags & IFF_MULTICAST)) { mreq.imr_multiaddr.s_addr = tsin.sa_in.sin_addr.s_addr; mreq.imr_interface.s_addr = ((struct sockaddr_in *)addr->ifa_addr)->sin_addr.s_addr; setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); } addr = addr->ifa_next; } freeifaddrs(addrs); if ( debug.on ) msg( LOG_DEBUG, func, "Adding multicast membership." ); } else { msg( LOG_ERR, func, "getifaddrs failed (%m). service = %s", sid ); } } #endif return( OK ) ; }