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 <dirent.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <netdb.h>
16 #include <syslog.h>
17 #include <memory.h>
18 #include <fcntl.h>
19 #include <grp.h>
20 #include <pwd.h>
21
22 #include "str.h"
23 #include "parse.h"
24 #include "parsers.h"
25 #include "msg.h"
26 #include "parsesup.h"
27 #include "addr.h"
28 #include "includedir.h"
29 #include "main.h"
30 #include "sio.h"
31
32 #ifndef NAME_MAX
33 #define NAME_MAX 255
34 #endif
35
36
37 /*
38 * A NULL value for the name field marks the end of the table
39 *
40 * The 3rd value is the number of attribute values.
41 * If the number is positive, exactly that many values must be specified.
42 * If the number is -1, 0 or more values may be specified.
43 * If the number is -2, 0 or more values may be specified and the operators
44 * '+=' and '-=' may be used.
45 */
46 static const struct attribute service_attributes[] =
47 {
48 { "socket_type", A_SOCKET_TYPE, 1, socket_type_parser },
49 { "protocol", A_PROTOCOL, 1, protocol_parser },
50 { "wait", A_WAIT, 1, wait_parser },
51 { "user", A_USER, 1, user_parser },
52 { "group", A_GROUP, 1, group_parser },
53 { "server", A_SERVER, 1, server_parser },
54 { "server_args", A_SERVER_ARGS, -1, server_args_parser },
55 { "instances", A_INSTANCES, 1, instances_parser },
56 { "log_on_success", A_LOG_ON_SUCCESS,-2, log_on_success_parser },
57 { "log_on_failure", A_LOG_ON_FAILURE,-2, log_on_failure_parser },
58 { "log_type", A_LOG_TYPE, -1, log_type_parser },
59 { "only_from", A_ONLY_FROM, -2, only_from_parser },
60 { "no_access", A_NO_ACCESS, -2, no_access_parser },
61 { "access_times", A_ACCESS_TIMES, -1, access_times_parser },
62 { "type", A_TYPE, -1, type_parser },
63 #ifndef NO_RPC
64 { "rpc_version", A_RPC_VERSION, 1, rpc_version_parser },
65 { "rpc_number", A_RPC_NUMBER, 1, rpc_number_parser },
66 #endif
67 { "id", A_ID, 1, id_parser },
68 { "env", A_ENV, -2, env_parser },
69 { "port", A_PORT, 1, port_parser },
70 { "passenv", A_PASSENV, -2, passenv_parser },
71 { "flags", A_FLAGS, -1, flags_parser },
72 { "nice", A_NICE, 1, nice_parser },
73 { "redirect", A_REDIR, 2, redir_parser },
74 { "banner", A_BANNER, 1, banner_parser },
75 { "bind", A_BIND, 1, bind_parser },
76 { "interface", A_BIND, 1, bind_parser },
77 { "per_source", A_PER_SOURCE, 1, per_source_parser },
78 { "groups", A_GROUPS, 1, groups_parser },
79 { "banner_success", A_BANNER_SUCCESS, 1, banner_success_parser },
80 { "banner_fail", A_BANNER_FAIL, 1, banner_fail_parser },
81 { "cps", A_CPS, 2, cps_parser },
82 { "disable", A_SVCDISABLE, 1, svcdisable_parser },
83 #ifdef HAVE_LOADAVG
84 { "max_load", A_MAX_LOAD, 1, max_load_parser },
85 #endif
86 #ifdef RLIMIT_AS
87 { "rlimit_as", A_RLIMIT_AS, 1, rlim_as_parser },
88 #endif
89 #ifdef RLIMIT_CPU
90 { "rlimit_cpu", A_RLIMIT_CPU, 1, rlim_cpu_parser },
91 #endif
92 #ifdef RLIMIT_DATA
93 { "rlimit_data", A_RLIMIT_DATA, 1, rlim_data_parser },
94 #endif
95 #ifdef RLIMIT_RSS
96 { "rlimit_rss", A_RLIMIT_RSS, 1, rlim_rss_parser },
97 #endif
98 #ifdef RLIMIT_STACK
99 { "rlimit_stack", A_RLIMIT_STACK, 1, rlim_stack_parser },
100 #endif
101 { "v6only", A_V6ONLY, 1, v6only_parser },
102 { "deny_time", A_DENY_TIME, 1, deny_time_parser },
103 { "umask", A_UMASK, 1, umask_parser },
104 #ifdef HAVE_MDNS
105 { "mdns", A_MDNS, 1, mdns_parser },
106 #endif
107 #ifdef LIBWRAP
108 { "libwrap", A_LIBWRAP, 1, libwrap_parser },
109 #endif
110 { NULL, A_NONE, -1, NULL }
111 } ;
112
113 static const struct attribute default_attributes[] =
114 {
115 { "log_type", A_LOG_TYPE, -2, log_type_parser },
116 { "log_on_success", A_LOG_ON_SUCCESS, -2, log_on_success_parser },
117 { "log_on_failure", A_LOG_ON_FAILURE, -2, log_on_failure_parser },
118 { "disabled", A_DISABLED, -2, disabled_parser },
119 { "no_access", A_NO_ACCESS, -2, no_access_parser },
120 { "only_from", A_ONLY_FROM, -2, only_from_parser },
121 { "instances", A_INSTANCES, 1, instances_parser },
122 { "passenv", A_PASSENV, -2, passenv_parser },
123 { "banner", A_BANNER, 1, banner_parser },
124 { "bind", A_BIND, 1, bind_parser },
125 { "interface", A_BIND, 1, bind_parser },
126 { "per_source", A_PER_SOURCE, 1, per_source_parser },
127 { "groups", A_GROUPS, 1, groups_parser },
128 { "banner_success", A_BANNER_SUCCESS, 1, banner_success_parser },
129 { "banner_fail", A_BANNER_FAIL, 1, banner_fail_parser },
130 { "cps", A_CPS, 2, cps_parser },
131 { "enabled", A_ENABLED, -2, enabled_parser },
132 #ifdef HAVE_LOADAVG
133 { "max_load", A_MAX_LOAD, 1, max_load_parser },
134 #endif
135 { "v6only", A_V6ONLY, 1, v6only_parser },
136 { "umask", A_UMASK, 1, umask_parser },
137 #ifdef HAVE_MDNS
138 { "mdns", A_MDNS, 1, mdns_parser },
139 #endif
140 { NULL, A_NONE, 0, NULL }
141 } ;
142
143
144 #define MODIFIABLE( ap ) ( (ap)->a_nvalues == -2 )
145 #define FIXED_VALUES( ap ) ( (ap)->a_nvalues > 0 )
146
147 int line_count ;
148 const char *current_file = NULL;
149
150 static void get_service_entry( int fd, pset_h, const char *,
151 struct service_config * );
152 static void fill_attribute( unsigned attr_id, struct service_config *scp,
153 struct service_config *def );
154 static entry_e find_next_entry(int , char **) ;
155 static status_e parse_entry(entry_e, int, struct service_config *) ;
156
157 /*
158 * Given the id, return the name (only the service attributes are searched)
159 */
attr_name_lookup(unsigned int id)160 const char *attr_name_lookup( unsigned int id )
161 {
162 const struct attribute *ap ;
163
164 for ( ap = &service_attributes[ 0 ] ; ap->a_name ; ap++ )
165 if ( id == ap->a_id )
166 return( ap->a_name ) ;
167 return( CHAR_NULL ) ;
168 }
169
170
parse_end(void)171 void parse_end(void)
172 {
173 endprotoent() ;
174 endpwent() ;
175 endgrent() ;
176 endnetent() ;
177 endhostent() ;
178 }
179
180
181 /*
182 * Parsing rules and rationale
183 *
184 * The parse_conf_file function parses a configuration file identified
185 * by a file descriptor and fills the service table and defaults of
186 * the configuration argument.
187 *
188 * The configuration information for a service comes from 2 sources: the
189 * service entry and, possibly, the defaults entry.
190 * Attributes specified in the defaults entry can be overriden or
191 * modified by the service entry. Modifiable attributes can be identified
192 * by the value -2 for the 'a_nvalues' field of the struct attribute. Those
193 * attributes with a different value for 'a_nvalues' are overridable ones.
194 * The modifiable attributes are filled in only if the entry tries to modify
195 * them.
196 */
197
198 /*
199 * Read the configuration file (descriptor fd) and place all
200 * services found there in the configuration.
201 */
parse_conf_file(int fd,struct configuration * confp,const char * filename)202 void parse_conf_file( int fd, struct configuration *confp, const char *filename)
203 {
204 pset_h sconfs = CNF_SERVICE_CONFS( confp ) ;
205 struct service_config *default_config = CNF_DEFAULTS( confp ) ;
206 boolean_e found_defaults = NO ;
207 struct service_config default_default_config ;
208 const char *func = "parse_conf_file" ;
209 int incfd;
210
211 line_count = 0 ;
212 current_file = filename;
213 CLEAR( default_default_config ) ;
214
215 for ( ;; )
216 {
217 entry_e entry_type ;
218 char *service_name = NULL;
219
220 /*
221 * if find_next_entry is successful, service_name
222 * will point to malloc'ed memory
223 */
224 entry_type = find_next_entry( fd, &service_name ) ;
225 switch ( entry_type )
226 {
227 case INCLUDE_ENTRY:
228 {
229 int saved_line_count = line_count;
230 incfd = open(service_name, O_RDONLY);
231 if( incfd < 0 ) {
232 parsemsg( LOG_ERR, func,
233 "Unable to open included configuration file: %s",
234 service_name);
235 break;
236 }
237 parsemsg( LOG_DEBUG,func,
238 "Reading included configuration file: %s",service_name);
239 parse_conf_file(incfd, confp, service_name);
240 /*
241 * parse_conf_file eventually calls Srdline, try Sclosing it
242 * to unmmap memory.
243 */
244 Sclose(incfd);
245 /* Restore since we've returned from included file */
246 current_file = filename;
247 line_count = saved_line_count;
248 }
249 break;
250 case INCLUDEDIR_ENTRY:
251 {
252 int saved_line_count = line_count;
253 handle_includedir(service_name, confp);
254 current_file = filename;
255 line_count = saved_line_count;
256 }
257 break;
258 case SERVICE_ENTRY:
259 get_service_entry( fd, sconfs, service_name, default_config ) ;
260 break ;
261 case DEFAULTS_ENTRY:
262 if ( found_defaults == YES )
263 {
264 parsemsg( LOG_ERR, func,
265 "only 1 defaults entry is allowed. This entry will be ignored" ) ;
266 skip_entry( fd ) ;
267 }
268 else if ( parse_entry( DEFAULTS_ENTRY, fd,
269 default_config ) == OK ) {
270 found_defaults = YES ;
271 /*
272 * We must check bind_address to see if it was deferred.
273 */
274 if (SC_SPECIFIED( default_config, A_BIND) &&
275 SC_BIND_ADDR(default_config) == NULL)
276 M_CLEAR( default_config->sc_specified_attributes, A_BIND ) ;
277 }
278 break ;
279
280 case BAD_ENTRY:
281 skip_entry( fd ) ;
282 break ;
283
284 case NO_ENTRY:
285 return ;
286 }
287 if (service_name)
288 free(service_name);
289 }
290 }
291
292
293 /*
294 * Find the next service entry.
295 * Look for a line of the form:
296 *
297 * <white-space> service <white-space> <service_name>
298 *
299 * followed by a line containing only the ENTRY_BEGIN character
300 */
find_next_entry(int fd,char ** snamep)301 static entry_e find_next_entry( int fd, char **snamep )
302 {
303 char *p ;
304 str_h strp ;
305 char *sname = NULL;
306 entry_e entry_type=0;
307 char *line = next_line( fd ) ;
308 const char *func = "find_next_entry" ;
309
310 if ( line == CHAR_NULL )
311 return( NO_ENTRY ) ;
312
313 strp = str_parse( line, " \t", STR_RETURN_ERROR, INT_NULL ) ;
314 if ( strp == NULL )
315 {
316 parsemsg( LOG_CRIT, func, "str_parse failed" ) ;
317 return( BAD_ENTRY ) ;
318 }
319
320 if ( ( p = str_component( strp ) ) == CHAR_NULL )
321 {
322 /*
323 * This shouldn't happen since it implies that there is a bug
324 * in next_line
325 */
326 parsemsg( LOG_WARNING, func, "empty line" ) ;
327 str_endparse( strp ) ;
328 return( BAD_ENTRY ) ;
329 }
330
331 /*
332 * Look for a keyword
333 */
334 if ( EQ( p, KW_SERVICE ) || EQ( p, KW_INCLUDE ) || EQ(p, KW_INCLUDEDIR))
335 {
336 if ( EQ( p, KW_INCLUDE ))
337 entry_type = INCLUDE_ENTRY;
338 else if ( EQ( p, KW_INCLUDEDIR ))
339 entry_type = INCLUDEDIR_ENTRY;
340
341 /*
342 * Now get the service name
343 */
344 if ( ( p = str_component( strp ) ) == CHAR_NULL )
345 {
346 parsemsg( LOG_ERR, func, "service name missing" ) ;
347 str_endparse( strp ) ;
348 return( BAD_ENTRY ) ;
349 }
350
351 sname = new_string( p ) ;
352 if ( sname == CHAR_NULL )
353 {
354 out_of_memory( func ) ;
355 str_endparse( strp ) ;
356 return( BAD_ENTRY ) ;
357 }
358 str_endparse( strp ) ;
359
360 if( (entry_type == INCLUDE_ENTRY) ||
361 (entry_type == INCLUDEDIR_ENTRY))
362 {
363 *snamep = sname ;
364 return( entry_type ) ;
365 }
366 else
367 entry_type = SERVICE_ENTRY ;
368 }
369 else if ( EQ( p, KW_DEFAULTS ) )
370 {
371 str_endparse( strp ) ;
372 entry_type = DEFAULTS_ENTRY ;
373 }
374 else
375 {
376 parsemsg( LOG_ERR, func, "missing service keyword" ) ;
377 str_endparse( strp ) ;
378 return( BAD_ENTRY ) ;
379 }
380
381 /*
382 * Now look for ENTRY_BEGIN
383 */
384 line = next_line( fd ) ;
385 if ( line == NULL || ! line_has_only_1_char( line, ENTRY_BEGIN ) )
386 {
387 parsemsg( LOG_ERR, func,
388 "Service %s: missing '%c'", sname, ENTRY_BEGIN ) ;
389 if ( entry_type == SERVICE_ENTRY )
390 free( sname ) ;
391 return( BAD_ENTRY ) ;
392 }
393 *snamep = sname ;
394 return( entry_type ) ;
395 }
396
397
398 /*
399 * Get a service entry. Steps:
400 *
401 * 1. Parse entry attributes
402 * 2. Determine service id
403 * 3. Insert entry in table
404 */
get_service_entry(int fd,pset_h sconfs,const char * name,struct service_config * defaults)405 static void get_service_entry( int fd,
406 pset_h sconfs,
407 const char *name,
408 struct service_config *defaults )
409 {
410 struct service_config *scp ;
411 const char *func = "get_service_entry" ;
412
413 scp = sc_alloc( name ) ;
414 if ( scp == NULL )
415 {
416 skip_entry( fd ) ;
417 return ;
418 }
419
420 /* Now fill in default attributes if given. */
421 if ( SC_SPECIFIED( defaults, A_LOG_ON_SUCCESS ) &&
422 ! SC_IS_PRESENT( scp, A_LOG_ON_SUCCESS) )
423 fill_attribute( A_LOG_ON_SUCCESS, scp, defaults ) ;
424 if ( SC_SPECIFIED( defaults, A_LOG_ON_FAILURE ) &&
425 ! SC_IS_PRESENT( scp, A_LOG_ON_FAILURE ) )
426 fill_attribute( A_LOG_ON_FAILURE, scp, defaults ) ;
427 if ( SC_SPECIFIED( defaults, A_ONLY_FROM ) &&
428 ! SC_IS_PRESENT( scp, A_ONLY_FROM ) )
429 fill_attribute( A_ONLY_FROM, scp, defaults ) ;
430 if ( SC_SPECIFIED( defaults, A_NO_ACCESS ) &&
431 ! SC_IS_PRESENT( scp, A_NO_ACCESS ) )
432 fill_attribute( A_NO_ACCESS, scp, defaults ) ;
433 if ( SC_SPECIFIED( defaults, A_PASSENV ) &&
434 ! SC_IS_PRESENT( scp, A_PASSENV ) )
435 fill_attribute( A_PASSENV, scp, defaults ) ;
436 if ( SC_SPECIFIED( defaults, A_ACCESS_TIMES ) &&
437 ! SC_IS_PRESENT( scp, A_ACCESS_TIMES ) )
438 fill_attribute( A_ACCESS_TIMES, scp, defaults ) ;
439 if ( SC_SPECIFIED( defaults, A_BANNER ) &&
440 ! SC_IS_PRESENT( scp, A_BANNER ) )
441 fill_attribute( A_BANNER, scp, defaults ) ;
442 if ( SC_SPECIFIED( defaults, A_BANNER_SUCCESS ) &&
443 ! SC_IS_PRESENT( scp, A_BANNER_SUCCESS ) )
444 fill_attribute( A_BANNER_SUCCESS, scp, defaults ) ;
445 if ( SC_SPECIFIED( defaults, A_BANNER_FAIL ) &&
446 ! SC_IS_PRESENT( scp, A_BANNER_FAIL ) )
447 fill_attribute( A_BANNER_FAIL, scp, defaults ) ;
448
449 if ( parse_entry( SERVICE_ENTRY, fd, scp ) == FAILED )
450 {
451 sc_free( scp ) ;
452 skip_entry( fd ) ;
453 return ;
454 }
455
456 /*
457 * If no service id was specified, set it equal to the service name
458 */
459 if ( ! SC_SPECIFIED( scp, A_ID ) ) {
460 if ( (SC_ID(scp) = new_string( SC_NAME(scp) )) )
461 SC_PRESENT( scp, A_ID ) ;
462 else
463 {
464 out_of_memory( func ) ;
465 sc_free( scp ) ;
466 return ;
467 }
468 }
469
470 if ( ! (pset_add( sconfs, scp )) )
471 {
472 out_of_memory( func ) ;
473 sc_free( scp ) ;
474 return ;
475 }
476
477 }
478
479
480 /*
481 * Fill in scp the value of the modifiable attribute attr from def.
482 * These modifiable attributes are:
483 * log_on_{success,failure}
484 * only_from
485 * no_access
486 * passenv
487 */
fill_attribute(unsigned attr_id,struct service_config * scp,struct service_config * def)488 static void fill_attribute( unsigned attr_id,
489 struct service_config *scp,
490 struct service_config *def )
491 {
492 switch ( attr_id )
493 {
494 case A_LOG_ON_SUCCESS:
495 M_ASSIGN( SC_LOG_ON_SUCCESS(scp), SC_LOG_ON_SUCCESS(def) ) ;
496 SC_PRESENT( scp, A_LOG_ON_SUCCESS ) ;
497 break ;
498
499 case A_LOG_ON_FAILURE:
500 M_ASSIGN( SC_LOG_ON_FAILURE(scp), SC_LOG_ON_FAILURE(def) ) ;
501 SC_PRESENT( scp, A_LOG_ON_FAILURE ) ;
502 break ;
503
504 case A_ONLY_FROM:
505 if ( addrlist_copy( SC_ONLY_FROM(def), &SC_ONLY_FROM(scp) ) == OK )
506 SC_PRESENT( scp, A_ONLY_FROM ) ;
507 break ;
508
509 case A_NO_ACCESS:
510 if ( addrlist_copy( SC_NO_ACCESS(def), &SC_NO_ACCESS(scp) ) == OK )
511 SC_PRESENT( scp, A_NO_ACCESS ) ;
512 break ;
513
514 case A_PASSENV:
515 if ( copy_pset( SC_PASS_ENV_VARS(def),
516 &SC_PASS_ENV_VARS(scp), 0 ) == OK )
517 SC_PRESENT( scp, A_PASSENV ) ;
518 break ;
519
520 case A_ACCESS_TIMES:
521 if ( copy_pset( SC_ACCESS_TIMES(def),
522 &SC_ACCESS_TIMES(scp), 0 ) == OK )
523 SC_PRESENT( scp, A_ACCESS_TIMES ) ;
524 break ;
525
526 case A_BANNER:
527 if ((SC_BANNER(scp) = new_string(SC_BANNER(def))) != NULL)
528 SC_PRESENT( scp, A_BANNER );
529 break ;
530
531 case A_BANNER_SUCCESS:
532 if ((SC_BANNER_SUCCESS(scp) = new_string(SC_BANNER_SUCCESS(def)))
533 != NULL)
534 SC_PRESENT( scp, A_BANNER_SUCCESS );
535 break ;
536
537 case A_BANNER_FAIL:
538 if ((SC_BANNER_FAIL(scp) = new_string(SC_BANNER_FAIL(def))) != NULL)
539 SC_PRESENT( scp, A_BANNER_FAIL );
540 break ;
541 }
542 }
543
544
545 /*
546 * Find the attribute with the specified name
547 */
attr_lookup(const struct attribute attr_array[],const char * attr_name)548 static const struct attribute *attr_lookup(
549 const struct attribute attr_array[], const char *attr_name )
550 {
551 const struct attribute *ap ;
552 const char *func = "attr_lookup" ;
553
554 for ( ap = &attr_array[ 0 ] ; ap->a_name ; ap++ )
555 if ( EQ( attr_name, ap->a_name ) )
556 return ap;
557 if ( attr_array == service_attributes )
558 parsemsg( LOG_WARNING, func, "bad service attribute: %s", attr_name ) ;
559 else
560 parsemsg( LOG_WARNING, func,
561 "attribute: %s should not be in default section", attr_name ) ;
562 return NULL;
563 }
564
565
566 /*
567 * Identify the attribute in <attr_name>.
568 *
569 * Check if
570 * 1) the attribute has been defined already
571 * 2) the value count is correct
572 * 3) the assign op is appropriate
573 *
574 * Invoke appropriate parser.
575 *
576 * This function will return FAILED only if its in the default section
577 * and an attribute cannot be ID'd. Otherwise, it returns OK.
578 */
identify_attribute(entry_e entry_type,struct service_config * scp,const char * attr_name,enum assign_op op,pset_h attr_values)579 static status_e identify_attribute( entry_e entry_type,
580 struct service_config *scp,
581 const char *attr_name,
582 enum assign_op op,
583 pset_h attr_values )
584 {
585 const struct attribute *ap ;
586 const char *func = "identify_attribute" ;
587
588 if ( entry_type == SERVICE_ENTRY )
589 ap = attr_lookup( service_attributes, attr_name ) ;
590 else
591 ap = attr_lookup( default_attributes, attr_name ) ;
592
593 if ( ap == NULL )
594 return OK; /* We simply ignore keywords not on the list */
595
596 if ( ! MODIFIABLE( ap ) )
597 {
598 if ( SC_SPECIFIED( scp, ap->a_id ) )
599 {
600 parsemsg( LOG_WARNING, func, "Service %s: attribute already set: %s",
601 SC_NAME(scp), attr_name ) ;
602 return OK;
603 }
604
605 if ( op != SET_EQ )
606 {
607 parsemsg( LOG_WARNING, func,
608 "Service %s: operator '%s' cannot be used for attribute '%s'",
609 SC_NAME(scp), ( op == PLUS_EQ ) ? "+=" : "-=", attr_name ) ;
610 return OK;
611 }
612 }
613 else /* modifiable attribute */
614 {
615 /*
616 * For the defaults entry, '=' and '+=' have the same meaning
617 */
618 if ( entry_type == DEFAULTS_ENTRY && op == SET_EQ )
619 op = PLUS_EQ ;
620 }
621
622 if ( FIXED_VALUES( ap ) &&
623 (unsigned)ap->a_nvalues != pset_count( attr_values ) )
624 {
625 parsemsg( LOG_WARNING, func,
626 "attribute %s expects %d values and %d values were specified",
627 attr_name, ap->a_nvalues, pset_count( attr_values ) ) ;
628 return OK;
629 }
630
631 if ( (*ap->a_parser)( attr_values, scp, op ) == OK )
632 { /* This is the normal path. */
633 SC_SPECIFY( scp, ap->a_id ) ;
634 }
635 else if ( entry_type == SERVICE_ENTRY )
636 {
637 parsemsg( LOG_ERR, func,
638 "Error parsing attribute %s - DISABLING SERVICE", attr_name ) ;
639 SC_DISABLE( scp );
640 }
641 /*
642 * We are in the default section and an error was detected. At
643 * this point, we should terminate since whatever attribute
644 * was trying to be specified cannot be propagated.
645 */
646 else if ( !debug.on )
647 return FAILED;
648
649 return OK;
650 }
651
652
653 /*
654 * Read the entry line-by-line and add the information in scp
655 * Use defaults to initialize modifiable entry fields.
656 */
parse_entry(entry_e entry_type,int fd,struct service_config * scp)657 static status_e parse_entry( entry_e entry_type,
658 int fd,
659 struct service_config *scp )
660 {
661 static pset_h attr_values = NULL;
662 char *line ;
663 char *attr_name ;
664 enum assign_op op ;
665 const char *func = "get_attributes" ;
666
667 if ( ! attr_values && ( attr_values = pset_create( 10, 10 ) ) == NULL )
668 {
669 out_of_memory( func ) ;
670 return( FAILED ) ;
671 }
672
673 for ( ;; )
674 {
675 line = next_line( fd ) ;
676 if ( line == CHAR_NULL )
677 {
678 parsemsg( LOG_ERR, func, "incomplete entry" ) ;
679 return( FAILED ) ;
680 }
681
682 if ( line_has_only_1_char( line, ENTRY_END ) )
683 return( OK ) ;
684
685 if ( parse_line( line, &attr_name, &op, attr_values ) == FAILED )
686 {
687 pset_clear( attr_values ) ;
688 return( FAILED ) ;
689 }
690
691 if (identify_attribute( entry_type,
692 scp, attr_name, op, attr_values ) == FAILED )
693 {
694 /*
695 * An error was detected in the default section. We will terminate
696 * since whatever attribute being specified cannot be propagated.
697 */
698 msg(LOG_ERR, func,
699 "A fatal error was encountered while parsing the default section."
700 " xinetd will exit.");
701 Sclose( fd );
702 terminate_program();
703 }
704 pset_clear( attr_values ) ;
705 }
706 }
707
708