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