/* * Fill in scp the value of the modifiable attribute attr from def. * These modifiable attributes are: * log_on_{success,failure} * only_from * no_access * passenv */ static void fill_attribute( unsigned attr_id, struct service_config *scp, struct service_config *def ) { switch ( attr_id ) { case A_LOG_ON_SUCCESS: M_ASSIGN( SC_LOG_ON_SUCCESS(scp), SC_LOG_ON_SUCCESS(def) ) ; SC_PRESENT( scp, A_LOG_ON_SUCCESS ) ; break ; case A_LOG_ON_FAILURE: M_ASSIGN( SC_LOG_ON_FAILURE(scp), SC_LOG_ON_FAILURE(def) ) ; SC_PRESENT( scp, A_LOG_ON_FAILURE ) ; break ; case A_ONLY_FROM: if ( addrlist_copy( SC_ONLY_FROM(def), &SC_ONLY_FROM(scp) ) == OK ) SC_PRESENT( scp, A_ONLY_FROM ) ; break ; case A_NO_ACCESS: if ( addrlist_copy( SC_NO_ACCESS(def), &SC_NO_ACCESS(scp) ) == OK ) SC_PRESENT( scp, A_NO_ACCESS ) ; break ; case A_PASSENV: if ( copy_pset( SC_PASS_ENV_VARS(def), &SC_PASS_ENV_VARS(scp), 0 ) == OK ) SC_PRESENT( scp, A_PASSENV ) ; break ; case A_ACCESS_TIMES: if ( copy_pset( SC_ACCESS_TIMES(def), &SC_ACCESS_TIMES(scp), 0 ) == OK ) SC_PRESENT( scp, A_ACCESS_TIMES ) ; break ; case A_BANNER: if ((SC_BANNER(scp) = new_string(SC_BANNER(def))) != NULL) SC_PRESENT( scp, A_BANNER ); break ; case A_BANNER_SUCCESS: if ((SC_BANNER_SUCCESS(scp) = new_string(SC_BANNER_SUCCESS(def))) != NULL) SC_PRESENT( scp, A_BANNER_SUCCESS ); break ; case A_BANNER_FAIL: if ((SC_BANNER_FAIL(scp) = new_string(SC_BANNER_FAIL(def))) != NULL) SC_PRESENT( scp, A_BANNER_FAIL ); break ; } }
/* * Get a service entry. Steps: * * 1. Parse entry attributes * 2. Determine service id * 3. Insert entry in table */ static void get_service_entry( int fd, pset_h sconfs, const char *name, struct service_config *defaults ) { struct service_config *scp ; const char *func = "get_service_entry" ; scp = sc_alloc( name ) ; if ( scp == NULL ) { skip_entry( fd ) ; return ; } /* Now fill in default attributes if given. */ if ( SC_SPECIFIED( defaults, A_LOG_ON_SUCCESS ) && ! SC_IS_PRESENT( scp, A_LOG_ON_SUCCESS) ) fill_attribute( A_LOG_ON_SUCCESS, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_LOG_ON_FAILURE ) && ! SC_IS_PRESENT( scp, A_LOG_ON_FAILURE ) ) fill_attribute( A_LOG_ON_FAILURE, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_ONLY_FROM ) && ! SC_IS_PRESENT( scp, A_ONLY_FROM ) ) fill_attribute( A_ONLY_FROM, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_NO_ACCESS ) && ! SC_IS_PRESENT( scp, A_NO_ACCESS ) ) fill_attribute( A_NO_ACCESS, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_PASSENV ) && ! SC_IS_PRESENT( scp, A_PASSENV ) ) fill_attribute( A_PASSENV, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_ACCESS_TIMES ) && ! SC_IS_PRESENT( scp, A_ACCESS_TIMES ) ) fill_attribute( A_ACCESS_TIMES, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_BANNER ) && ! SC_IS_PRESENT( scp, A_BANNER ) ) fill_attribute( A_BANNER, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_BANNER_SUCCESS ) && ! SC_IS_PRESENT( scp, A_BANNER_SUCCESS ) ) fill_attribute( A_BANNER_SUCCESS, scp, defaults ) ; if ( SC_SPECIFIED( defaults, A_BANNER_FAIL ) && ! SC_IS_PRESENT( scp, A_BANNER_FAIL ) ) fill_attribute( A_BANNER_FAIL, scp, defaults ) ; if ( parse_entry( SERVICE_ENTRY, fd, scp ) == FAILED ) { sc_free( scp ) ; skip_entry( fd ) ; return ; } /* * If no service id was specified, set it equal to the service name */ if ( ! SC_SPECIFIED( scp, A_ID ) ) { if ( (SC_ID(scp) = new_string( SC_NAME(scp) )) ) SC_PRESENT( scp, A_ID ) ; else { out_of_memory( func ) ; sc_free( scp ) ; return ; } } if ( ! (pset_add( sconfs, scp )) ) { out_of_memory( func ) ; sc_free( scp ) ; return ; } }
static int get_next_inet_entry( int fd, pset_h sconfs, struct service_config *defaults) { char *p; str_h strp; char *line = next_line(fd); struct service_config *scp; unsigned u, i; const char *func = "get_next_inet_entry"; char *name = NULL, *rpcvers = NULL, *rpcproto = NULL; char *group, *proto, *stype; const struct name_value *nvp; struct protoent *pep ; struct passwd *pw ; struct group *grp ; const char *dot = "."; const char *slash = "/"; pset_h args; if( line == CHAR_NULL ) return -2; strp = str_parse( line, " \t", STR_RETURN_ERROR, INT_NULL ) ; if( strp == NULL ) { parsemsg( LOG_CRIT, func, "inetd.conf - str_parse failed" ) ; return( -1 ) ; } if( (args = pset_create(10,10)) == NULL ) { out_of_memory(func); return -1; } /* Break the line into components, based on spaces */ while( (p = str_component( strp )) ) { if( pset_add(args, p) == NULL ) { parsemsg( LOG_CRIT, func, ES_NOMEM ); pset_destroy(args); return -1; } } str_endparse( strp ); /* get the service name */ name = new_string((char *)pset_pointer( args, 0 )); if( name == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - Invalid service name" ); pset_destroy(args); return -1; } /* Check to find the '/' for specifying RPC version numbers */ if( (rpcvers = strstr(name, slash)) != NULL ) { *rpcvers = '\0'; rpcvers++; } scp = sc_alloc( name ); if( scp == NULL ) { pset_destroy(args); free( name ); return -1; } /* * sc_alloc makes its own copy of name. At this point, sc_alloc worked * so we will free our copy to avoid leaks. */ free( name ); /* Replicate inetd behavior in this regard. Also makes sure the * service actually works on system where setgroups(0,NULL) doesn't * work. */ SC_GROUPS(scp) = YES; SC_SPECIFY( scp, A_GROUPS ); /* Get the socket type (stream dgram) */ stype = (char *)pset_pointer(args, 1); if( stype == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - Invalid socket type" ); pset_destroy(args); sc_free(scp); return -1; } nvp = nv_find_value( socket_types, stype ); if( nvp == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - Bad socket type: %s", p); pset_destroy(args); sc_free(scp); return -1; } SC_SOCKET_TYPE(scp) = nvp->value; /* Get the protocol type */ proto = (char *)pset_pointer(args,2); if( strstr(proto, "rpc") != NULL ) { int rpcmin, rpcmax; struct rpc_data *rdp = SC_RPCDATA( scp ) ; if( rpcvers == NULL ) { pset_destroy(args); sc_free(scp); return -1; /* uh oh */ } p = strchr(rpcvers, '-'); if( p && parse_int(rpcvers, 10, '-', &rpcmin) == 0 ) { if( parse_base10(p + 1, &rpcmax) || rpcmin > rpcmax ) { pset_destroy(args); sc_free(scp); return -1; } } else { if( parse_base10(rpcvers, &rpcmin) ) { pset_destroy(args); sc_free(scp); return -1; } rpcmax = rpcmin; } /* now have min and max rpc versions */ rdp->rd_min_version = rpcmin; rdp->rd_max_version = rpcmax; rpcproto = strstr(proto, slash); if( rpcproto == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - bad rpc version numbers" ); pset_destroy(args); sc_free(scp); return -1; } *rpcproto = '\0'; rpcproto++; proto = rpcproto; /* Set the RPC type field */ nvp = nv_find_value( service_types, "RPC" ); if ( nvp == NULL ) { parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ; pset_destroy(args); sc_free(scp); return -1; } M_SET(SC_TYPE(scp), nvp->value); } if ( ( pep = getprotobyname( proto ) ) == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - Protocol %s not in /etc/protocols", proto ) ; pset_destroy(args); sc_free(scp); return -1; } SC_PROTONAME(scp) = new_string( proto ) ; if ( SC_PROTONAME(scp) == NULL ) { out_of_memory( func ) ; pset_destroy(args); sc_free(scp); return -1; } SC_PROTOVAL(scp) = pep->p_proto; SC_SPECIFY(scp, A_PROTOCOL); /* Get the wait attribute */ p = (char *)pset_pointer(args, 3); if ( p == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - No value specified for wait" ); sc_free(scp); return -1; } if ( EQ( p, "wait" ) ) SC_WAIT(scp) = YES ; else if ( EQ( p, "nowait" ) ) SC_WAIT(scp) = NO ; else parsemsg( LOG_ERR, func, "inetd.conf - Bad value for wait: %s", p ) ; /* Get the user to run as */ p = (char *)pset_pointer(args, 4); if ( p == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - No value specified for user" ); sc_free(scp); return -1; } if( (group = strstr(p, dot)) ) { *group = '\0'; group++; grp = (struct group *)getgrnam( (char *)group ) ; if ( grp == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - Unknown group: %s", group ) ; pset_destroy(args); sc_free(scp); return -1; } SC_GID(scp) = ((struct group *)grp)->gr_gid; SC_SPECIFY( scp, A_GROUP ); } pw = getpwnam( p ); if ( pw == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - Unknown user: %s", p ) ; pset_destroy(args); sc_free(scp); return -1; } str_fill( pw->pw_passwd, ' ' ); SC_UID(scp) = pw->pw_uid; SC_USER_GID(scp) = pw->pw_gid; /* Get server name, or flag as internal */ p = (char *)pset_pointer(args, 5); if ( p == NULL ) { parsemsg( LOG_ERR, func, "inetd.conf - No value specified for user" ); sc_free(scp); return -1; } if( EQ( p, "internal" ) ) { nvp = nv_find_value( service_types, "INTERNAL" ); if ( nvp == NULL ) { parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ; pset_destroy(args); sc_free(scp); return -1; } M_SET(SC_TYPE(scp), nvp->value); if( EQ( SC_NAME(scp), "time" ) ) { if( EQ( proto, "stream" ) ) SC_ID(scp) = new_string("time-stream"); else SC_ID(scp) = new_string("time-dgram"); } if( EQ( SC_NAME(scp), "daytime" ) ) { if( EQ( proto, "stream" ) ) SC_ID(scp) = new_string("daytime-stream"); else SC_ID(scp) = new_string("daytime-dgram"); } if( EQ( SC_NAME(scp), "chargen" ) ) { if( EQ( proto, "stream" ) ) SC_ID(scp) = new_string("chargen-stream"); else SC_ID(scp) = new_string("chargen-dgram"); } if( EQ( SC_NAME(scp), "echo" ) ) { if( EQ( proto, "stream" ) ) SC_ID(scp) = new_string("echo-stream"); else SC_ID(scp) = new_string("echo-dgram"); } if( EQ( SC_NAME(scp), "discard" ) ) { parsemsg(LOG_WARNING, func, "inetd.conf - service discard not supported"); pset_destroy(args); sc_free(scp); return -1; } } else { SC_SERVER(scp) = new_string( p ); if ( SC_SERVER(scp) == NULL ) { out_of_memory( func ) ; pset_destroy(args); sc_free(scp); return -1; } SC_SPECIFY( scp, A_SERVER); /* Get argv */ SC_SERVER_ARGV(scp) = (char **)argv_alloc(pset_count(args)+1); for( u = 0; u < pset_count(args)-6 ; u++ ) { p = new_string((char *)pset_pointer(args, u+6)); if( p == NULL ) { for ( i = 1 ; i < u ; i++ ) free( SC_SERVER_ARGV(scp)[i] ); free( SC_SERVER_ARGV(scp) ); pset_destroy(args); sc_free(scp); return -1; } SC_SERVER_ARGV(scp)[u] = p; } /* Set the reuse flag, as this is the default for inetd */ nvp = nv_find_value( service_flags, "REUSE" ); if ( nvp == NULL ) { parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ; pset_destroy(args); sc_free(scp); return -1; } M_SET(SC_XFLAGS(scp), nvp->value); /* Set the NOLIBWRAP flag, since inetd doesn't have libwrap built in */ nvp = nv_find_value( service_flags, "NOLIBWRAP" ); if ( nvp == NULL ) { parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ; pset_destroy(args); sc_free(scp); return -1; } M_SET(SC_XFLAGS(scp), nvp->value); /* Set the NAMEINARGS flag, as that's the default for inetd */ nvp = nv_find_value( service_flags, "NAMEINARGS" ); if ( nvp == NULL ) { parsemsg( LOG_WARNING, func, "inetd.conf - Bad foo %s", name ) ; pset_destroy(args); sc_free(scp); return (-1); } M_SET(SC_XFLAGS(scp), nvp->value); SC_SPECIFY( scp, A_SERVER_ARGS ); if ( (SC_ID(scp) = new_string( SC_NAME(scp) )) ) SC_PRESENT( scp, A_ID ) ; else { out_of_memory( func ) ; pset_destroy(args); sc_free(scp); return -1; } } SC_SPECIFY( scp, A_PROTOCOL ); SC_SPECIFY( scp, A_USER ); SC_SPECIFY( scp, A_SOCKET_TYPE ); SC_SPECIFY( scp, A_WAIT ); if( ! pset_add(sconfs, scp) ) { out_of_memory( func ); pset_destroy(args); sc_free(scp); return -1; } pset_destroy(args); parsemsg( LOG_DEBUG, func, "added service %s", SC_NAME(scp)); return 0; }