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
parse_inet_conf_file(int fd,struct configuration * confp)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
get_next_inet_entry(int fd,pset_h sconfs,struct service_config * defaults)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
421