Newsgroups: comp.sources.unix From: panos@cs.colorado.edu (Panos Tsirigotis) Subject: v26i259: xinetd-2.1.1 - inetd replacement with access control and logging, Part15/31 Sender: unix-sources-moderator@gw.home.vix.com Approved: vixie@gw.home.vix.com Submitted-By: panos@cs.colorado.edu (Panos Tsirigotis) Posting-Number: Volume 26, Issue 259 Archive-Name: xinetd-2.1.1/part15 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'libs/src/sio/sio.h' <<'END_OF_FILE' X/* X * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis X * All rights reserved. The file named COPYRIGHT specifies the terms X * and conditions for redistribution. X */ X X/* X * $Id: sio.h,v 8.1 1993/03/13 01:13:58 panos Exp $ X */ X X#ifndef __SIO_H X#define __SIO_H X X#include X#include X X/* X * Naming conventions: X * 1) SIO functions and macros have names starting with a capital S X * 2) SIO constants meant to be used by user programs have X * names starting with SIO_ X * 3) Internal functions, struct identifiers, enum identifiers X * etc. have names starting with __sio X * 4) Internal constants and macros have names starting with __SIO X */ X X X/* X * external constants X * X * SIO_FLUSH_ALL: flush all output streams X * SIO_EOF: eof on stream X * SIO_ERR: operation failed X */ X#define SIO_FLUSH_ALL (-1) X#define SIO_EOF (-2) X#define SIO_ERR (-1) X X/* X * Undo types X */ X#define SIO_UNDO_LINE 0 X#define SIO_UNDO_CHAR 1 X X/* X * Buffering types X */ X#define SIO_FULLBUF 0 X#define SIO_LINEBUF 1 X#define SIO_NOBUF 2 X X/* X * Descriptor for an input stream X */ Xstruct __sio_input_descriptor X{ X /* X * buf: points to the buffer area. X * When doing memory mapping, it is equal to the unit X * from which we are reading. When doing buffered I/O X * it points to the primary buffer. X */ X char *buf ; X unsigned buffer_size ; X X char *start ; /* start of valid buffer contents */ X char *end ; /* end of valid buffer contents + 1 */ X char *nextb ; /* pointer to next byte to read/write */ X /* Always: start <= nextb < end */ X X unsigned line_length ; X int max_line_length ; X int tied_fd ; X X int memory_mapped ; /* flag to denote if we use */ X /* memory mapping */ X} ; X Xtypedef struct __sio_input_descriptor __sio_id_t ; X X X/* X * Descriptor for an output stream X */ Xstruct __sio_output_descriptor X{ X /* X * buf: points to the buffer area. X * buf_end: is equal to buf + buffer_size X */ X char *buf ; X char *buf_end ; X X unsigned buffer_size ; X X char *start ; /* start of valid buffer contents */ X /* (used by the R and W functions) */ X char *nextb ; /* pointer to next byte to read/write */ X /* Always: start <= nextb < buf_end */ X int buftype ; /* type of buffering */ X} ; X Xtypedef struct __sio_output_descriptor __sio_od_t ; X X X X/* X * Stream types X */ Xenum __sio_stream { __SIO_INPUT_STREAM, __SIO_OUTPUT_STREAM } ; X X X/* X * General descriptor X */ Xstruct __sio_descriptor X{ X union X { X __sio_id_t input_descriptor ; X __sio_od_t output_descriptor ; X } descriptor ; X enum __sio_stream stream_type ; X int initialized ; X} ; X Xtypedef struct __sio_descriptor __sio_descriptor_t ; X X X/* X * The array of descriptors (as many as available file descriptors) X */ Xextern __sio_descriptor_t *__sio_descriptors ; X Xextern int errno ; X X X/* X * Internally used macros X */ X#define __SIO_FD_INITIALIZED( fd ) (__sio_descriptors[ fd ].initialized) X#define __SIO_ID( fd ) (__sio_descriptors[ fd ].descriptor.input_descriptor) X#define __SIO_OD( fd ) (__sio_descriptors[ fd ].descriptor.output_descriptor) X#define __SIO_MUST_FLUSH( od, ch ) \ X ( (od).buftype != SIO_FULLBUF && \ X ( (od).buftype == SIO_NOBUF || ch == '\n' ) ) X X X/* X * SIO Macros: X * X * SIOLINELEN( fd ) X * SIOMAXLINELEN( fd ) X * Sputchar( fd, c ) X * Sgetchar( fd ) X * X * NOTE: The maximum line size depends on whether the descriptor X * was originally memory mapped. If it was, then the maximum X * line size will be the map_unit_size (a function of the system X * page size and PAGES_MAPPED). Otherwise, it will be either the X * optimal block size as reported by stat(2) or SIO_BUFFER_SIZE. X */ X X#define SIOLINELEN( fd ) __SIO_ID( fd ).line_length X#define SIOMAXLINELEN( fd ) \ X ( \ X __SIO_FD_INITIALIZED( fd ) \ X ? ( \ X (__sio_descriptors[ fd ].stream_type == __SIO_INPUT_STREAM) \ X ? __SIO_ID( fd ).max_line_length \ X : ( errno = EBADF, SIO_ERR ) \ X ) \ X : ( /* not initialized; initialize it for input */ \ X (__sio_init( &__sio_descriptors[ fd ], fd, __SIO_INPUT_STREAM ) \ X == SIO_ERR) \ X ? SIO_ERR \ X : __SIO_ID( fd ).max_line_length \ X ) \ X ) X X X X/* X * Adds a character to a buffer, returns the character or SIO_ERR X */ X#define __SIO_ADDCHAR( od, fd, c ) \ X ( od.buftype == SIO_FULLBUF ) \ X ? (int) ( *(od.nextb)++ = (unsigned char) (c) ) \ X : ( od.buftype == SIO_LINEBUF ) \ X ? ( ( *(od.nextb) = (unsigned char) (c) ) != '\n' ) \ X ? (int) *(od.nextb)++ \ X : Sputc( fd, *(od.nextb) ) \ X : Sputc( fd, c ) X X X/* X * The Sgetchar/Sputchar macros depend on the fact that the fields X * nextb, buf_end, end X * are 0 if a stream descriptor is not being used or has not yet been X * initialized. X * This is true initially because of the static allocation of the X * descriptor array, and Sdone must make sure that it is true X * after I/O on a descriptor is over. X */ X#define Sputchar( fd, c ) \ X ( \ X ( __SIO_OD( fd ).nextb < __SIO_OD( fd ).buf_end ) \ X ? ( __SIO_ADDCHAR( __SIO_OD( fd ), fd, c ) ) \ X : Sputc( fd, c ) \ X ) X X#define Sgetchar( fd ) \ X ( \ X ( __SIO_ID( fd ).nextb < __SIO_ID( fd ).end ) \ X ? (int) *__SIO_ID( fd ).nextb++ \ X : Sgetc( fd ) \ X ) X X X#ifdef __ARGS X#undef __ARGS X#endif X X#ifdef PROTOTYPES X# define __ARGS( s ) s X#else X# define __ARGS( s ) () X#endif X X/* X * The Read functions X */ Xint Sread __ARGS( ( int fd, char *buf, int nbytes ) ) ; Xint Sgetc __ARGS( ( int fd ) ) ; Xchar *Srdline __ARGS( ( int fd ) ) ; Xchar *Sfetch __ARGS( ( int fd, long *length ) ) ; X X/* X * The Write functions X */ Xint Swrite __ARGS( ( int fd, char *buf, int nbytes ) ) ; Xint Sputc __ARGS( ( int fd, char c ) ) ; Xint Sprint __ARGS( ( int fd, char *format, ... ) ) ; Xint Sprintv __ARGS( ( int fd, char *format, va_list ) ) ; X X/* X * other functions X */ Xint Sdone __ARGS( ( int fd ) ) ; Xint Sundo __ARGS( ( int fd, int type ) ) ; Xint Sflush __ARGS( ( int fd ) ) ; Xint Sclose __ARGS( ( int fd ) ) ; Xint Sbuftype __ARGS( ( int fd, int type ) ) ; X X#endif /* __SIO_H */ X END_OF_FILE if test 6642 -ne `wc -c <'libs/src/sio/sio.h'`; then echo shar: \"'libs/src/sio/sio.h'\" unpacked with wrong size! fi # end of 'libs/src/sio/sio.h' fi if test -f 'libs/src/str/strs.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libs/src/str/strs.c'\" else echo shar: Extracting \"'libs/src/str/strs.c'\" \(6391 characters\) sed "s/^X//" >'libs/src/str/strs.c' <<'END_OF_FILE' X/* X * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis X * All rights reserved. The file named COPYRIGHT specifies the terms X * and conditions for redistribution. X */ X Xstatic char RCSid[] = "$Id: strs.c,v 3.1 1993/06/13 02:50:39 panos Exp $" ; X X#include X#include X#include X Xchar *malloc() ; X X#include "ss_impl.h" X X/* X * NOTE: The brute force method (with the __strs_bfops) must be always X * available so that we can switch to it if another method fails. X */ Xextern struct ss_ops __strs_bfops ; Xextern struct ss_ops __strs_rkops ; Xextern struct ss_ops __strs_kmpops ; Xextern struct ss_ops __strs_sbmops ; Xextern struct ss_ops __strs_bmhops ; Xextern struct ss_ops __strs_soops ; X X/* X * NOTE: This table is arranged according to increasing method number. X * This allows quick indexing into it using the user-provided X * method as a hint: X * if ( selection_table[ user_method ].method == user_method ) X * FOUND X * else X * DO SEQUENTIAL SEARCH X * This allows both quick access and a change of method numbers X * in the future without requiring recompilation of programs in X * order to work with new versions of the library. X */ Xstatic struct ss_select selection_table[] = X { X { STRS_BF, &__strs_bfops }, X { STRS_RK, &__strs_rkops }, X { STRS_KMP, &__strs_kmpops }, X { STRS_SBM, &__strs_sbmops }, X { STRS_BMH, &__strs_bmhops }, X { STRS_SO, &__strs_soops }, X { 0, 0 } X } ; X Xstatic char identity_map[ ALPHABET_SIZE ] ; Xstatic char upper_to_lower_map[ ALPHABET_SIZE ] ; X Xstatic int tables_initialized ; X X/* X * This header is returned when an empty pattern is given to strs_setup. X * The rest of the functions check ss_patlen and do nothing if that is zero. X * ss_patlen in this header will be initialized to zero. X */ Xstatic header_s empty_pattern_header ; X X XPRIVATE void initialize_tables() X{ X int i ; X X for ( i = 0 ; i < sizeof( upper_to_lower_map ) ; i++ ) X { X if ( isascii( i ) && isupper( i ) ) X upper_to_lower_map[ i ] = i + 'a' - 'A' ; X else X upper_to_lower_map[ i ] = i ; X identity_map[ i ] = i ; X } X} X X X/* X * Initializes header X * X * Note that 'pattern' does not need to be a NUL-terminated string. X */ XPRIVATE int init( hp, flags, pattern, patlen ) X register header_s *hp ; X int flags ; X char *pattern ; X int patlen ; X{ X int requested_method = SS_GETMETHOD( flags ) ; X register struct ss_select *selp ; X X if ( ! tables_initialized ) X { X initialize_tables() ; X tables_initialized = TRUE ; X } X X /* X * Initialize header fields X */ X SS_FLAGS( hp ) = SS_GETFLAGS( flags ) ; X SS_PATLEN( hp ) = patlen ; X if ( SS_SWITCH( hp ) && patlen < 4 ) X SS_OPS( hp ) = &__strs_bfops ; /* brute force */ X else X { X /* X * Determine ops X */ X if ( selection_table[ requested_method ].sel_method == requested_method ) X selp = &selection_table[ requested_method ] ; X else X for ( selp = &selection_table[ 0 ] ; selp->sel_ops ; selp++ ) X if ( requested_method == selp->sel_method ) X break ; X if ( selp->sel_ops ) X SS_OPS( hp ) = selp->sel_ops ; X else if ( SS_SWITCH( hp ) ) X SS_OPS( hp ) = &__strs_bfops ; /* brute force */ X else X return( SS_ERR ) ; X } X X if ( SS_MALLOC( hp ) ) X { X SS_PATTERN( hp ) = malloc( (unsigned)SS_PATLEN( hp ) ) ; X if ( SS_PATTERN( hp ) == CHAR_NULL ) X { X (void) free( (char *)hp ) ; X return( SS_ERR ) ; X } X (void) memcpy( SS_PATTERN( hp ), pattern, (int)SS_PATLEN( hp ) ) ; X } X else X SS_PATTERN( hp ) = pattern ; X X /* X * If the user asked for case-insensitive search, we create our own X * copy of the pattern in lower case. If the pattern is malloc'ed X * we overwrite, otherwise we malloc some memory and clear the X * STRS_NOMALLOC flag. X */ X if ( SS_IGNCASE( hp ) ) X { X char *new_pattern ; X register int i ; X X SS_SETMAP( hp, upper_to_lower_map ) ; X X if ( SS_MALLOC( hp ) ) X new_pattern = SS_PATTERN( hp ) ; X else X { X new_pattern = malloc( (unsigned)SS_PATLEN( hp ) + 1 ) ; X if ( new_pattern == CHAR_NULL ) X return( SS_ERR ) ; X SS_SETMALLOC( hp ) ; /* clears the STRS_NOMALLOC flag */ X } X for ( i = 0 ; i < SS_PATLEN( hp ) ; i++ ) X new_pattern[ i ] = SS_MAP( hp, SS_PATTERN( hp )[ i ] ) ; X SS_PATTERN( hp ) = new_pattern ; X } X else X SS_SETMAP( hp, identity_map ) ; X X for ( ;; ) X { X if ( SS_SETUP( hp ) == SS_OK ) X return( SS_OK ) ; X else X { X if ( ! SS_SWITCH( hp ) || SS_OPS( hp ) == &__strs_bfops ) X { X if ( SS_MALLOC( hp ) ) X (void) free( (char *)hp ) ; X return( SS_ERR ) ; X } X SS_OPS( hp ) = &__strs_bfops ; X } X } X} X X X/* X * Finalize header X */ XPRIVATE void fini( hp ) X header_s *hp ; X{ X SS_DONE( hp ) ; X if ( SS_MALLOC( hp ) ) X (void) free( SS_PATTERN( hp ) ) ; X} X X X/* X * Create a search handle X */ Xstrs_h strs_setup( flags, pattern, va_alist ) X int flags ; X char *pattern ; X va_dcl X{ X header_s *hp ; X int patlen ; X va_list ap ; X X hp = HP( malloc( sizeof( *hp ) ) ) ; X if ( hp == NULL ) X return( NULL_HANDLE ) ; X X if ( flags & STRS_PATLEN ) X { X va_start( ap ) ; X patlen = va_arg( ap, int ) ; X va_end( ap ) ; X } X else X patlen = strlen( pattern ) ; X X if ( patlen == 0 ) X return( (strs_h) &empty_pattern_header ) ; X X if ( init( hp, flags, pattern, patlen ) == SS_OK ) X return( (strs_h)hp ) ; X else X { X free( (char *)hp ) ; X return( NULL_HANDLE ) ; X } X} X X X/* X * Destroy a search handle X */ Xvoid strs_done( handle ) X strs_h handle ; X{ X header_s *hp = HP( handle ) ; X X if ( SS_PATLEN( hp ) != 0 ) X { X fini( hp ) ; X (void) free( (char *) handle ) ; X } X} X X Xchar *strs_match( handle, str, len ) X strs_h handle ; X char *str ; X int len ; X{ X register header_s *hp = HP( handle ) ; X X if ( SS_PATLEN( hp ) == 0 ) X return( str ) ; X if ( SS_PATLEN( hp ) > len ) X return( CHAR_NULL ) ; X return( SS_MATCH( hp, str, len ) ) ; X} X X X Xchar *strs_search( flags, str, len, pattern, va_alist ) X int flags ; X char *str ; X int len ; X char *pattern ; /* NUL-terminated */ X va_dcl X{ X header_s t_header ; X char *p ; X int patlen ; X va_list ap ; X X if ( flags & STRS_PATLEN ) X { X va_start( ap ) ; X patlen = va_arg( ap, int ) ; X va_end( ap ) ; X } X else X patlen = strlen( pattern ) ; X X if ( patlen == 0 ) X return( str ) ; X X if ( patlen > len ) X return( CHAR_NULL ) ; X X if ( init( &t_header, flags | STRS_NOMALLOC, pattern, patlen ) == SS_OK ) X { X p = SS_MATCH( &t_header, str, len ) ; X fini( &t_header ) ; X return( p ) ; X } X else X return( CHAR_NULL ) ; X} X X END_OF_FILE if test 6391 -ne `wc -c <'libs/src/str/strs.c'`; then echo shar: \"'libs/src/str/strs.c'\" unpacked with wrong size! fi # end of 'libs/src/str/strs.c' fi if test -f 'xinetd/child.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xinetd/child.c'\" else echo shar: Extracting \"'xinetd/child.c'\" \(6363 characters\) sed "s/^X//" >'xinetd/child.c' <<'END_OF_FILE' X/* X * (c) Copyright 1992 by Panagiotis Tsirigotis X * All rights reserved. The file named COPYRIGHT specifies the terms X * and conditions for redistribution. X */ X Xstatic char RCSid[] = "$Id: child.c,v 6.6 1993/06/13 01:42:13 panos Exp $" ; X X#include X#include X#include X#include X#include X#include X#include X#include X X#include "str.h" X#include "pset.h" X X#include "options.h" X X#include "attr.h" X#include "server.h" X#include "state.h" X#include "sconst.h" X#include "config.h" X Xchar *inet_ntoa() ; X Xvoid msg() ; Xvoid msg_suspend() ; Xvoid msg_resume() ; X X X XPRIVATE void exec_server( serp ) X struct server *serp ; X{ X struct service_config *scp = SVC_CONF( SERVER_SERVICE( serp ) ) ; X int fd ; X int descriptor = SERVER_FD( serp ) ; X char *server = SC_SERVER( scp ) ; X char *func = "exec_server" ; X void no_control_tty() ; X X if ( debug.on ) X msg( LOG_DEBUG, func, "duping %d", descriptor ) ; X X for ( fd = 0 ; fd <= MAX_PASS_FD ; fd++ ) X if ( dup2( descriptor, fd ) == -1 ) X { X msg( LOG_ERR, func, X "dup2( %d, %d ) failed: %m", descriptor, fd ) ; X _exit( 1 ) ; X } X X (void) close( descriptor ) ; X X if ( debug.on ) X { X msg( LOG_DEBUG, func, "exec( %s ). no control terminal", server ) ; X no_control_tty() ; X } X X#ifdef RLIMIT_NOFILE X { X struct rlimit rl ; X X rl.rlim_cur = ps.ros.orig_max_descriptors ; X rl.rlim_max = ps.ros.max_descriptors ; X (void) setrlimit( RLIMIT_NOFILE, &rl ) ; X } X#endif X X msg_suspend() ; X X (void) execve( server, SC_SERVER_ARGV( scp ), X env_getvars( SC_ENV( scp )->env_handle ) ) ; X X /* X * The exec failed. Log the error and exit. X */ X msg_resume() ; X msg( LOG_ERR, func, "execv( %s ) failed: %m", server ) ; X _exit( 0 ) ; X} X X X/* X * Rename this process by changing the ps.ros.Argv vector X * Try to put the name of the service in ps.ros.Argv[0], Argv[1] X * until either the service name is exhausted or we run out X * of ps.ros.Argv's. X * The rest of ps.ros.Argv is cleared to spaces X */ XPRIVATE void rename_process( name ) X char *name ; X{ X register char *from = name ; X register char *to = ps.ros.Argv[ 0 ] ; X register int index = 1 ; X X while ( *from != NUL ) X { X if ( *to != NUL ) X *to++ = *from++ ; X else X if ( index < ps.ros.Argc ) X to = ps.ros.Argv[ index++ ] ; X else X break ; X } X str_fill( to, ' ' ) ; X while ( index < ps.ros.Argc ) X str_fill( ps.ros.Argv[ index++ ], ' ' ) ; X} X X XPRIVATE void set_credentials( scp ) X register struct service_config *scp ; X{ X char *func = "set_credentials" ; X X if ( SC_SPECIFIED( scp, A_GROUP ) || SC_SPECIFIED( scp, A_USER ) ) X if ( ps.ros.is_superuser ) X { X int gid = sc_getgid( scp ) ; X X if ( setgid( gid ) == -1 ) X { X msg( LOG_ERR, func, "setgid failed: %m" ) ; X _exit( 1 ) ; X } X } X else X msg( LOG_WARNING, func, "can't change gid; not superuser" ) ; X X if ( SC_SPECIFIED( scp, A_USER ) ) X if ( ps.ros.is_superuser ) X { X if ( setuid( SC_UID( scp ) ) == -1 ) X { X msg( LOG_ERR, func, "setuid failed: %m" ) ; X _exit( 1 ) ; X } X } X else X msg( LOG_WARNING, func, "can't change uid; not superuser" ) ; X} X X X X/* X * This function is invoked in a forked process to run a server. X * If the service is internal the appropriate function is invoked X * otherwise the server program is exec'ed. X * This function also logs the remote user id if appropriate X */ Xvoid child_process( serp ) X register struct server *serp ; X{ X struct service *sp = SERVER_SERVICE( serp ) ; X register struct service_config *scp = SVC_CONF( sp ) ; X idresult_e log_remote_user() ; X char *idresult_explain() ; X void signal_default_state() ; X X#ifdef DEBUG_SERVER X if ( debug.on ) X { X msg( LOG_DEBUG, "child_process", "Process %d is sleeping", getpid() ) ; X sleep( 10 ) ; X } X#endif X X if ( SERVER_LOGUSER( serp ) ) X { X unsigned timeout ; X idresult_e result ; X X /* X * We use LOGUSER_SUCCESS_TIMEOUT unless the service requires X * identification, in which case we use an infinite timeout X */ X timeout = SC_MUST_IDENTIFY( scp ) ? 0 : LOGUSER_SUCCESS_TIMEOUT ; X result = log_remote_user( serp, timeout ) ; X X if ( result != IDR_OK && SC_MUST_IDENTIFY( scp ) ) X { X svc_logprint( sp, NOID_ENTRY, "%s %s", X conn_addrstr( SERVER_CONNECTION( serp ) ), X idresult_explain( result ) ) ; X _exit( 0 ) ; X } X } X X if ( ! SC_IS_INTERCEPTED( scp ) ) X { X set_credentials( scp ) ; X signal_default_state() ; X if ( SC_SPECIFIED( scp, A_NICE ) ) X (void) nice( SC_NICE( scp ) ) ; X } X X if ( ! SC_IS_INTERNAL( scp ) ) X exec_server( serp ) ; X else X { X char name[ 180 ] ; X X /* X * We don't bother to disassociate from the controlling terminal X * (we have a controlling terminal only if debug.on is TRUE) X * X * Also, for interceptor processes, we give them the name: X * interceptor X */ X if ( SC_IS_INTERCEPTED( scp ) ) X strx_print( INT_NULL, name, sizeof( name ), X "%s %s interceptor", program_name, SC_ID( scp ) ) ; X else X { X int namelen = sizeof( name ) - 1 ; /* leave space for the NUL */ X struct sockaddr_in *sinp = conn_address( SERVER_CONNECTION( serp ) ) ; X int len = strx_nprint( name, namelen, X "(%s service) %s", program_name, SC_ID( scp ) ) ; X X if ( SC_ACCEPTS_CONNECTIONS( scp ) && sinp != SOCKADDRIN_NULL ) X strx_print( INT_NULL, &name[ len ], namelen - len, X " %s", inet_ntoa( sinp->sin_addr ) ) ; X } X rename_process( name ) ; X svc_internal( sp, serp ) ; X } X _exit( 0 ) ; X /* NOTREACHED */ X} X X X/* X * This function is invoked when a SIGCLD is received X */ Xvoid child_exit() X{ X char *func = "child_exit" ; X X for ( ;; ) /* Find all children that exited */ X { X int status ; X register int pid ; X struct server *serp ; X X#if defined( sun ) && defined( lint ) X pid = wait3( (union wait *)&status, WNOHANG, RUSAGE_NULL ) ; X#else X pid = wait3( &status, WNOHANG, RUSAGE_NULL ) ; X#endif X X if ( debug.on ) X msg( LOG_DEBUG, func, "wait3 returned = %d", pid ) ; X X if ( pid == -1 ) X if ( errno == EINTR ) X continue ; X else X break ; X X if ( pid == 0 ) X break ; X X if ( ( serp = server_lookup( pid ) ) != NULL ) X { X serp->svr_exit_status = status ; X server_end( serp ) ; X } X else X msg( LOG_NOTICE, func, "unknown child process %d %s", pid, X PROC_STOPPED( status ) ? "stopped" : "died" ) ; X } X} X END_OF_FILE if test 6363 -ne `wc -c <'xinetd/child.c'`; then echo shar: \"'xinetd/child.c'\" unpacked with wrong size! fi # end of 'xinetd/child.c' fi if test -f 'xinetd/udpint.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xinetd/udpint.c'\" else echo shar: Extracting \"'xinetd/udpint.c'\" \(6887 characters\) sed "s/^X//" >'xinetd/udpint.c' <<'END_OF_FILE' X/* X * (c) Copyright 1992 by Panagiotis Tsirigotis X * All rights reserved. The file named COPYRIGHT specifies the terms X * and conditions for redistribution. X */ X Xstatic char RCSid[] = "$Id: udpint.c,v 6.4 1993/06/06 00:15:17 panos Exp $" ; X X#include X#include X#include X#include X#include X#include X#include X X#include "access.h" X#include "defs.h" X#include "int.h" X X/* X * Datagrams greater than this will be truncated X */ X#define MAX_DATAGRAM_SIZE ( 32 * 1024 ) X Xchar *inet_ntoa() ; X Xvoid msg() ; X Xstruct packet X{ X struct sockaddr_in from ; X char *data ; X int size ; X} ; X Xtypedef struct packet packet_s ; X X Xstruct idgram_private X{ X unsigned received_packets ; X} ; X X#define IDP( p ) ((struct idgram_private *)(p)) X X Xstatic struct idgram_private idgram ; X XPRIVATE void di_mux() ; XPRIVATE void di_exit() ; X Xstatic struct intercept_ops idgram_ops = X { X di_mux, X di_exit X } ; X X Xstatic struct intercept dgram_intercept_state ; X X Xstruct intercept *di_init( serp ) X struct server *serp ; X{ X register struct intercept *ip = &dgram_intercept_state ; X X ip->int_socket_type = SOCK_DGRAM ; X ip->int_priv = (void *) &idgram ; X ip->int_ops = &idgram_ops ; X int_init( ip, serp ) ; X return( ip ) ; X} X X XPRIVATE void di_exit() X{ X register struct intercept *ip = &dgram_intercept_state ; X void drain() ; X X if ( IDP( ip->int_priv )->received_packets == 0 ) X drain( INT_REMOTE( ip ) ) ; X int_exit( ip ) ; X} X X X/* X * Returns only if there is an I/O error while communicating with the server X */ XPRIVATE void di_mux() X{ X register struct intercept *ip = &dgram_intercept_state ; X fd_set socket_mask ; X int mask_max ; X PRIVATE void udp_remote_to_local() ; X PRIVATE status_e udp_local_to_remote() ; X X FD_ZERO( &socket_mask ) ; X FD_SET( INT_REMOTE( ip ), &socket_mask ) ; X mask_max = INT_REMOTE( ip ) ; X X for ( ;; ) X { X register unsigned u ; X channel_s *chp ; X fd_set read_mask ; X int n_ready ; X X read_mask = socket_mask ; X n_ready = int_select( mask_max+1, &read_mask ) ; X X if ( n_ready == -1 ) X return ; X X if ( FD_ISSET( INT_REMOTE( ip ), &read_mask ) ) X { X udp_remote_to_local( ip, &chp ) ; X if ( chp != NULL ) X { X FD_SET( chp->ch_local_socket, &socket_mask ) ; X if ( chp->ch_local_socket > mask_max ) X mask_max = chp->ch_local_socket ; X } X if ( --n_ready == 0 ) X continue ; X } X X for ( u = 0 ; u < pset_count( INT_CONNECTIONS( ip ) ) ; u++ ) X { X chp = CHP( pset_pointer( INT_CONNECTIONS( ip ), u ) ) ; X X if ( FD_ISSET( chp->ch_local_socket, &read_mask ) ) X { X if ( udp_local_to_remote( chp ) == FAILED ) X return ; X if ( --n_ready == 0 ) X break ; X } X } X } X} X X X/* X * Read data from the remote socket and send it to the appropriate local X * socket. X * If this is a new connection, insert it in the connection table and X * place its handle in *chpp. X */ XPRIVATE void udp_remote_to_local( ip, chpp ) X struct intercept *ip ; X channel_s **chpp ; X{ X char buf[ MAX_DATAGRAM_SIZE ] ; X packet_s packet ; X channel_s *chp ; X bool_int addr_checked ; X PRIVATE void send_data() ; X PRIVATE status_e get_incoming_packet() ; X X *chpp = CHANNEL_NULL ; X X packet.data = buf ; X packet.size = sizeof( buf ) ; X if ( get_incoming_packet( ip, &packet ) == FAILED ) X return ; X X chp = int_lookupconn( ip, &packet.from, &addr_checked ) ; X if ( chp == CHANNEL_NULL ) X { X struct server *serp = INT_SERVER( ip ) ; X struct service *sp = SERVER_SERVICE( serp ) ; X connection_s *cop = SERVER_CONNECTION( serp ) ; X X if ( ( chp = int_newconn( ip, &packet.from, INT_REMOTE( ip ) ) ) == NULL ) X return ; X X conn_setaddr( cop, &packet.from ) ; /* for logging */ X X if ( INTERCEPT( ip ) ) X { X mask_t check_mask ; X access_e result ; X X M_OR( check_mask, MASK( CF_ADDRESS ), MASK( CF_TIME ) ) ; X result = access_control( sp, cop, &check_mask ) ; X X if ( result != AC_OK ) X { X svc_log_failure( sp, cop, result ) ; X chp->ch_state = BAD_CHANNEL ; X return ; X } X } X X /* X * Since we don't distinguish ports, there is no point to log X * another successful attempt from the same address X */ X if ( ! addr_checked ) X svc_log_success( sp, cop, SERVER_PID( serp ) ) ; X X *chpp = chp ; X } X else if ( chp->ch_state == BAD_CHANNEL ) X return ; X X#ifdef DEBUG_UDPINT X if ( debug.on ) X msg( LOG_DEBUG, "udp_remote_to_local", X "sending %d bytes to server on port %d", X packet.size, ntohs( INT_LOCALADDR( ip )->sin_port ) ) ; X#endif X X send_data( chp->ch_local_socket, X packet.data, packet.size, SOCKADDRIN_NULL ) ; X} X X X/* X * Send the data in buf to destination addr using the socket sd. X * If addr is NULL, use the default socket destination X */ XPRIVATE void send_data( sd, buf, len, addr ) X int sd ; X char *buf ; X int len ; X struct sockaddr_in *addr ; X{ X char *p ; X int left ; X int cc ; X char *func = "send_data" ; X X for ( p = buf, left = len ; left > 0 ; left -= cc, p+= cc ) X { X if ( addr == SOCKADDRIN_NULL ) X cc = send( sd, p, left, 0 ) ; X else X cc = sendto( sd, p, left, 0, SA( addr ), sizeof( *addr ) ) ; X X if ( cc == -1 ) X if ( errno == EINTR ) X { X cc = 0 ; X continue ; X } X else X { X msg( LOG_ERR, func, "%s: %m", addr ? "sendto" : "send" ) ; X return ; X } X } X} X X XPRIVATE status_e get_incoming_packet( ip, pp ) X struct intercept *ip ; X packet_s *pp ; X{ X int from_len ; X char *func = "get_incoming_packet" ; X X for ( ;; ) X { X int cc ; X X from_len = sizeof( pp->from ) ; X cc = recvfrom( INT_REMOTE( ip ), pp->data, pp->size, X 0, SA( &pp->from ), &from_len ) ; X if ( cc == -1 ) X { X if ( errno != EINTR ) X { X msg( LOG_ERR, func, "recvfrom error: %m" ) ; X return( FAILED ) ; X } X } X else if ( cc == 0 ) X return( FAILED ) ; X else X { X pp->size = cc ; X IDP( ip->int_priv )->received_packets++ ; X break ; X } X } X X if ( from_len == 0 ) X { X msg( LOG_ERR, func, "incoming packet had 0 length address" ) ; X return( FAILED ) ; X } X X#ifdef DEBUG_UDPINT X if ( debug.on ) X msg( LOG_DEBUG, func, "Received %d bytes from address: %s,%d", X pp->size, X inet_ntoa( pp->from.sin_addr ), ntohs( pp->from.sin_port ) ) ; X#endif X X return( OK ) ; X} X X X XPRIVATE status_e udp_local_to_remote( chp ) X channel_s *chp ; X{ X char buf[ MAX_DATAGRAM_SIZE ] ; X int cc ; X char *func = "udp_local_to_remote" ; X X for ( ;; ) X { X cc = recv( chp->ch_local_socket, buf, sizeof( buf ), 0 ) ; X X if ( cc == -1 ) X { X if ( errno != EINTR ) X { X msg( LOG_ERR, func, "recv from daemon: %m" ) ; X return( FAILED ) ; X } X } X else if ( cc == 0 ) X return( FAILED ) ; X else X break ; X } X X#ifdef DEBUG_UDPINT X if ( debug.on ) X msg( LOG_DEBUG, func, "sending %d bytes to address %s,%d", X cc, inet_ntoa( chp->ch_from.sin_addr ), ntohs( chp->ch_from.sin_port ) ) ; X#endif X X send_data( chp->ch_remote_socket, buf, cc, &chp->ch_from ) ; X return( OK ) ; X} X END_OF_FILE if test 6887 -ne `wc -c <'xinetd/udpint.c'`; then echo shar: \"'xinetd/udpint.c'\" unpacked with wrong size! fi # end of 'xinetd/udpint.c' fi echo shar: End of archive 15 \(of 31\). cp /dev/null ark15isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 31 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0