#! /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 <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 20 (of 31)."
# Contents:  xinetd/sconf.c xinetd/shutdown.c
# Wrapped by panos@mystique on Mon Jun 21 14:51:26 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'xinetd/sconf.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xinetd/sconf.c'\"
else
echo shar: Extracting \"'xinetd/sconf.c'\" \(11251 characters\)
sed "s/^X//" >'xinetd/sconf.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: sconf.c,v 6.7 1993/06/15 23:25:57 panos Exp $" ;
X
X#include "misc.h"
X
X#include "state.h"
X#include "defs.h"
X#include "attr.h"
X#include "sconf.h"
X#include "addr.h"
X
Xchar *malloc() ;
Xint free() ;
X
X#define NEW_SCONF()					NEW( struct service_config )
X#define FREE_SCONF( scp )			FREE( scp )
X
X/*
X * Conditional free; checks if the pointer is NULL
X */
X#define COND_FREE( x )           if ( x )                   \
X                                 {                          \
X                                    free( (char *) x ) ;    \
X                                    x = NULL ;              \
X                                 }
X
Xextern struct name_value success_log_options[] ;
Xextern struct name_value failure_log_options[] ;
Xextern struct name_value service_types[] ;
Xextern struct name_value service_flags[] ;
Xextern struct name_value socket_types[] ;
Xextern struct name_value syslog_facilities[] ;
Xextern struct name_value syslog_levels[] ;
X
Xvoid tabprint() ;
Xvoid out_of_memory() ;
X
X
X/*
X * Allocate a new service_config and initialize the service name field
X * with 'name'; the rest of the fields are set to 0 which gives them
X * their default values.
X */
Xstruct service_config *sc_alloc( name )
X	char *name ;
X{
X	struct service_config *scp ;
X	char *func = "sc_alloc" ;
X
X	scp = NEW_SCONF() ;
X	if ( scp == NULL )
X	{
X		out_of_memory( func ) ;
X		return( NULL ) ;
X	}
X	CLEAR( *scp ) ;
X	scp->sc_name = name ;
X	return( scp ) ;
X}
X
X
XPRIVATE void release_string_pset( pset )
X	pset_h pset ;
X{
X	pset_apply( pset, free, NULL ) ;
X	pset_destroy( pset ) ;
X}
X
X
X
X/*
X * Free all malloc'ed memory for the specified service
X */
Xvoid sc_free( scp )
X   register struct service_config *scp ;
X{
X	void ti_free() ;
X
X   COND_FREE( scp->sc_name ) ;
X   COND_FREE( scp->sc_id ) ;
X   COND_FREE( scp->sc_protocol.name ) ;
X   COND_FREE( scp->sc_server ) ;
X   if ( scp->sc_server_argv )
X   {
X      register char **pp ;
X
X		/*
X		 * argv[ 0 ] is a special case because it may not have been allocated yet
X		 */
X		if ( scp->sc_server_argv[ 0 ] != NULL)
X			free( scp->sc_server_argv[ 0 ] ) ;
X      for ( pp = &scp->sc_server_argv[ 1 ] ; *pp != NULL ; pp++ )
X         free( *pp ) ;
X      free( (char *) scp->sc_server_argv ) ;
X   }
X   COND_FREE( log_filelog( SC_LOG( scp ) )->fl_filename ) ;
X
X	if ( scp->sc_access_times != NULL )
X	{
X		ti_free( scp->sc_access_times ) ;
X		pset_destroy( scp->sc_access_times ) ;
X	}
X
X	if ( scp->sc_only_from != NULL )
X	{
X		addrlist_free( scp->sc_only_from ) ;
X		pset_destroy( scp->sc_only_from ) ;
X	}
X
X	if ( scp->sc_no_access != NULL )
X	{
X		addrlist_free( scp->sc_no_access ) ;
X		pset_destroy( scp->sc_no_access ) ;
X	}
X
X   if ( scp->sc_env_var_defs != NULL )
X		release_string_pset( scp->sc_env_var_defs ) ;
X	if ( scp->sc_pass_env_vars != NULL )
X		release_string_pset( scp->sc_pass_env_vars ) ;
X	if ( SC_ENV( scp )->env_type == CUSTOM_ENV && 
X												SC_ENV( scp )->env_handle != ENV_NULL )
X		env_destroy( SC_ENV( scp )->env_handle ) ;
X	
X	FREE_SCONF( scp ) ;
X}
X
X
X/*
X * Create a configuration for one of the special services
X */
Xstruct service_config *sc_make_special( service_name, bp, instances )
X	char *service_name ;
X	builtin_s *bp ;
X	int instances ;
X{
X	char *name ;
X	struct service_config *scp ;
X	char *func = "sc_make" ;
X
X	name = make_string( 1, service_name ) ;
X	if ( name == NULL )
X	{
X		out_of_memory( func ) ;
X		return( NULL ) ;
X	}
X
X	if ( ( scp = sc_alloc( name ) ) == NULL )
X	{
X		free( name ) ;
X		return( NULL ) ;
X	}
X
X   scp->sc_id = make_string( 1, scp->sc_name ) ;
X   if ( scp->sc_id == NULL )
X   {
X      free( name ) ;
X      out_of_memory( func ) ;
X      return( NULL ) ;
X   }
X   SC_SPECIFY( scp, A_ID ) ;
X
X	/*
X	 * All special services are internal
X	 */
X   M_SET( scp->sc_type, ST_SPECIAL ) ;
X   M_SET( scp->sc_type, ST_INTERNAL ) ;
X	scp->sc_builtin = bp ;
X   SC_SPECIFY( scp, A_TYPE ) ;
X
X   M_SET( scp->sc_flags, SF_NORETRY ) ;
X   SC_SPECIFY( scp, A_FLAGS ) ;
X
X   scp->sc_instances = instances ;
X   SC_SPECIFY( scp, A_INSTANCES ) ;
X
X   scp->sc_wait = NO ;
X   SC_SPECIFY( scp, A_WAIT ) ;
X
X	return( scp ) ;
X}
X
X
X
XPRIVATE void dump_log_data( fd, scp, tab_level )
X	int fd ;
X	register struct service_config *scp ;
X	int tab_level ;
X{
X	register struct log *lp = SC_LOG( scp ) ;
X	register struct filelog *flp ;
X	int i ;
X
X	switch ( log_get_type( lp ) )
X	{
X		case L_NONE:
X			tabprint( fd, tab_level, "No logging\n" ) ;
X			return ;
X
X		case L_COMMON_FILE:
X			tabprint( fd, tab_level, "Logging to common log file\n" ) ;
X			break ;
X
X		case L_FILE:
X			flp = log_filelog( lp ) ;
X			tabprint( fd, tab_level, "Logging to file: %s", flp->fl_filename ) ;
X
X			if ( FILELOG_SIZE_CONTROL( flp ) )
X				Sprint( fd, " (soft=%d hard=%d)\n",
X								flp->fl_soft_limit, flp->fl_hard_limit ) ;
X			else
X				Sprint( fd, " (no limits)\n" ) ;
X			break ;
X		
X		case L_SYSLOG:
X			tabprint( fd, tab_level,
X				"Logging to syslog. Facility = %s, level = %s\n",
X					nv_get_name( syslog_facilities, log_syslog( lp )->sl_facility ),
X					nv_get_name( syslog_levels, log_syslog( lp )->sl_level ) ) ;
X			break ;
X	}
X
X	tabprint( fd, tab_level, "Log_on_success flags =" ) ;
X	for ( i = 0 ; success_log_options[ i ].name != NULL ; i++ )
X		if ( M_IS_SET( scp->sc_log_on_success, success_log_options[ i ].value ) )
X			Sprint( fd, " %s", success_log_options[ i ].name ) ;
X	Sputchar( fd, '\n' ) ;
X
X	tabprint( fd, tab_level, "Log_on_failure flags =" ) ;
X	for ( i = 0 ; failure_log_options[ i ].name != NULL ; i++ )
X		if ( M_IS_SET( scp->sc_log_on_failure, failure_log_options[ i ].value ) )
X			Sprint( fd, " %s", failure_log_options[ i ].name ) ;
X	Sputchar( fd, '\n' ) ;
X}
X
X
X/*
X * Print info about service scp to file descriptor fd
X */
Xvoid sc_dump( scp, fd, tab_level, is_defaults )
X	register struct service_config *scp ;
X	register int fd ;
X	int tab_level ;
X	bool_int is_defaults ;
X{
X	register struct name_value		*nvp ;
X	register unsigned 				u ;
X	register char 						**pp ;
X	void 									ti_dump() ;
X
X	if ( is_defaults )
X		tabprint( fd, tab_level, "Service defaults\n" ) ;
X	else
X		tabprint( fd, tab_level, "Service configuration: %s\n", scp->sc_name ) ;
X
X	if ( ! is_defaults )
X	{
X		tabprint( fd, tab_level+1, "id = %s\n", scp->sc_id ) ;
X
X		if ( ! M_ARE_ALL_CLEAR( scp->sc_flags ) )
X		{
X			tabprint( fd, tab_level+1, "flags =" ) ;
X			for ( nvp = &service_flags[ 0 ] ; nvp->name != NULL ; nvp++ )
X				if ( M_IS_SET( scp->sc_flags, nvp->value ) )
X					Sprint( fd, " %s", nvp->name ) ;
X			Sputchar( fd, '\n' ) ;
X		}
X
X		if ( ! M_ARE_ALL_CLEAR( scp->sc_type ) )
X		{
X			tabprint( fd, tab_level+1, "type =" ) ;
X			for ( nvp = &service_types[ 0 ] ; nvp->name != NULL ; nvp++ )
X				if ( M_IS_SET( scp->sc_type, nvp->value ) )
X					Sprint( fd, " %s", nvp->name ) ;
X			Sputchar( fd, '\n' ) ;
X		}
X
X		tabprint( fd, tab_level+1, "socket_type = %s\n",
X			nv_get_name( socket_types, scp->sc_socket_type ) ) ;
X
X		if ( SC_SPECIFIED( scp, A_PORT ) )
X			tabprint( fd, tab_level+1, "port = %d\n", scp->sc_port ) ;
X
X		tabprint( fd, tab_level+1, "Protocol (name,number) = (%s,%d)\n",
X				scp->sc_protocol.name, scp->sc_protocol.value ) ;
X	}
X
X	if ( SC_SPECIFIED( scp, A_INSTANCES ) )
X		if ( scp->sc_instances == UNLIMITED )
X			tabprint( fd, tab_level+1, "Instances = UNLIMITED\n" ) ;
X		else
X			tabprint( fd, tab_level+1, "Instances = %d\n", scp->sc_instances ) ;
X		
X	if ( SC_SPECIFIED( scp, A_NICE ) )
X		tabprint( fd, tab_level+1, "Nice = %d\n", scp->sc_nice ) ;
X
X	if ( ! is_defaults )
X	{
X		if ( ! SC_IS_INTERNAL( scp ) )
X		{
X			tabprint( fd, tab_level+1, "Server = %s\n", scp->sc_server ) ;
X			tabprint( fd, tab_level+1, "Server argv =" ) ;
X			for ( pp = scp->sc_server_argv ; *pp ; pp++ )
X				Sprint( fd, " %s", *pp ) ;
X			Sputchar( fd, '\n' ) ;
X		} 
X
X		if ( SC_IS_RPC( scp ) )
X		{
X			struct rpc_data *rdp = SC_RPCDATA( scp ) ;
X
X			tabprint( fd, tab_level+1, "RPC data\n" ) ;
X			tabprint( fd, tab_level+2,
X									"program number = %ld\n", rdp->rd_program_number ) ;
X			tabprint( fd, tab_level+2, "rpc_version = " ) ;
X			if ( rdp->rd_min_version == rdp->rd_max_version )
X				Sprint( fd, "%ld\n", rdp->rd_min_version ) ;
X			else
X				Sprint( fd, "%ld-%ld\n",
X									rdp->rd_min_version, rdp->rd_max_version ) ;
X		}
X
X		if ( SC_SPECIFIED( scp, A_ACCESS_TIMES ) )
X		{
X			tabprint( fd, tab_level+1, "Access times =" ) ;
X			ti_dump( scp->sc_access_times, fd ) ;
X			Sputchar ( fd, '\n' ) ;
X		}
X	}
X
X	if ( SC_SPECIFIED( scp, A_ONLY_FROM ) )
X	{
X		tabprint( fd, tab_level+1, "Only from: " ) ;
X		addrlist_dump( scp->sc_only_from, fd ) ;
X		Sputchar( fd, '\n' ) ;
X	}
X
X	if ( SC_SPECIFIED( scp, A_NO_ACCESS ) )
X	{
X		tabprint( fd, tab_level+1, "No access: " ) ;
X		addrlist_dump( scp->sc_no_access, fd ) ;
X		Sputchar( fd, '\n' ) ;
X	}
X	
X	dump_log_data( fd, scp, tab_level+1 ) ;
X
X	if ( SC_SPECIFIED( scp, A_PASSENV ) )
X	{
X		tabprint( fd, tab_level+1, "Passenv =" ) ;
X		for ( u = 0 ; u < pset_count( scp->sc_pass_env_vars ) ; u++ )
X			Sprint( fd, " %s",
X						(char *) pset_pointer( scp->sc_pass_env_vars, u ) ) ;
X		Sputchar ( fd, '\n' ) ;
X	}
X
X	if ( ! is_defaults )
X		if ( SC_SPECIFIED( scp, A_ENV ) )
X		{
X			tabprint( fd, tab_level+1, "Environment additions:\n" ) ;
X			for ( u = 0 ; u < pset_count( scp->sc_env_var_defs ) ; u++ )
X				tabprint( fd, tab_level+2,
X						"%s\n", (char *) pset_pointer( scp->sc_env_var_defs, u ) ) ;
X		}
X	
X	if ( SC_ENV( scp )->env_type == CUSTOM_ENV )
X	{
X		tabprint( fd, tab_level+1, "Environment strings:\n" ) ;
X		for ( pp = env_getvars( SC_ENV( scp )->env_handle ) ; *pp ; pp++ )
X			tabprint( fd, tab_level+2, "%s\n", *pp ) ;
X	}
X	Sflush( fd ) ;
X}
X
X
X#define SC_RPCPROGNUM( s )    RD_PROGNUM( SC_RPCDATA( s ) )
X#define SAME_RPC( s1, s2 )    ( SC_RPCPROGNUM( s1 ) == SC_RPCPROGNUM( s2 ) )
X#define SAME_NONRPC( s1, s2 ) ( (s1)->sc_socket_type == (s2)->sc_socket_type \
X                                 && (s1)->sc_port == (s2)->sc_port )
X
X/*
X * Two service configurations are considered different if any of the
X * following is TRUE:
X *		1) only one is unlisted
X *		2) only one is internal
X *		3) only one is RPC
X *		4) they have different values for the 'wait' attribute
X *		5) they use different protocols
X *		6) they are both RPC services but have different program numbers
X *		7) neither is an RPC service and they have different socket_types or
X *			use diffent ports
X *
X * This function returns TRUE if the specified configurations are different.
X *
X * Note that this function is closely related to the 'readjust' function
X * that is invoked on reconfiguration; that function will not change 
X * attributes that this function checks to determine if two configurations
X * are different.
X */
Xbool_int sc_different_confs( scp1, scp2 )
X	struct service_config *scp1, *scp2 ;
X{
X   if ( SC_IS_UNLISTED( scp1 ) != SC_IS_UNLISTED( scp2 ) ||
X				SC_IS_INTERNAL( scp1 ) != SC_IS_INTERNAL( scp2 ) ||
X					SC_IS_RPC( scp1 ) != SC_IS_RPC( scp2 ) )
X      return( TRUE ) ;
X
X   if ( scp1->sc_wait != scp2->sc_wait )
X      return( TRUE ) ;
X  
X	if ( scp1->sc_protocol.value != scp2->sc_protocol.value )
X      return( TRUE ) ;
X
X   if ( SC_IS_RPC( scp1 ) )
X   {
X		if ( ! SAME_RPC( scp1, scp2 ) )
X         return( TRUE ) ;
X   }
X   else
X   {
X		if ( ! SAME_NONRPC( scp1, scp2 ) )
X         return( TRUE ) ;
X   }
X   return( FALSE ) ;
X}
X
END_OF_FILE
if test 11251 -ne `wc -c <'xinetd/sconf.c'`; then
    echo shar: \"'xinetd/sconf.c'\" unpacked with wrong size!
fi
# end of 'xinetd/sconf.c'
fi
if test -f 'xinetd/shutdown.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xinetd/shutdown.c'\"
else
echo shar: Extracting \"'xinetd/shutdown.c'\" \(10894 characters\)
sed "s/^X//" >'xinetd/shutdown.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: shutdown.c,v 6.4 1993/06/13 01:47:17 panos Exp $" ;
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X#include <pwd.h>
X#include <string.h>
X#include <syslog.h>
X
X#include "sio.h"
X#include "str.h"
X
X#include "defs.h"
X
Xchar *malloc() ;
Xchar *crypt() ;
X
Xvoid msg() ;
X
Xtypedef enum { SD_LOGIN, SD_SHELL, SD_EXEC, SD_FINGER } shutdown_e ;
X
Xstruct shutdown_function
X{
X	char			*sf_service ;
X	voidfunc 	sf_func ;
X	char			*sf_function_name ;
X} ;
X
X
XPRIVATE void rlogin_shutdown() ;
XPRIVATE void rexec_shutdown() ;
XPRIVATE void rsh_shutdown() ;
XPRIVATE void finger_shutdown() ;
X
Xstatic struct shutdown_function shutdown_functions[] =
X   {
X      { "login",		rlogin_shutdown,	"rlogin_shutdown"	},
X		{ "shell",		rsh_shutdown,		"rsh_shutdown"		},
X		{ "exec",		rexec_shutdown,	"rexec_shutdown"	},
X		{ "finger",		finger_shutdown,	"finger_shutdown"	},
X      { CHAR_NULL }
X   } ;
X
X
Xtypedef enum
X	{
X		RS_OK, RS_EOF, RS_IOERR, RS_NOMEM, RS_TOOLONG, RS_BADCONN
X	} read_status_e ;
X
Xstatic struct name_value read_status_names[] =
X	{
X		{ "Error: out of memory",		(int) RS_NOMEM		},
X		{ "Error: input too long",		(int) RS_TOOLONG	},
X		{ "Error: I/O",					(int) RS_IOERR  	},
X		{ "Error: end-of-file",			(int) RS_EOF		},
X		{ "Error: bad connection",		(int) RS_BADCONN	},
X		{ CHAR_NULL,						1						},
X		{ "UNKNOWN",						0						}
X	} ;
X
X#define rs_explain( s )			nv_get_name( read_status_names, (int) (s) )
X
X
X/*
X * NOTE: All shutdown functions assume that the process will exit
X * 		very soon, so they don't bother to deallocate any malloc'ed
X *			memory. In particular, it is not guaranteed that the memory 
X *			returned by these functions will point to malloc'ed memory
X */
X
X
X/*
X * Locate and return the shutdown function for the given service
X */
Xvoidfunc get_shutdown_by_name( service ) 
X	register char *service ;
X{
X	register struct shutdown_function *sfp ;
X
X	for ( sfp = &shutdown_functions[ 0 ] ; sfp->sf_service ; sfp++ )
X		if ( EQ( service, sfp->sf_service ) )
X			return( sfp->sf_func ) ;
X	return( NULL ) ;
X}
X
X
Xchar *get_shutdown_by_addr( func )
X	register voidfunc func ;
X{
X	register struct shutdown_function *sfp ;
X
X	for ( sfp = &shutdown_functions[ 0 ] ; sfp->sf_service ; sfp++ )
X		if ( func == sfp->sf_func )
X			break ;
X	return( sfp->sf_function_name ) ;
X}
X
X
X/*
X * Read a string of length at most max_len from socket sd.
X * The string is placed in buf (if buf is not NULL). If buf
X * is NULL, the input is drained.
X * The input string is always read even if the allowed length
X * is exceeded (the extra characters are ignored).
X * max_len is the maximum length of the input string excluding the
X * terminating NUL.
X * The actual length is returned in lenp.
X */
XPRIVATE read_status_e read_string( sd, max_len, buf, lenp )
X	int					sd ;
X	register unsigned max_len ;
X	char					*buf ;
X	unsigned				*lenp ;
X{
X	char						c ;
X	register char			*p ;
X	int						cc ;
X	read_status_e			read_status ;
X	register status_e		status		= OK ;
X	register int			len			= 0 ;
X	int						drain_input = ( buf == NULL ) ;
X
X	if ( drain_input )
X	{
X		status = FAILED ;
X		p = &c ;
X	}
X	else
X	{
X		p = buf ;
X		status = OK ;
X	}
X
X	for ( ;; )
X	{
X		/*
X		 * Keep reading characters one by one (ugly !!!)
X		 * If status == FAILED, don't store them
X		 * Interesting side-effect: since we stop increasing p in
X		 * this case, *p will be used for storing all subsequent input
X		 * until the NUL. So we get a NUL terminated string with
X		 * the extra characters ignored.
X		 */
X		if ( len > max_len )
X		{
X			status = FAILED ;
X			read_status = RS_TOOLONG ;
X		}
X
X		/*
X		 * If an I/O error occurs, end the loop
X		 */
X		if ( ( cc = read( sd, p, 1 ) ) != 1 )
X		{
X			if ( cc == -1 )
X				if ( errno == EINTR )
X					continue ;
X				else
X					read_status = RS_IOERR ;
X			else
X				read_status = RS_EOF ;
X			status = FAILED ;
X			break ;
X		}
X		if ( *p == NUL )
X			break ;
X		if ( status == OK )
X		{
X			len++ ;
X			p++ ;
X		}
X	}
X	if ( status == OK )
X	{
X		*lenp = len ;
X		read_status = RS_OK ;
X	}
X	return( drain_input ? RS_OK : read_status ) ;
X}
X
X
X/*
X * Allocates a single buffer big enough to hold <count> strings whose
X * maximum lengths are given in the <limits> array
X * The pointers in the <strings> array will point to the part
X * of the buffer for each string.
X */
XPRIVATE char *setup( count, limits, strings )
X	register unsigned		count ;
X	unsigned					limits[] ;
X	char						*strings[] ;
X{
X	register unsigned		total_len ;
X	register unsigned		index ;
X	register unsigned		u ;
X	char						*buf ;
X
X	for ( u = 0, total_len = 0 ; u < count ; u++ )
X		total_len += limits[ u ] ;
X	
X	buf = malloc( total_len + count ) ;		/* count the NULs */
X	if ( buf == NUL )
X		return( NULL ) ;
X	
X	for ( u = 0, index = 0 ; u < count ; u++ )
X	{
X		strings[ u ] = &buf[ index ] ;
X		index += limits[ u ] + 1 ;
X	}
X	return( buf ) ;
X}
X
X
X
XPRIVATE int connect_back( id, sd, port )
X	shutdown_e			id ;
X	int					sd ;
X	unsigned short 	port ;
X{
X	int						new_sd ;
X	struct sockaddr_in	sin ;
X	int						sin_len	= sizeof( sin ) ;
X	char						*func		= "connect_back" ;
X
X	/*
X	 * Get the remote address
X	 */
X	if ( getpeername( sd, SA( &sin ), &sin_len ) == -1 )
X	{
X		if ( debug.on )
X			msg( LOG_DEBUG, func, "id=%d, getpeername: %m", (int) id ) ;
X		return( -1 ) ;
X	}
X
X	/*
X	 * Get a socket for the new connection.
X	 * For the shell service, the socket must have a proviliged local port
X	 */
X	if ( id == SD_SHELL )
X	{
X		int local_port = IPPORT_RESERVED - 1 ;
X		unsigned short client_port = ntohs( sin.sin_port ) ;
X
X		if ( ! ( client_port >= IPPORT_RESERVED/2 &&
X											client_port < IPPORT_RESERVED ) )
X		return( -1 ) ;
X
X		if ( ( new_sd = rresvport( &local_port ) ) == -1 )
X			return( -1 ) ;
X	}
X	else if ( id == SD_EXEC )
X	{
X		if ( ( new_sd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
X			return( -1 ) ;
X	}
X	else
X		return( -1 ) ;
X
X	sin.sin_port = htons( port ) ;
X	sin.sin_family = AF_INET ;
X	if ( connect( new_sd, SA( &sin ), sizeof( sin ) ) == -1 )
X	{
X		if ( debug.on )
X			msg( LOG_DEBUG, func, "connect: %m (port=%d)", port ) ;
X		(void) close( new_sd ) ;
X		return( -1 ) ;
X	}
X	return( new_sd ) ;
X}
X
X
XPRIVATE status_e rservices_common( id, sd, nargs, 
X										limits, strings, total_lenp, pp )
X	shutdown_e	id ;				/* service id 											*/
X	unsigned		nargs ;			/* number of expected args. args are 			*/
X										/* NUL-terminated strings							*/
X	unsigned		limits[] ;		/* max length of each arg							*/
X	char			*strings[] ;	/* array of arg pointers							*/
X	unsigned		*total_lenp ;	/* total length of args								*/
X	char			**pp ;			/* pointer to string to put error message		*/
X{
X	read_status_e	rs ;
X	char				*store_buf ;
X	unsigned			total_len ;
X	unsigned			len ;
X	int				i ;
X	char				*func = "rservices_common" ;
X
X	store_buf = setup( nargs, limits, strings ) ;
X	if ( store_buf == NULL )
X	{
X		*pp = rs_explain( RS_NOMEM ) ;
X		return( FAILED ) ;
X	}
X
X	for ( i = 0, total_len = 0 ; i < nargs ; i++ )
X	{
X		rs = read_string( sd, limits[ i ], strings[ i ], &len ) ;
X		if ( rs != RS_OK )
X		{
X			*pp = rs_explain( rs ) ;
X			return( FAILED ) ;
X		}
X
X		if ( i == 0 && ( id == SD_SHELL || id == SD_EXEC ) )
X		{
X			unsigned short port = atoi( strings[ 0 ] ) ;
X
X			if ( debug.on )
X				msg( LOG_DEBUG, func, "port for new connection = %d", port ) ;
X
X			if ( port != 0 && connect_back( id, sd, port ) == -1 )
X			{
X				*pp = rs_explain( RS_BADCONN ) ;
X				return( FAILED ) ;
X			}
X		}
X		else
X			total_len += len ;
X	}
X	*total_lenp = total_len ;
X	return( OK ) ;
X}
X
X
X#define RLOGIN_ARGS 		4
X
XPRIVATE void rlogin_shutdown( sd, pp )
X	int sd ;
X	char **pp ;
X{
X	char					*print_buf ;
X	unsigned				print_buf_size ;
X	unsigned				total_len ;
X	char					*strings[ RLOGIN_ARGS ] ;
X	static unsigned	limits[ RLOGIN_ARGS ] = { 0, 16, 16, 4096 } ;
X
X	(void) write( sd, "", 1 ) ;
X
X	if ( pp == NULL )
X		return ;
X
X	if ( rservices_common( SD_LOGIN, sd,
X				RLOGIN_ARGS, limits, strings, &total_len, pp ) == FAILED )
X		return ;
X
X	print_buf_size = total_len + 100 ;
X	print_buf = malloc( print_buf_size ) ;
X	if ( print_buf != NULL )
X		*pp = strx_sprint( print_buf, print_buf_size,
X						"remote_user=%s local_user=%s tty=%s",
X							strings[ 1 ], strings[ 2 ], strings[ 3 ] ) ;
X	else
X		*pp = rs_explain( RS_NOMEM ) ;
X}
X
X
X	
X#define REXEC_ARGS			4
X#define SALT_LEN				2
X
XPRIVATE void rexec_shutdown( sd, pp )
X	int sd ;
X	char **pp ;
X{
X	char					*print_buf ;
X	unsigned				print_buf_size ;
X	char					*password ;
X	char					salt[ SALT_LEN ] ;
X	struct passwd		*pw ;
X	char					*verify ;
X	unsigned				total_len ;
X	char					*strings[ REXEC_ARGS ] ;
X	char					error_indication		= '\1' ;
X	char					*error_message			= "Permission denied.\n" ;
X	static unsigned	limits[ REXEC_ARGS ] = { 5, 16, 16, 4096 } ;
X
X	(void) write( sd, &error_indication, 1 ) ;
X	(void) write( sd, error_message, strlen( error_message ) + 1 ) ;
X	
X	if ( pp == NULL )
X		return ;
X
X	if ( rservices_common( SD_EXEC, sd,
X				REXEC_ARGS, limits, strings, &total_len, pp ) == FAILED )
X		return ;
X
X	/*
X	 * Verify the password
X	 */
X	password = strings[ 2 ] ;
X	pw = getpwnam( strings[ 1 ] ) ;
X	if ( pw != NULL )
X	{
X		strncpy( salt, pw->pw_passwd, SALT_LEN )[ SALT_LEN ] = NUL ;
X		if ( EQ( crypt( password, salt ), pw->pw_passwd ) )
X			verify = "ok" ;
X		else
X			verify = "failed" ;
X	}
X	else
X		verify = "baduser" ;
X
X	str_fill( password, ' ' ) ;		/* clear the password */
X
X	print_buf_size = total_len + 100 ;
X	print_buf = malloc( print_buf_size ) ;
X	if ( print_buf != NULL )
X		*pp = strx_sprint( print_buf, print_buf_size, 
X							"remote_user=%s verify=%s command=%s",
X											strings[ 1 ], verify, strings[ 3 ] ) ;
X	else
X		*pp = rs_explain( RS_NOMEM ) ;
X}
X
X
X
X#define RSH_ARGS			4
X
XPRIVATE void rsh_shutdown( sd, pp )
X	int sd ;
X	char **pp ;
X{
X	char					*print_buf ;
X	unsigned				print_buf_size ;
X	unsigned				total_len ;
X	char					*strings[ RSH_ARGS ] ;
X	char					error_indication		= '\1' ;
X	char					*error_message			= "Permission denied.\n" ;
X	static unsigned	limits[ RSH_ARGS ]	= { 5, 16, 16, 4096 } ;
X
X	(void) write( sd, &error_indication, 1 ) ;
X	(void) write( sd, error_message, strlen( error_message ) + 1 ) ;
X
X	if ( pp == NULL )
X		return ;
X	
X	if ( rservices_common( SD_SHELL, sd,
X					RSH_ARGS, limits, strings, &total_len, pp ) == FAILED )
X		return ;
X	
X	print_buf_size = total_len + 100 ;
X	print_buf = malloc( print_buf_size ) ;
X	if ( print_buf != NULL )
X		*pp = strx_sprint( print_buf, print_buf_size,
X					"remote_user=%s local_user=%s command=%s",
X							strings[ 1 ], strings[ 2 ], strings[ 3 ] ) ;
X	else
X		*pp = rs_explain( RS_NOMEM ) ;
X}
X
X
XPRIVATE void finger_shutdown( sd, pp )
X	int sd ;
X	char **pp ;
X{
X	char *line ;
X	int line_len ;
X
X	if ( pp == NULL )
X		return ;
X	
X	line = Srdline( sd ) ;
X	line_len = SIOLINELEN( sd ) ;
X
X	if ( line_len > 0 && line[ line_len-1 ] == '\r' )
X		line[ --line_len ] = NUL ;
X
X	*pp = ( line_len == 0 ) ? "EMPTY-LINE" : line ;
X}
X
END_OF_FILE
if test 10894 -ne `wc -c <'xinetd/shutdown.c'`; then
    echo shar: \"'xinetd/shutdown.c'\" unpacked with wrong size!
fi
# end of 'xinetd/shutdown.c'
fi
echo shar: End of archive 20 \(of 31\).
cp /dev/null ark20isdone
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
