From 9a5f280a7dc512b75ce25ed9143b5259f3ecc184 Mon Sep 17 00:00:00 2001 From: Thomas Swan Date: Wed, 2 Oct 2013 23:00:12 -0500 Subject: [PATCH] new feature: support for rfc1078 help command "help" is reserved keyword according to rfc1078 and must list TCPMUX services. If the help service is requested from the TCPMUX server, any services listed must be accessible via TCPMUX. The patch also introduces new flag PUBLISH which is required for the tcpmux service to be published via the help command. TCPMUX and TCPMUXPLUS services which do not have the PUBLISH flag are not listed in order to preserve the existing behavior and to support providing unpublished TCPMUX services. --- xinetd/builtins.c | 86 ++++++++++++++++++++++++++++++++++++++++-- xinetd/nvlists.c | 1 + xinetd/sconf.h | 2 + xinetd/service.h | 4 +- xinetd/xinetd.conf.man | 52 +++++++++++++++++++++---- 5 files changed, 133 insertions(+), 12 deletions(-) diff --git a/xinetd/builtins.c b/xinetd/builtins.c index 3b85579..a414cf3 100644 --- a/xinetd/builtins.c +++ b/xinetd/builtins.c @@ -489,6 +489,64 @@ static void dgram_chargen( const struct server *serp ) (void) sendto( fd, buf, (size_t)(p-buf), 0, SA( &lsin ), sin_len ) ; } +/* Handle a help request for the tcpmux service. + * It's helpful to remember here that we are now a child of the original + * xinetd process and were called after the first line of input was + * read from the tcpmux_server routine. + * Serp still points to an actual tcpmux 'server', or at least the + * service pointer of serp is valid. + */ + +static void tcpmux_help( const struct server *serp ) +{ + char buff[ 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; + + /* 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 ( ! SVC_IS_MUXCLIENT( sp ) ) + { + if ( debug.on ) + { + msg( LOG_DEBUG, "tcpmux_handler", + "help skipping non-tcpmux service: %s.", + SC_NAME( SVC_CONF ( sp ) ) ); + continue; + } + } + + /* only list tcpmux services with the TCPMUXHELP flag + */ + if ( ! SVC_MUXHELP( sp ) ) + { + msg( LOG_DEBUG, "tcpmux_handler", "help skipping unpublished service: %s.", SC_NAME( SVC_CONF ( sp ) ) ); + continue; + } + + msg( LOG_DEBUG, "tcpmux_handler", "help listing: %s", + SC_NAME( SVC_CONF( sp ) ) ); + + strncpy( buff, SC_NAME( SVC_CONF( sp ) ), BUFFER_SIZE - 2 ); + strcat( buff, TCPMUX_CRLF ); + if ( Swrite( descriptor, buff, strlen( buff ) ) != strlen( buff ) ) + { + msg(LOG_ERR, "tcpmux_handler", "write failed for help."); + exit(0); + } + + continue; + } +} /* Handle a request for a tcpmux service. * It's helpful to remember here that we are now a child of the original @@ -544,9 +602,19 @@ static void tcpmux_handler( const struct server *serp ) cc, svc_name); } - /* Search the services for the a match on name. + /* RFC 1078: help is a reserved service name */ + if ( strcasecmp( svc_name, "help" ) == 0 ) + { + msg(LOG_DEBUG, "tcpmux_handler", "help requested"); + tcpmux_help( serp ); + Sflush( descriptor ); + Sclose( descriptor ); + exit(0); + } + /* 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 ) ) ; @@ -557,7 +625,7 @@ static void tcpmux_handler( const struct server *serp ) */ scp = SVC_CONF( sp ); - if ( ! SVC_IS_MUXCLIENT( sp ) && ! SVC_IS_MUXPLUSCLIENT( sp ) ) + if ( ! SVC_IS_MUXCLIENT( sp ) ) { if ( debug.on ) { @@ -569,7 +637,6 @@ static void tcpmux_handler( const struct server *serp ) /* Send the accept string if we're a PLUS (+) client. */ - if ( SVC_IS_MUXPLUSCLIENT( sp ) ) { if ( Swrite( descriptor, TCPMUX_ACK, sizeof( TCPMUX_ACK ) ) != @@ -585,6 +652,17 @@ static void tcpmux_handler( const struct server *serp ) continue; /* Keep looking */ } + /* Stop processing and shutdown if help was requested + */ + if ( strcasecmp( svc_name, "help" ) == 0 ) + { + Sflush( descriptor ); + Sclose( descriptor ); + exit(0); + } + + /* We were unable to find a matching service + */ if ( u >= pset_count( SERVICES( ps ) ) ) { if ( debug.on ) @@ -617,7 +695,7 @@ static void tcpmux_handler( const struct server *serp ) if( SC_IS_INTERNAL( scp ) ) { SC_INTERNAL(scp, nserp); } else { - exec_server(nserp); + child_process(nserp); } } diff --git a/xinetd/nvlists.c b/xinetd/nvlists.c index 0cb9887..930f7a6 100644 --- a/xinetd/nvlists.c +++ b/xinetd/nvlists.c @@ -48,6 +48,7 @@ const struct name_value service_flags[] = { "IPv4", SF_IPV4 }, { "IPv6", SF_IPV6 }, { "LABELED", SF_LABELED }, + { "PUBLISH", SF_TCPMUXHELP }, { CHAR_NULL, 0 } } ; diff --git a/xinetd/sconf.h b/xinetd/sconf.h index 85ae3ce..28a1415 100644 --- a/xinetd/sconf.h +++ b/xinetd/sconf.h @@ -59,6 +59,7 @@ #define SF_IPV4 10 #define SF_IPV6 11 #define SF_LABELED 12 +#define SF_TCPMUXHELP 13 /* * Values for log options @@ -241,6 +242,7 @@ struct service_config #define SC_IPV4( scp ) M_IS_SET( (scp)->sc_xflags, SF_IPV4 ) #define SC_IPV6( scp ) M_IS_SET( (scp)->sc_xflags, SF_IPV6 ) #define SC_LABELED_NET( scp ) M_IS_SET( (scp)->sc_xflags, SF_LABELED ) +#define SC_MUXHELP( scp ) M_IS_SET( (scp)->sc_xflags, SF_TCPMUXHELP ) #define SC_IS_RPC( scp ) ( M_IS_SET( (scp)->sc_type, ST_RPC ) ) #define SC_IS_INTERNAL( scp ) ( M_IS_SET( (scp)->sc_type, ST_INTERNAL ) ) diff --git a/xinetd/service.h b/xinetd/service.h index 954a9de..6ac1e02 100644 --- a/xinetd/service.h +++ b/xinetd/service.h @@ -87,12 +87,14 @@ struct service #define SVC_IS_SUSPENDED( sp ) ( (sp)->svc_state == SVC_SUSPENDED ) #define SVC_IS_AVAILABLE( sp ) ( SVC_IS_ACTIVE(sp) || SVC_IS_SUSPENDED(sp) ) #define SVC_IS_DISABLED( sp ) ( (sp)->svc_state == SVC_DISABLED ) -#define SVC_IS_MUXCLIENT( sp ) ( SC_IS_MUXCLIENT( SVC_CONF ( sp ) ) ) +#define SVC_IS_MUXCLIENT( sp ) ( SC_IS_MUXCLIENT( SVC_CONF ( sp ) ) || SC_IS_MUXPLUSCLIENT( SVC_CONF ( sp ) ) ) #define SVC_IS_MUXPLUSCLIENT(sp) ( SC_IS_MUXPLUSCLIENT( SVC_CONF ( sp ) ) ) #define SVC_IS_TCPMUX( sp ) ( SC_IS_TCPMUX( SVC_CONF ( sp ) ) ) +#define SVC_MUXHELP(sp) ( SC_MUXHELP( SVC_CONF ( sp ) ) ) #define TCPMUX_ACK "+Go\r\n" #define TCPMUX_NOT_FOUND "-Service name not found\r\n" +#define TCPMUX_CRLF "\r\n" /* * Predicate checking macros */ diff --git a/xinetd/xinetd.conf.man b/xinetd/xinetd.conf.man index 031b559..bd1720d 100644 --- a/xinetd/xinetd.conf.man +++ b/xinetd/xinetd.conf.man @@ -4,7 +4,7 @@ .\"and conditions for redistribution. .\" .\" $Id$ -.TH XINETD.CONF 5 "14 June 2001" +.TH XINETD.CONF 5 "12 September 2013" .\" *************************** NAME ********************************* .SH NAME xinetd.conf \- Extended Internet Services Daemon configuration file @@ -148,6 +148,9 @@ Sets the service to be an IPv6 service (AF_INET6), if IPv6 is available on the s .B LABELED The LABELED flag will tell xinetd to change the child processes SE Linux context to match that of the incoming connection as it starts the service. This only works for external tcp non-waiting servers and is an error if applied to an internal, udp, or tcp-wait server. .TP +.B PUBLISH +The PUBLISH flag will tell xinetd to list the service when the help command is issued to the TCPMUX server. Only TCPMUX services with the PUBLISH flag will be listed when the help command is issued to the internal TCPMUX server. +.TP .B REUSE The REUSE flag is deprecated. All services now implicitly use the REUSE flag. .RE @@ -777,12 +780,14 @@ have no limitation in the number of .\" *********************** TCPMUX Services **************************** .SH "TCPMUX Services" .LP -\fBxinetd\fP supports TCPMUX services that conform to RFC 1078. These services -may not have a well-known port associated with them, and can be accessed via -the TCPMUX well-known port. +\fBxinetd\fP supports TCPMUX services that conform to RFC 1078. These +services may not have a well-known port associated with them, and can +be accessed via the TCPMUX well-known port. \fBxinetd\fP implements +the TCPMUX \fIhelp\fP command which will list only TCPMUX services +which also contain the \fBPUBLISH\fP flag. .LP For each service that is to be accessed via TCPMUX, a service entry in -\fB/etc/xinetd.conf\fP or in a configuration file in an \fBincludedir\fP +\fB/etc/xinetd.conf\fP or in a configuration file in an \fBincludedir\fP directory must exist. .LP The \fIservice_name\fP field (as defined above for each service in any @@ -799,6 +804,11 @@ handshake (as defined in RFC 1078) with the calling process before initiating the service. If the type is \fBTCPMUX\fP, the server that is started is responsible for performing the handshake. .LP +The \fIflag\fP field should also include \fBPUBLISH\fP if the service +is to be listed when the help command is issued the TCPMUX server. +The default is not listing the service name when the help command +is given. +.LP The \fItype\fP field should also include \fBUNLISTED\fP if the service is not listed in a standard system file (like @@ -836,6 +846,34 @@ service myorg_server } .fi .RE +.PD .1v +.RS +.nf + +# this service is listed when help is called via tcpmux +service myorg_server +{ +.RS +.IP disable 20 += no +.IP type += TCPMUX +.IP socket_type +.IP flags += PUBLISH += stream +.IP protocol += tcp +.IP wait += no +.IP user += root +.IP server += /usr/etc/my_server_exec +.RE +} +.fi +.RE .PD .LP Besides a service entry for each service that can be accessed @@ -846,13 +884,13 @@ sample: .RS .nf -service tcpmux +service tcpmux-server { .RS .IP type 20 = INTERNAL .IP id -= tcpmux += tcpmux-server .IP socket_type = stream .IP protocol