2 * (c) Copyright 1992 by Panagiotis Tsirigotis
3 * (c) Sections Copyright 1998-2001 by Rob Braun
4 * All rights reserved. The file named COPYRIGHT specifies the terms
5 * and conditions for redistribution.
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
28 #include "connection.h"
36 #include "libportable.h"
42 #define BUFFER_SIZE 1024
44 static void stream_echo(const struct server *) ;
45 static void dgram_echo(const struct server *) ;
46 static void stream_discard(const struct server *) ;
47 static void dgram_discard(const struct server *) ;
48 static void stream_time(const struct server *) ;
49 static void dgram_time(const struct server *) ;
50 static void stream_daytime(const struct server *) ;
51 static void dgram_daytime(const struct server *) ;
52 static void stream_chargen(const struct server *) ;
53 static void dgram_chargen(const struct server *) ;
54 static void tcpmux_handler(const struct server *) ;
57 * SG - This is the call sequence to get to a built-in service
60 * svc_request service.c
61 * svc_handle -- aka svc_handler_func -- aka svc_generic_handler service.c
63 * server_internal server.c
64 * SC_INTERNAL service.h
65 * BUILTIN_INVOKE sc_conf.h
66 * sc_builtin -- index into builtin_services builtins.c
69 static const struct builtin_service builtin_services[] =
71 { "echo", SOCK_STREAM, { stream_echo, FORK } },
72 { "echo", SOCK_DGRAM, { dgram_echo, NO_FORK } },
73 { "discard", SOCK_STREAM, { stream_discard, FORK } },
74 { "discard", SOCK_DGRAM, { dgram_discard, NO_FORK } },
75 { "time", SOCK_STREAM, { stream_time, NO_FORK } },
76 { "time", SOCK_DGRAM, { dgram_time, NO_FORK } },
77 { "daytime", SOCK_STREAM, { stream_daytime, NO_FORK } },
78 { "daytime", SOCK_DGRAM, { dgram_daytime, NO_FORK } },
79 { "chargen", SOCK_STREAM, { stream_chargen, FORK } },
80 { "chargen", SOCK_DGRAM, { dgram_chargen, NO_FORK } },
81 { "sensor", SOCK_STREAM, { stream_discard, NO_FORK } },
82 { "sensor", SOCK_DGRAM, { dgram_discard, NO_FORK } },
83 { "tcpmux", SOCK_STREAM, { tcpmux_handler, FORK } },
84 { NULL, 0, { NULL, 0 } }
88 const builtin_s *builtin_find( const char *service_name, int type )
90 const builtin_s *bsp ;
91 const char *func = "builtin_find" ;
93 if ( (bsp = builtin_lookup( builtin_services, service_name, type )) )
97 const char *type_name;
98 const struct name_value *sock_type = nv_find_name( socket_types, type );
99 if (sock_type == NULL)
100 type_name = "Unknown socket type";
102 type_name = sock_type->name;
103 msg( LOG_ERR, func, "No such internal service: %s/%s - DISABLING",
104 service_name, type_name ) ;
110 const builtin_s *builtin_lookup( const struct builtin_service services[],
111 const char *service_name,
114 const struct builtin_service *bsp ;
116 for ( bsp = services ; bsp->bs_name != NULL ; bsp++ )
117 if ( EQ( bsp->bs_name, service_name ) && bsp->bs_socket_type == type )
118 return( &bsp->bs_handle ) ;
124 * The rest of this file contains the functions that implement the
129 static void stream_echo( const struct server *serp )
131 char buf[ BUFFER_SIZE ] ;
133 int descriptor = SERVER_FD( serp ) ;
134 struct service *svc = SERVER_SERVICE( serp ) ;;
136 if( SVC_WAITS( svc ) ) {
137 descriptor = accept(descriptor, NULL, NULL);
138 if ( descriptor == -1 ) {
139 if ((errno == EMFILE) || (errno == ENFILE))
140 cps_service_stop(svc, "no available descriptors");
145 close_all_svc_descriptors();
149 cc = read( descriptor, buf, sizeof( buf ) ) ;
153 if ( errno == EINTR )
159 if ( write_buf( descriptor, buf, cc ) == FAILED )
162 if( SVC_WAITS( svc ) ) /* Service forks, so close it */
166 static void dgram_echo( const struct server *serp )
168 char buf[ DATAGRAM_SIZE ] ;
169 union xsockaddr lsin;
171 socklen_t sin_len = 0;
172 int descriptor = SERVER_FD( serp ) ;
173 const char *func = "dgram_echo";
175 if( SC_IPV4( SVC_CONF( SERVER_SERVICE( serp ) ) ) )
176 sin_len = sizeof( struct sockaddr_in );
177 else if( SC_IPV6( SVC_CONF( SERVER_SERVICE( serp ) ) ) )
178 sin_len = sizeof( struct sockaddr_in6 );
180 cc = recvfrom( descriptor, buf, sizeof( buf ), 0, SA( &lsin ), &sin_len ) ;
182 (void) sendto( descriptor, buf, cc, 0, SA( &lsin ), sizeof( lsin ) ) ;
186 static void stream_discard( const struct server *serp )
188 char buf[ BUFFER_SIZE ] ;
190 int descriptor = SERVER_FD( serp ) ;
191 struct service *svc = SERVER_SERVICE( serp ) ;;
193 if( SVC_WAITS( svc ) ) {
194 descriptor = accept(descriptor, NULL, NULL);
195 if ( descriptor == -1 ) {
196 if ((errno == EMFILE) || (errno == ENFILE))
197 cps_service_stop(svc, "no available descriptors");
202 close_all_svc_descriptors();
206 cc = read( descriptor, buf, sizeof( buf ) ) ;
207 if ( (cc == 0) || ((cc == -1) && (errno != EINTR)) )
210 if( SVC_WAITS( svc ) ) /* Service forks, so close it */
215 static void dgram_discard( const struct server *serp )
219 (void) recv( SERVER_FD( serp ), buf, sizeof( buf ), 0 ) ;
224 * Generate the current time using the SMTP format:
225 * 02 FEB 1991 12:31:42 MST
227 * The result is placed in buf.
228 * buflen is a value-result parameter. It indicates the size of
229 * buf and on exit it has the length of the string placed in buf.
231 static void daytime_protocol( char *buf, unsigned int *buflen )
233 static const char *month_name[] =
235 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
236 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
245 (void) time( &now ) ;
246 tmp = localtime( &now ) ;
247 #ifndef HAVE_STRFTIME
248 strx_print( buflen, buf, size,
249 "%02d %s %d %02d:%02d:%02d %s\r\n",
250 tmp->tm_mday, month_name[ tmp->tm_mon ], 1900 + tmp->tm_year,
251 tmp->tm_hour, tmp->tm_min, tmp->tm_sec, tmp->tm_zone ) ;
253 cc = strx_nprint( buf, size,
254 "%02d %s %d %02d:%02d:%02d",
255 tmp->tm_mday, month_name[ tmp->tm_mon ], 1900 + tmp->tm_year,
256 tmp->tm_hour, tmp->tm_min, tmp->tm_sec ) ;
260 cc = strftime( &buf[ *buflen ], size, " %Z\r\n", tmp ) ;
267 static void stream_daytime( const struct server *serp )
269 char time_buf[ BUFFER_SIZE ] ;
270 unsigned int buflen = sizeof( time_buf ) ;
271 int descriptor = SERVER_FD( serp ) ;
272 struct service *svc = SERVER_SERVICE( serp ) ;;
274 if( SVC_WAITS( svc ) ) {
275 descriptor = accept(descriptor, NULL, NULL);
276 if ( descriptor == -1 ) {
277 if ((errno == EMFILE) || (errno == ENFILE))
278 cps_service_stop(svc, "no available descriptors");
282 daytime_protocol( time_buf, &buflen ) ;
283 (void) write_buf( descriptor, time_buf, buflen ) ;
288 static void dgram_daytime( const struct server *serp )
290 char time_buf[ BUFFER_SIZE ] ;
291 union xsockaddr lsin ;
292 socklen_t sin_len = 0 ;
293 unsigned int buflen = sizeof( time_buf ) ;
294 int descriptor = SERVER_FD( serp ) ;
295 const char *func = "dgram_daytime";
297 if ( SC_IPV4( SVC_CONF( SERVER_SERVICE( serp ) ) ) )
298 sin_len = sizeof( struct sockaddr_in );
299 else if ( SC_IPV6( SVC_CONF( SERVER_SERVICE( serp ) ) ) )
300 sin_len = sizeof( struct sockaddr_in6 );
302 if ( recvfrom( descriptor, time_buf, sizeof( time_buf ), 0,
303 SA( &lsin ), &sin_len ) == -1 )
306 daytime_protocol( time_buf, &buflen ) ;
308 (void) sendto( descriptor, time_buf, buflen, 0, SA(&lsin), sizeof( lsin ) ) ;
312 #define TIME_OFFSET 2208988800UL
315 * We always report the time as 32 bits in network-byte-order
317 static void time_protocol( unsigned char *timep )
320 unsigned long base1900;
322 (void) time( &now ) ;
323 base1900 = (unsigned long)now + TIME_OFFSET ;
324 timep[0] = base1900 >> 24;
325 timep[1] = base1900 >> 16;
326 timep[2] = base1900 >> 8;
332 static void stream_time( const struct server *serp )
334 unsigned char time_buf[4];
335 int descriptor = SERVER_FD( serp );
336 struct service *svc = SERVER_SERVICE( serp );
338 if( SVC_WAITS( svc ) ) {
339 descriptor = accept(descriptor, NULL, NULL);
340 if ( descriptor == -1 ) {
341 if ((errno == EMFILE) || (errno == ENFILE))
342 cps_service_stop(svc, "no available descriptors");
347 time_protocol( time_buf ) ;
348 (void) write_buf( descriptor, (char *) time_buf, 4 ) ;
354 static void dgram_time( const struct server *serp )
357 unsigned char time_buf[4];
358 union xsockaddr lsin ;
359 socklen_t sin_len = 0 ;
360 int fd = SERVER_FD( serp ) ;
361 const char *func = "dgram_daytime";
363 if ( SC_IPV4( SVC_CONF( SERVER_SERVICE( serp ) ) ) )
364 sin_len = sizeof( struct sockaddr_in );
365 else if ( SC_IPV6( SVC_CONF( SERVER_SERVICE( serp ) ) ) )
366 sin_len = sizeof( struct sockaddr_in6 );
368 if ( recvfrom( fd, buf, sizeof( buf ), 0, SA( &lsin ), &sin_len ) == -1 )
371 time_protocol( time_buf ) ;
372 (void) sendto( fd, (char *) time_buf, 4, 0, SA( &lsin ), sin_len ) ;
376 #define ASCII_PRINTABLE_CHARS 94
377 #define LINE_LENGTH 72
379 #define RING_BUF_SIZE ASCII_PRINTABLE_CHARS + LINE_LENGTH
381 static char *ring_buf = NULL ;
385 #define ASCII_START ( ' ' + 1 )
386 #define ASCII_END 126
388 #define min( a, b ) ((a)<(b) ? (a) : (b))
390 static char *generate_line( char *buf, unsigned int len )
392 unsigned int line_len = min( LINE_LENGTH, len-2 ) ;
394 if ( len < 2 ) /* If len < 2, min will be wrong */
397 /* This never gets freed. That's ok, because the reference to it is
398 * always kept for future reference.
400 if ( (ring_buf == NULL) && ((ring_buf = malloc(RING_BUF_SIZE)) == NULL) )
408 for ( p = ring_buf, ch = ASCII_START ;
409 p <= &ring_buf[ RING_BUF_SIZE - 1 ] ; p++ )
412 if ( ch == ASCII_END )
417 (void) memcpy( buf, ring, line_len ) ;
418 buf[ line_len ] = '\r' ;
419 buf[ line_len+1 ] = '\n' ;
422 if ( &ring_buf[ RING_BUF_SIZE - 1 ] - ring + 1 < LINE_LENGTH )
428 static void stream_chargen( const struct server *serp )
430 char line_buf[ LINE_LENGTH+2 ] ;
431 int descriptor = SERVER_FD( serp ) ;
432 struct service *svc = SERVER_SERVICE( serp );
434 if( SVC_WAITS( svc ) ) {
435 descriptor = accept(descriptor, NULL, NULL);
436 if ( descriptor == -1 ) {
437 if ((errno == EMFILE) || (errno == ENFILE))
438 cps_service_stop(svc, "no available descriptors");
443 (void) shutdown( descriptor, 0 ) ;
444 close_all_svc_descriptors();
448 if ( generate_line( line_buf, sizeof( line_buf ) ) == NULL )
450 if ( write_buf( descriptor, line_buf, sizeof( line_buf ) ) == FAILED )
453 if( SVC_WAITS( svc ) ) /* Service forks, so close it */
458 static void dgram_chargen( const struct server *serp )
460 char buf[ BUFFER_SIZE ] ;
463 union xsockaddr lsin ;
464 socklen_t sin_len = 0 ;
465 int fd = SERVER_FD( serp ) ;
466 unsigned int left = sizeof( buf ) ;
467 const char *func = "dgram_chargen";
469 if ( SC_IPV4( SVC_CONF( SERVER_SERVICE( serp ) ) ) )
470 sin_len = sizeof( struct sockaddr_in );
471 else if ( SC_IPV6( SVC_CONF( SERVER_SERVICE( serp ) ) ) )
472 sin_len = sizeof( struct sockaddr_in6 );
474 if ( recvfrom( fd, buf, sizeof( buf ), 0, SA( &lsin ), &sin_len ) == -1 )
477 #if BUFFER_SIZE < LINE_LENGTH+2
478 bad_variable = 1 ; /* this will cause a compilation error */
481 for ( p = buf ; left > 2 ; left -= len, p += len )
483 len = min( LINE_LENGTH+2, left ) ;
484 if ( generate_line( p, len ) == NULL )
487 (void) sendto( fd, buf, p-buf, 0, SA( &lsin ), sin_len ) ;
491 /* Handle a request for a tcpmux service.
492 * It's helpful to remember here that we are now a child of the original
493 * xinetd process. We were forked to keep the parent from blocking
494 * when we try to read the service name off'n the socket connection.
495 * Serp still points to an actual tcpmux 'server', or at least the
496 * service pointer of serp is valid.
499 static void tcpmux_handler( const struct server *serp )
501 char svc_name[ BUFFER_SIZE ] ;
503 int descriptor = SERVER_FD( serp ) ;
504 const struct service *svc = SERVER_SERVICE( serp ) ;
506 struct service *sp = NULL;
507 struct server server, *nserp;
508 struct service_config *scp = NULL;
510 close_all_svc_descriptors();
512 /* Read in the name of the service in the format "svc_name\r\n".
514 * XXX: should loop on partial reads (could probably use Sread() if
515 * it wasn't thrown out of xinetd source code a few revisions back).
519 cc = read( descriptor, svc_name, sizeof( svc_name ) ) ;
520 } while (cc == -1 && errno == EINTR);
524 msg(LOG_ERR, "tcpmux_handler", "read failed");
529 ( ( svc_name[cc - 1] != '\n' ) || ( svc_name[cc - 2] != '\r' ) ) )
532 msg(LOG_DEBUG, "tcpmux_handler", "Invalid service name format.");
537 svc_name[cc - 2] = '\0'; /* Remove \r\n for compare */
541 msg(LOG_DEBUG, "tcpmux_handler", "Input (%d bytes) %s as service name.",
545 /* Search the services for the a match on name.
548 for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
550 sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
552 if ( strcasecmp( svc_name, SC_NAME( SVC_CONF( sp ) ) ) == 0 )
554 /* Found the pointer. Validate its type.
556 scp = SVC_CONF( sp );
558 if ( ! SVC_IS_MUXCLIENT( sp ) )
562 msg(LOG_DEBUG, "tcpmux_handler", "Non-tcpmux service name: %s.",
569 /* Send the accept string if we're a PLUS (+) client.
572 if ( SVC_IS_MUXPLUSCLIENT( sp ) )
574 if ( Swrite( descriptor, TCPMUX_ACK, sizeof( TCPMUX_ACK ) ) !=
575 sizeof( TCPMUX_ACK ) )
577 msg(LOG_ERR, "tcpmux_handler", "Ack write failed for %s.",
582 break; /* Time to get on with the service */
584 continue; /* Keep looking */
587 if ( u >= pset_count( SERVICES( ps ) ) )
591 msg(LOG_DEBUG, "tcpmux_handler", "Service name %s not found.",
597 if( SVC_WAITS( svc ) ) /* Service forks, so close it */
601 server.svr_conn = SERVER_CONNECTION(serp);
602 nserp = server_alloc(&server);
603 if( SC_IS_INTERNAL( scp ) ) {
604 SC_INTERNAL(scp, nserp);