fixes init script for non ipv6 enabled systems #472755
[packages/xinetd.git] / xinetd / inet.c
1 /*
2  * (c) Copyright 1998-2001 by Rob Braun
3  * All rights reserved.  The file named COPYRIGHT specifies the terms
4  * and conditions for redistribution.
5  */
6 #include "config.h"
7 #include <sys/types.h>
8 #include <netdb.h>
9 #include <string.h>
10 #include <syslog.h>
11 #include <memory.h>
12 #include <fcntl.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <grp.h>
16 #include <pwd.h>
17 #include <limits.h>
18
19 #include "str.h"
20 #include "inet.h"
21 #include "msg.h"
22 #include "parse.h"
23 #include "parsesup.h"
24 #include "nvlists.h"
25
26 static int get_next_inet_entry( int fd, pset_h sconfs, 
27                           struct service_config *defaults);
28
29 void parse_inet_conf_file( int fd, struct configuration *confp )
30 {
31    pset_h sconfs                         = CNF_SERVICE_CONFS( confp );
32    struct service_config *default_config = CNF_DEFAULTS( confp );
33    
34    line_count = 0;
35
36    for( ;; )
37    {   
38       if (get_next_inet_entry(fd, sconfs, default_config) == -2)
39          break;
40    }
41 }
42
43 static int get_next_inet_entry( int fd, pset_h sconfs, 
44                           struct service_config *defaults)
45 {
46    char *p;
47    str_h strp;
48    char *line = next_line(fd);
49    struct service_config *scp;
50    unsigned u, i;
51    const char *func = "get_next_inet_entry";
52    char *name = NULL, *rpcvers = NULL, *rpcproto = NULL;
53    char *group, *proto, *stype;
54    const struct name_value *nvp;
55    struct protoent *pep ;
56    struct passwd *pw ;
57    struct group *grp ;
58    const char *dot = ".";
59    const char *slash = "/";
60    pset_h args;
61    
62    if( line == CHAR_NULL )
63       return -2;
64
65    strp = str_parse( line, " \t", STR_RETURN_ERROR, INT_NULL ) ;
66    if( strp == NULL )
67    {
68       parsemsg( LOG_CRIT, func, "inetd.conf - str_parse failed" ) ;
69       return( -1 ) ;
70    }
71
72    if( (args = pset_create(10,10)) == NULL )
73    {
74       out_of_memory(func);
75       return -1;
76    }
77
78    /* Break the line into components, based on spaces */
79    while( (p = str_component( strp )) )
80    {
81       if( pset_add(args, p) == NULL )
82       {
83          parsemsg( LOG_CRIT, func, ES_NOMEM );
84          pset_destroy(args);
85          return -1;
86       }
87    }
88    str_endparse( strp );
89
90    /* get the service name */
91    name = new_string((char *)pset_pointer( args, 0 ));
92    if( name == NULL ) {
93       parsemsg( LOG_ERR, func, "inetd.conf - Invalid service name" );
94       pset_destroy(args);
95       return -1;
96    }
97
98    /* Check to find the '/' for specifying RPC version numbers */
99    if( (rpcvers = strstr(name, slash)) != NULL ) {
100       *rpcvers = '\0';
101       rpcvers++;
102    }
103
104    scp = sc_alloc( name );
105    if( scp == NULL )
106    {
107       pset_destroy(args);
108       free( name );
109       return -1;
110    }
111    /*
112     * sc_alloc makes its own copy of name. At this point, sc_alloc worked
113     * so we will free our copy to avoid leaks.
114     */
115    free( name );
116
117    /* Replicate inetd behavior in this regard.  Also makes sure the
118     * service actually works on system where setgroups(0,NULL) doesn't
119     * work.
120     */
121    SC_GROUPS(scp) = YES;
122    SC_SPECIFY( scp, A_GROUPS );
123
124    /* Get the socket type (stream dgram) */
125    stype = (char *)pset_pointer(args, 1);
126    if( stype == NULL ) {
127       parsemsg( LOG_ERR, func, "inetd.conf - Invalid socket type" );
128       pset_destroy(args);
129       sc_free(scp);
130       return -1;
131    }
132    nvp = nv_find_value( socket_types, stype );
133    if( nvp == NULL )
134    {
135       parsemsg( LOG_ERR, func, "inetd.conf - Bad socket type: %s", p);
136       pset_destroy(args);
137       sc_free(scp);
138       return -1;
139    }
140
141    SC_SOCKET_TYPE(scp) = nvp->value;
142
143    /* Get the protocol type */
144    proto = (char *)pset_pointer(args,2);
145    if( strstr(proto, "rpc") != NULL )
146    {
147       int rpcmin, rpcmax;
148       struct rpc_data *rdp = SC_RPCDATA( scp ) ;
149
150       if( rpcvers == NULL ) {
151          pset_destroy(args);
152          sc_free(scp);
153          return -1;
154          /* uh oh */
155       }
156
157       p = strchr(rpcvers, '-');
158       if( p && parse_int(rpcvers, 10, '-', &rpcmin) == 0 ) {
159          if( parse_base10(p + 1, &rpcmax) || rpcmin > rpcmax ) {
160             pset_destroy(args);
161             sc_free(scp);
162             return -1;
163          }
164       } else {
165          if( parse_base10(rpcvers, &rpcmin) ) {
166             pset_destroy(args);
167             sc_free(scp);
168             return -1;
169          }
170
171          rpcmax = rpcmin;
172       }
173
174       /* now have min and max rpc versions */
175       rdp->rd_min_version = rpcmin;      
176       rdp->rd_max_version = rpcmax;      
177
178       rpcproto = strstr(proto, slash);
179       if( rpcproto == NULL ) {
180          parsemsg( LOG_ERR, func, "inetd.conf - bad rpc version numbers" );
181          pset_destroy(args);
182          sc_free(scp);
183          return -1;
184       }
185       *rpcproto = '\0';
186       rpcproto++;
187       proto = rpcproto;
188
189       /* Set the RPC type field */
190       nvp = nv_find_value( service_types, "RPC" );
191       if ( nvp == NULL )
192       {
193          parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ;
194          pset_destroy(args);
195          sc_free(scp);
196          return -1;
197       }
198
199       M_SET(SC_TYPE(scp), nvp->value);
200    }
201    if ( ( pep = getprotobyname( proto ) ) == NULL )
202    {
203       parsemsg( LOG_ERR, func, "inetd.conf - Protocol %s not in /etc/protocols",
204                 proto ) ;
205       pset_destroy(args);
206       sc_free(scp);
207       return -1;
208    }
209
210    SC_PROTONAME(scp) = new_string( proto ) ;
211    if ( SC_PROTONAME(scp) == NULL )
212    {
213       out_of_memory( func ) ;
214       pset_destroy(args);
215       sc_free(scp);
216       return -1;
217    }
218    SC_PROTOVAL(scp) = pep->p_proto;
219    SC_SPECIFY(scp, A_PROTOCOL);
220
221    /* Get the wait attribute */
222    p = (char *)pset_pointer(args, 3);
223    if ( p == NULL ) {
224       parsemsg( LOG_ERR, func, "inetd.conf - No value specified for wait" );
225       sc_free(scp);
226       return -1;
227    }
228    if ( EQ( p, "wait" ) )
229       SC_WAIT(scp) = YES ;
230    else if ( EQ( p, "nowait" ) )
231       SC_WAIT(scp) = NO ;
232    else
233       parsemsg( LOG_ERR, func, "inetd.conf - Bad value for wait: %s", p ) ;
234
235    /* Get the user to run as */
236    p = (char *)pset_pointer(args, 4);
237    if ( p == NULL ) {
238       parsemsg( LOG_ERR, func, "inetd.conf - No value specified for user" );
239       sc_free(scp);
240       return -1;
241    }
242    if( (group = strstr(p, dot)) )
243    {
244       *group = '\0';
245       group++;
246    
247       grp = (struct group *)getgrnam( (char *)group ) ;
248       if ( grp == NULL )
249       {
250          parsemsg( LOG_ERR, func, "inetd.conf - Unknown group: %s", group ) ;
251          pset_destroy(args);
252          sc_free(scp);
253          return -1;
254       }   
255
256       SC_GID(scp) = ((struct group *)grp)->gr_gid;
257       SC_SPECIFY( scp, A_GROUP );
258    }
259
260    pw = getpwnam( p );
261    if ( pw == NULL )
262    {
263       parsemsg( LOG_ERR, func, "inetd.conf - Unknown user: %s", p ) ;
264       pset_destroy(args);
265       sc_free(scp);
266       return -1;
267    }
268    str_fill( pw->pw_passwd, ' ' );
269    SC_UID(scp) = pw->pw_uid;
270    SC_USER_GID(scp) = pw->pw_gid;
271
272    /* Get server name, or flag as internal */
273    p = (char *)pset_pointer(args, 5);
274    if ( p == NULL ) {
275       parsemsg( LOG_ERR, func, "inetd.conf - No value specified for user" );
276       sc_free(scp);
277       return -1;
278    }
279    if( EQ( p, "internal" ) ) 
280    {
281       nvp = nv_find_value( service_types, "INTERNAL" );
282       if ( nvp == NULL )
283       {
284          parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ;
285          pset_destroy(args);
286          sc_free(scp);
287          return -1;
288       }
289
290       M_SET(SC_TYPE(scp), nvp->value);
291
292       if( EQ( SC_NAME(scp), "time" ) ) {
293          if( EQ( proto, "stream" ) )
294             SC_ID(scp) = new_string("time-stream");
295          else
296             SC_ID(scp) = new_string("time-dgram");
297       }
298
299       if( EQ( SC_NAME(scp), "daytime" ) ) {
300          if( EQ( proto, "stream" ) )
301             SC_ID(scp) = new_string("daytime-stream");
302          else
303             SC_ID(scp) = new_string("daytime-dgram");
304       }
305
306       if( EQ( SC_NAME(scp), "chargen" ) ) {
307          if( EQ( proto, "stream" ) )
308             SC_ID(scp) = new_string("chargen-stream");
309          else
310             SC_ID(scp) = new_string("chargen-dgram");
311       }
312
313       if( EQ( SC_NAME(scp), "echo" ) ) {
314          if( EQ( proto, "stream" ) )
315             SC_ID(scp) = new_string("echo-stream");
316          else
317             SC_ID(scp) = new_string("echo-dgram");
318       }
319
320       if( EQ( SC_NAME(scp), "discard" ) ) 
321       {
322          parsemsg(LOG_WARNING, func, 
323                   "inetd.conf - service discard not supported");
324          pset_destroy(args);
325          sc_free(scp);
326          return -1;
327       }
328    }
329    else
330    {
331       SC_SERVER(scp) = new_string( p );
332       if ( SC_SERVER(scp) == NULL )
333       {
334          out_of_memory( func ) ;
335          pset_destroy(args);
336          sc_free(scp);
337          return -1;
338       }
339       SC_SPECIFY( scp, A_SERVER);
340
341       /* Get argv */ 
342       SC_SERVER_ARGV(scp) = (char **)argv_alloc(pset_count(args)+1);
343
344       for( u = 0; u < pset_count(args)-6 ; u++ )
345       {
346          p = new_string((char *)pset_pointer(args, u+6));
347          if( p == NULL )
348          {
349             for ( i = 1 ; i < u ; i++ )
350                free( SC_SERVER_ARGV(scp)[i] );
351             free( SC_SERVER_ARGV(scp) );
352             pset_destroy(args);
353             sc_free(scp);
354             return -1;
355          }
356          SC_SERVER_ARGV(scp)[u] = p;
357       }
358       /* Set the reuse flag, as this is the default for inetd */
359       nvp = nv_find_value( service_flags, "REUSE" );
360       if ( nvp == NULL )
361       {
362          parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ;
363          pset_destroy(args);
364          sc_free(scp);
365          return -1;
366       }
367       M_SET(SC_XFLAGS(scp), nvp->value);
368
369       /* Set the NOLIBWRAP flag, since inetd doesn't have libwrap built in */
370       nvp = nv_find_value( service_flags, "NOLIBWRAP" );
371       if ( nvp == NULL )
372       {
373          parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ;
374          pset_destroy(args);
375          sc_free(scp);
376          return -1;
377       }
378       M_SET(SC_XFLAGS(scp), nvp->value);
379    
380       /* Set the NAMEINARGS flag, as that's the default for inetd */
381       nvp = nv_find_value( service_flags, "NAMEINARGS" );
382       if ( nvp == NULL )
383       {
384          parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ;
385          pset_destroy(args);
386          sc_free(scp);
387          return (-1);
388       }
389       M_SET(SC_XFLAGS(scp), nvp->value);
390       SC_SPECIFY( scp, A_SERVER_ARGS );
391
392       if ( (SC_ID(scp) = new_string( SC_NAME(scp) )) )
393          SC_PRESENT( scp, A_ID ) ;
394       else
395       {
396          out_of_memory( func ) ;
397          pset_destroy(args);
398          sc_free(scp);
399          return -1;
400       }
401    }
402    
403    SC_SPECIFY( scp, A_PROTOCOL );
404    SC_SPECIFY( scp, A_USER );
405    SC_SPECIFY( scp, A_SOCKET_TYPE );
406    SC_SPECIFY( scp, A_WAIT );
407
408    if( ! pset_add(sconfs, scp) )
409    {
410       out_of_memory( func );
411       pset_destroy(args);
412       sc_free(scp);
413       return -1;
414    }
415
416    pset_destroy(args);
417    parsemsg( LOG_DEBUG, func, "added service %s", SC_NAME(scp));
418    return 0;
419 }
420