fixes init script for non ipv6 enabled systems #472755
[packages/xinetd.git] / xinetd / builtins.c
1 /*
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.
6  */
7
8
9 #include "config.h"
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <errno.h>
15 #include <time.h>
16 #include <syslog.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #ifdef HAVE_NETDB_H
20 #include <netdb.h>
21 #endif
22
23 #include "str.h"
24 #include "pset.h"
25 #include "sio.h"
26 #include "builtins.h"
27 #include "msg.h"
28 #include "connection.h"
29 #include "server.h"
30 #include "service.h"
31 #include "sconf.h"
32 #include "main.h"
33 #include "util.h"
34 #include "xconfig.h"
35 #include "state.h"
36 #include "libportable.h"
37 #include "signals.h"
38 #include "nvlists.h"
39 #include "child.h"
40 #include "access.h"
41
42 #define BUFFER_SIZE               1024
43
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 *) ;
55
56 /*
57  * SG - This is the call sequence to get to a built-in service
58  *
59  *   main_loop                  main.c
60  *    svc_request                  service.c
61  *     svc_handle -- aka svc_handler_func -- aka svc_generic_handler   service.c
62  *      server_run                      server.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
67  */
68
69 static const struct builtin_service builtin_services[] =
70    {
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       } }
85    } ;
86
87
88 const builtin_s *builtin_find( const char *service_name, int type )
89 {
90    const builtin_s   *bsp ;
91    const char        *func = "builtin_find" ;
92    
93    if ( (bsp = builtin_lookup( builtin_services, service_name, type )) )
94       return( bsp ) ;
95    else
96    {
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";
101         else
102                 type_name = sock_type->name;
103         msg( LOG_ERR, func, "No such internal service: %s/%s - DISABLING", 
104                         service_name, type_name ) ;
105         return( NULL ) ;
106    }
107 }
108
109
110 const builtin_s *builtin_lookup( const struct builtin_service services[], 
111                            const char *service_name, 
112                            int type )
113 {
114    const struct builtin_service *bsp ;
115    
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 ) ;
119    return( NULL ) ;
120 }
121
122
123 /*
124  * The rest of this file contains the functions that implement the 
125  * builtin services
126  */
127
128
129 static void stream_echo( const struct server *serp )
130 {
131    char   buf[ BUFFER_SIZE ] ;
132    int    cc ;
133    int    descriptor = SERVER_FD( serp ) ;
134    struct service *svc = SERVER_SERVICE( serp ) ;;
135
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");
141          return;
142       }
143    }
144
145    close_all_svc_descriptors();
146
147    for ( ;; )
148    {
149       cc = read( descriptor, buf, sizeof( buf ) ) ;
150       if ( cc == 0 )
151          break ;
152       if ( cc == -1 ) {
153          if ( errno == EINTR )
154             continue ;
155          else
156             break ;
157       }
158
159       if ( write_buf( descriptor, buf, cc ) == FAILED )
160          break ;
161    }
162    if( SVC_WAITS( svc ) ) /* Service forks, so close it */
163       Sclose(descriptor);
164 }
165
166 static void dgram_echo( const struct server *serp )
167 {
168    char            buf[ DATAGRAM_SIZE ] ;
169    union xsockaddr lsin;
170    int             cc ;
171    socklen_t       sin_len = 0;
172    int             descriptor = SERVER_FD( serp ) ;
173    const char     *func = "dgram_echo";
174
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 );
179
180    cc = recvfrom( descriptor, buf, sizeof( buf ), 0, SA( &lsin ), &sin_len ) ;
181    if ( cc != -1 ) {
182       (void) sendto( descriptor, buf, cc, 0, SA( &lsin ), sizeof( lsin ) ) ;
183    }
184 }
185
186 static void stream_discard( const struct server *serp )
187 {
188    char  buf[ BUFFER_SIZE ] ;
189    int   cc ;
190    int    descriptor = SERVER_FD( serp ) ;
191    struct service *svc = SERVER_SERVICE( serp ) ;;
192
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");
198          return;
199       }
200    }
201
202    close_all_svc_descriptors();
203
204    for ( ;; )
205    {
206       cc = read( descriptor, buf, sizeof( buf ) ) ;
207       if ( (cc == 0) || ((cc == -1) && (errno != EINTR)) )
208          break ;
209    }
210    if( SVC_WAITS( svc ) ) /* Service forks, so close it */
211       Sclose(descriptor);
212 }
213
214
215 static void dgram_discard( const struct server *serp )
216 {
217    char buf[ 1 ] ;
218
219    (void) recv( SERVER_FD( serp ), buf, sizeof( buf ), 0 ) ;
220 }
221
222
223 /*
224  * Generate the current time using the SMTP format:
225  *      02 FEB 1991 12:31:42 MST
226  *
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.
230  */
231 static void daytime_protocol( char *buf, unsigned int *buflen )
232 {
233    static const char *month_name[] =
234       {
235          "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
236          "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
237       } ;
238    time_t      now ;
239    struct tm   *tmp ;
240    int         size = *buflen ;
241 #ifdef HAVE_STRFTIME
242    int      cc ;
243 #endif
244
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 ) ;
252 #else
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 ) ;
257    if ( cc >= 0 ) { 
258       *buflen = cc ;
259       size -= cc ;
260       cc = strftime( &buf[ *buflen ], size, " %Z\r\n", tmp ) ;
261       *buflen += cc ;
262    }
263 #endif
264 }
265
266
267 static void stream_daytime( const struct server *serp )
268 {
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 ) ;;
273
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");
279          return;
280       }
281    }
282    daytime_protocol( time_buf, &buflen ) ;
283    (void) write_buf( descriptor, time_buf, buflen ) ;
284    Sclose(descriptor);
285 }
286
287
288 static void dgram_daytime( const struct server *serp )
289 {
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";
296
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 );
301
302    if ( recvfrom( descriptor, time_buf, sizeof( time_buf ), 0,
303             SA( &lsin ), &sin_len ) == -1 )
304       return ;
305
306    daytime_protocol( time_buf, &buflen ) ;
307    
308    (void) sendto( descriptor, time_buf, buflen, 0, SA(&lsin), sizeof( lsin ) ) ;
309 }
310
311
312 #define TIME_OFFSET         2208988800UL
313
314 /*
315  * We always report the time as 32 bits in network-byte-order
316  */
317 static void time_protocol( unsigned char *timep )
318 {
319    time_t now ;
320    unsigned long base1900;
321
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;
327    timep[3] = base1900;
328
329 }
330
331
332 static void stream_time( const struct server *serp )
333 {
334    unsigned char time_buf[4];
335    int descriptor = SERVER_FD( serp );
336    struct service *svc = SERVER_SERVICE( serp );
337
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");
343          return;
344       }
345    }
346
347    time_protocol( time_buf ) ;
348    (void) write_buf( descriptor, (char *) time_buf, 4 ) ;
349
350    Sclose(descriptor);
351 }
352
353
354 static void dgram_time( const struct server *serp )
355 {
356    char     buf[ 1 ] ;
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";
362
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 );
367
368    if ( recvfrom( fd, buf, sizeof( buf ), 0, SA( &lsin ), &sin_len ) == -1 )
369       return ;
370
371    time_protocol( time_buf ) ;
372    (void) sendto( fd, (char *) time_buf, 4, 0, SA( &lsin ), sin_len ) ;
373 }
374
375
376 #define ASCII_PRINTABLE_CHARS     94
377 #define LINE_LENGTH               72
378
379 #define RING_BUF_SIZE             ASCII_PRINTABLE_CHARS + LINE_LENGTH
380
381 static char *ring_buf = NULL ;
382 static char *ring ;
383
384
385 #define ASCII_START          ( ' ' + 1 )
386 #define ASCII_END            126
387
388 #define min( a, b )          ((a)<(b) ? (a) : (b))
389
390 static char *generate_line( char *buf, unsigned int len )
391 {
392    unsigned int line_len = min( LINE_LENGTH, len-2 ) ;
393
394    if ( len < 2 )       /* If len < 2, min will be wrong */
395       return( NULL ) ;
396
397    /* This never gets freed.  That's ok, because the reference to it is
398     * always kept for future reference.
399     */
400    if ( (ring_buf == NULL) && ((ring_buf = malloc(RING_BUF_SIZE)) == NULL) ) 
401       return(NULL);
402
403    if ( ring == NULL )
404    {
405       char ch ;
406       char *p ;
407
408       for ( p = ring_buf, ch = ASCII_START ;
409             p <= &ring_buf[ RING_BUF_SIZE - 1 ] ; p++ )
410       {
411          *p = ch++ ;
412          if ( ch == ASCII_END )
413             ch = ASCII_START ;
414       }
415       ring = ring_buf ;
416    }
417    (void) memcpy( buf, ring, line_len ) ;
418    buf[ line_len   ] = '\r' ;
419    buf[ line_len+1 ] = '\n' ;
420
421    ring++ ;
422    if ( &ring_buf[ RING_BUF_SIZE - 1 ] - ring + 1 < LINE_LENGTH )
423       ring = ring_buf ;
424    return( buf ) ;
425 }
426
427
428 static void stream_chargen( const struct server *serp )
429 {
430    char   line_buf[ LINE_LENGTH+2 ] ;
431    int    descriptor = SERVER_FD( serp ) ;
432    struct service *svc = SERVER_SERVICE( serp );
433
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");
439          return;
440       }
441    }
442
443    (void) shutdown( descriptor, 0 ) ;
444    close_all_svc_descriptors();
445
446    for ( ;; )
447    {
448       if ( generate_line( line_buf, sizeof( line_buf ) ) == NULL )
449          break ;
450       if ( write_buf( descriptor, line_buf, sizeof( line_buf ) ) == FAILED )
451          break ;
452    }
453    if( SVC_WAITS( svc ) ) /* Service forks, so close it */
454       Sclose(descriptor);
455 }
456
457
458 static void dgram_chargen( const struct server *serp )
459 {
460    char            buf[ BUFFER_SIZE ] ;
461    char            *p ;
462    unsigned int    len ;
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";
468
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 );
473
474    if ( recvfrom( fd, buf, sizeof( buf ), 0, SA( &lsin ), &sin_len ) == -1 )
475       return ;
476
477 #if BUFFER_SIZE < LINE_LENGTH+2
478    bad_variable = 1 ;      /* this will cause a compilation error */
479 #endif
480
481    for ( p = buf ; left > 2 ; left -= len, p += len )
482    {
483       len = min( LINE_LENGTH+2, left ) ;
484       if ( generate_line( p, len ) == NULL )
485          break ;
486    }
487    (void) sendto( fd, buf, p-buf, 0, SA( &lsin ), sin_len ) ;
488 }
489
490
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.
497  */
498
499 static void tcpmux_handler( const struct server *serp )
500 {
501    char      svc_name[ BUFFER_SIZE ] ;
502    int       cc ;
503    int       descriptor = SERVER_FD( serp ) ;
504    const     struct service *svc = SERVER_SERVICE( serp ) ;
505    unsigned  u;
506    struct    service *sp = NULL;
507    struct    server server, *nserp;
508    struct    service_config *scp = NULL;
509
510    close_all_svc_descriptors();
511
512    /*  Read in the name of the service in the format "svc_name\r\n".
513     *
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).
516     */
517    do
518    {
519       cc = read( descriptor, svc_name, sizeof( svc_name ) ) ;
520    } while (cc == -1 && errno == EINTR);
521
522    if ( cc <= 0 )
523    {
524       msg(LOG_ERR, "tcpmux_handler", "read failed");
525       exit(0);
526    }
527
528    if ( ( cc <= 2 ) ||
529         ( ( svc_name[cc - 1] != '\n' ) || ( svc_name[cc - 2] != '\r' ) ) )
530    {
531       if ( debug.on )
532          msg(LOG_DEBUG, "tcpmux_handler", "Invalid service name format.");
533       
534       exit(0);
535    }
536
537    svc_name[cc - 2] = '\0';  /*  Remove \r\n for compare */
538
539    if ( debug.on )
540    {
541       msg(LOG_DEBUG, "tcpmux_handler", "Input (%d bytes) %s as service name.",
542           cc, svc_name);
543    }
544
545    /*  Search the services for the a match on name.
546     */
547
548    for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ )
549    {
550       sp = SP( pset_pointer( SERVICES( ps ), u ) ) ;
551
552       if ( strcasecmp( svc_name, SC_NAME( SVC_CONF( sp ) ) ) == 0 )
553       {
554          /*  Found the pointer. Validate its type.
555           */
556          scp = SVC_CONF( sp );
557 /*
558          if ( ! SVC_IS_MUXCLIENT( sp ) )
559          {
560             if ( debug.on )
561             {
562                msg(LOG_DEBUG, "tcpmux_handler", "Non-tcpmux service name: %s.",
563                    svc_name);
564             }
565             exit(0);
566          }
567 */
568
569          /*  Send the accept string if we're a PLUS (+) client.
570           */
571
572          if ( SVC_IS_MUXPLUSCLIENT( sp ) )
573          {
574             if ( Swrite( descriptor, TCPMUX_ACK, sizeof( TCPMUX_ACK ) ) !=
575                  sizeof( TCPMUX_ACK ) )
576             {
577                 msg(LOG_ERR, "tcpmux_handler", "Ack write failed for %s.",
578                     svc_name);
579                 exit(0);
580             }
581          }
582          break;  /*  Time to get on with the service */
583       }
584       continue;  /*  Keep looking */
585    }
586
587    if ( u >= pset_count( SERVICES( ps ) ) )
588    {
589       if ( debug.on )
590       {
591          msg(LOG_DEBUG, "tcpmux_handler", "Service name %s not found.",
592              svc_name);
593       }
594       exit(0);
595    }
596
597    if( SVC_WAITS( svc ) ) /* Service forks, so close it */
598       Sclose(descriptor);
599
600    server.svr_sp = sp;
601    server.svr_conn = SERVER_CONNECTION(serp);
602    nserp = server_alloc(&server);
603    if( SC_IS_INTERNAL( scp ) ) {
604       SC_INTERNAL(scp, nserp);
605    } else {
606       exec_server(nserp);
607    }
608 }
609