static void deactivate( const struct service *sp ) { (void) Sclose( SVC_FD( sp ) ) ; #ifdef HAVE_MDNS xinetd_mdns_deregister(SVC_CONF(sp)); #endif if (debug.on) msg(LOG_DEBUG, "deactivate", "%d Service %s deactivated", getpid(), SC_NAME( SVC_CONF(sp) ) ); #ifndef NO_RPC if ( SC_IS_RPC( SVC_CONF( sp ) ) ) { unsigned long vers ; const struct rpc_data *rdp = SC_RPCDATA( SVC_CONF( sp ) ) ; for ( vers = RD_MINVERS( rdp ) ; vers <= RD_MAXVERS( rdp ) ; vers++ ) { (void) pmap_unset( RD_PROGNUM( rdp ), vers ) ; } } #endif /* ! NO_RPC */ }
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; }
/* * Print info about service scp to file descriptor fd */ void sc_dump( struct service_config *scp, int fd, int tab_level, bool_int is_defaults ) { const struct name_value *nvp ; unsigned u ; char **pp ; if ( is_defaults ) tabprint( fd, tab_level, "Service defaults\n" ) ; else tabprint( fd, tab_level, "Service configuration: %s\n", SC_NAME(scp) ) ; if ( ! is_defaults ) { tabprint( fd, tab_level+1, "id = %s\n", SC_ID(scp) ) ; if ( ! M_ARE_ALL_CLEAR( SC_XFLAGS(scp) ) ) { tabprint( fd, tab_level+1, "flags =" ) ; for ( nvp = &service_flags[ 0 ] ; nvp->name != NULL ; nvp++ ) if ( M_IS_SET( SC_XFLAGS(scp), nvp->value ) ) Sprint( fd, " %s", nvp->name ) ; Sputchar( fd, '\n' ) ; } if ( ! M_ARE_ALL_CLEAR( SC_TYPE(scp) ) ) { tabprint( fd, tab_level+1, "type =" ) ; for ( nvp = &service_types[ 0 ] ; nvp->name != NULL ; nvp++ ) if ( M_IS_SET( SC_TYPE(scp), nvp->value ) ) Sprint( fd, " %s", nvp->name ) ; Sputchar( fd, '\n' ) ; } tabprint( fd, tab_level+1, "socket_type = %s\n", nv_get_name( socket_types, SC_SOCKET_TYPE(scp) ) ) ; tabprint( fd, tab_level+1, "Protocol (name,number) = (%s,%d)\n", SC_PROTONAME(scp), SC_PROTOVAL(scp) ) ; if ( SC_SPECIFIED( scp, A_PORT ) ) tabprint( fd, tab_level+1, "port = %d\n", SC_PORT(scp) ) ; } if ( SC_SPECIFIED( scp, A_INSTANCES ) ) { if ( SC_INSTANCES(scp) == UNLIMITED ) tabprint( fd, tab_level+1, "Instances = UNLIMITED\n" ) ; else tabprint( fd, tab_level+1, "Instances = %d\n", SC_INSTANCES(scp) ) ; } if ( SC_SPECIFIED( scp, A_WAIT ) ) { if ( SC_WAIT(scp) ) tabprint( fd, tab_level+1, "wait = yes\n" ) ; else tabprint( fd, tab_level+1, "wait = no\n" ) ; } if ( SC_SPECIFIED( scp, A_USER ) ) tabprint( fd, tab_level+1, "user = %d\n", SC_UID(scp) ) ; if ( SC_SPECIFIED( scp, A_GROUP ) ) tabprint( fd, tab_level+1, "group = %d\n", SC_GID(scp) ) ; if ( SC_SPECIFIED( scp, A_GROUPS ) ) { if (SC_GROUPS(scp) == 1) tabprint( fd, tab_level+1, "Groups = yes\n" ); else tabprint( fd, tab_level+1, "Groups = no\n" ); } if ( SC_SPECIFIED( scp, A_UMASK ) ) tabprint( fd, tab_level+1, "umask = %o\n", SC_UMASK(scp) ) ; if ( SC_SPECIFIED( scp, A_NICE ) ) tabprint( fd, tab_level+1, "Nice = %d\n", SC_NICE(scp) ) ; if ( SC_SPECIFIED( scp, A_CPS ) ) tabprint( fd, tab_level+1, "CPS = max conn:%lu wait:%lu\n", SC_TIME_CONN_MAX(scp), SC_TIME_WAIT(scp) ); if ( SC_SPECIFIED( scp, A_PER_SOURCE ) ) tabprint( fd, tab_level+1, "PER_SOURCE = %d\n", SC_PER_SOURCE(scp) ); if ( SC_SPECIFIED( scp, A_BIND ) ) { if ( SC_BIND_ADDR(scp) ) { char bindname[NI_MAXHOST]; unsigned int len = 0; if( SC_BIND_ADDR(scp)->sa.sa_family == AF_INET ) len = sizeof(struct sockaddr_in); else len = sizeof(struct sockaddr_in6); memset(bindname, 0, sizeof(bindname)); if( getnameinfo(&SC_BIND_ADDR(scp)->sa, len, bindname, NI_MAXHOST, NULL, 0, 0) != 0 ) strcpy(bindname, "unknown"); tabprint( fd, tab_level+1, "Bind = %s\n", bindname ); } else if ( SC_ORIG_BIND_ADDR(scp) ) { tabprint( fd, tab_level+1, "Bind = %s\n", SC_ORIG_BIND_ADDR(scp) ); } else { /* This should NEVER happen */ msg(LOG_ERR, "sc_dump", "bad configuration for %s:", SC_NAME(scp)); } } else tabprint( fd, tab_level+1, "Bind = All addresses.\n" ); if ( ! is_defaults ) { if ( (! SC_IS_INTERNAL( scp )) && (SC_REDIR_ADDR(scp) == NULL) ) { tabprint( fd, tab_level+1, "Server = %s\n", SC_SERVER(scp) ) ; tabprint( fd, tab_level+1, "Server argv =" ) ; if ( SC_SERVER_ARGV(scp) ) { for ( pp = SC_SERVER_ARGV(scp) ; *pp ; pp++ ) Sprint( fd, " %s", *pp ) ; } else Sprint( fd, " (NULL)"); Sputchar( fd, '\n' ) ; } #ifdef LIBWRAP if ( SC_LIBWRAP(scp) != NULL ) { tabprint( fd, tab_level + 1, "Libwrap = %s\n", SC_LIBWRAP(scp) ); } #endif if ( SC_REDIR_ADDR(scp) != NULL ) { char redirname[NI_MAXHOST]; unsigned int len = 0; if( SC_REDIR_ADDR(scp)->sa.sa_family == AF_INET ) len = sizeof(struct sockaddr_in); if( SC_REDIR_ADDR(scp)->sa.sa_family == AF_INET6 ) len = sizeof(struct sockaddr_in6); memset(redirname, 0, sizeof(redirname)); if( getnameinfo(&SC_REDIR_ADDR(scp)->sa, len, redirname, NI_MAXHOST, NULL, 0, 0) != 0 ) strcpy(redirname, "unknown"); tabprint( fd, tab_level+1, "Redirect = %s:%d\n", redirname, SC_REDIR_ADDR(scp)->sa_in.sin_port ); } if ( SC_IS_RPC( scp ) ) { struct rpc_data *rdp = SC_RPCDATA( scp ) ; tabprint( fd, tab_level+1, "RPC data\n" ) ; tabprint( fd, tab_level+2, "program number = %ld\n", rdp->rd_program_number ) ; tabprint( fd, tab_level+2, "rpc_version = " ) ; if ( rdp->rd_min_version == rdp->rd_max_version ) Sprint( fd, "%ld\n", rdp->rd_min_version ) ; else Sprint( fd, "%ld-%ld\n", rdp->rd_min_version, rdp->rd_max_version ) ; } if ( SC_SPECIFIED( scp, A_ACCESS_TIMES ) ) { tabprint( fd, tab_level+1, "Access times =" ) ; ti_dump( SC_ACCESS_TIMES(scp), fd ) ; Sputchar ( fd, '\n' ) ; } } /* This is important enough that each service should list it. */ tabprint( fd, tab_level+1, "Only from: " ) ; if ( SC_ONLY_FROM(scp) ) { /* Next check is done since -= doesn't zero out lists. */ if ( pset_count(SC_ONLY_FROM(scp)) == 0) Sprint( fd, "All sites" ); else addrlist_dump( SC_ONLY_FROM(scp), fd ) ; } else Sprint( fd, "All sites" ); Sputchar( fd, '\n' ) ; /* This is important enough that each service should list it. */ tabprint( fd, tab_level+1, "No access: " ) ; if ( SC_NO_ACCESS(scp) ) { /* Next check is done since -= doesn't zero out lists. */ if ( pset_count(SC_NO_ACCESS(scp)) == 0) Sprint( fd, "No blocked sites" ); else addrlist_dump( SC_NO_ACCESS(scp), fd ) ; } else Sprint( fd, "No blocked sites" ); Sputchar( fd, '\n' ) ; if ( SC_SENSOR(scp) ) { tabprint( fd, tab_level+1, "Deny Time: " ) ; Sprint( fd, "%d\n", SC_DENY_TIME(scp)); } dump_log_data( fd, scp, tab_level+1 ) ; if ( SC_IS_PRESENT( scp, A_PASSENV ) ) { tabprint( fd, tab_level+1, "Passenv =" ) ; for ( u = 0 ; u < pset_count( SC_PASS_ENV_VARS(scp) ) ; u++ ) Sprint( fd, " %s", (char *) pset_pointer( SC_PASS_ENV_VARS(scp), u ) ) ; Sputchar ( fd, '\n' ) ; } if ( ! is_defaults ) if ( SC_SPECIFIED( scp, A_ENV ) ) { tabprint( fd, tab_level+1, "Environment additions:\n" ) ; for ( u = 0 ; u < pset_count( SC_ENV_VAR_DEFS(scp) ) ; u++ ) tabprint( fd, tab_level+2, "%s\n", (char *) pset_pointer( SC_ENV_VAR_DEFS(scp), u ) ) ; } if ( SC_ENV( scp )->env_type == CUSTOM_ENV ) { tabprint( fd, tab_level+1, "Environment strings:\n" ) ; for ( pp = env_getvars( SC_ENV( scp )->env_handle ) ; *pp ; pp++ ) tabprint( fd, tab_level+2, "%s\n", *pp ) ; } Sflush( fd ) ; }
static status_e activate_rpc( struct service *sp ) { union xsockaddr tsin; socklen_t sin_len = sizeof(tsin); unsigned long vers ; struct service_config *scp = SVC_CONF( sp ) ; struct rpc_data *rdp = SC_RPCDATA( scp ) ; char *sid = SC_ID( scp ) ; unsigned registered_versions = 0 ; int sd = SVC_FD( sp ) ; const char *func = "activate_rpc" ; if( SC_BIND_ADDR(scp) != 0 ) memcpy( &tsin, SC_BIND_ADDR(scp), sizeof(tsin) ); else memset( &tsin, 0, sizeof(tsin)); if ( SC_PROTOVAL ( scp ) == IPPROTO_TCP ) { M_SET ( scp->sc_xflags, SF_NOLIBWRAP ); } if( SC_IPV4( scp ) ) { tsin.sa_in.sin_family = AF_INET ; sin_len = sizeof(struct sockaddr_in); } else if( SC_IPV6( scp ) ) { tsin.sa_in6.sin6_family = AF_INET6 ; sin_len = sizeof(struct sockaddr_in6); } if ( bind( sd, &tsin.sa, sin_len ) == -1 ) { msg( LOG_ERR, func, "bind failed (%m). service = %s", sid ) ; return( FAILED ) ; } /* * Find the port number that was assigned to the socket */ if ( getsockname( sd, &tsin.sa, &sin_len ) == -1 ) { msg( LOG_ERR, func, "getsockname failed (%m). service = %s", sid ) ; return( FAILED ) ; } if( tsin.sa.sa_family == AF_INET ) SC_SET_PORT( scp, ntohs( tsin.sa_in.sin_port ) ) ; else if( tsin.sa.sa_family == AF_INET6 ) SC_SET_PORT( scp, ntohs( tsin.sa_in6.sin6_port ) ) ; /* * Try to register as many versions as possible */ for ( vers = RD_MINVERS( rdp ) ; vers <= RD_MAXVERS( rdp ) ; vers++ ) { /* Is this right? For instance, if we have both tcp and udp services, * this will unregister the previously registered protocol. * pmap_unset(RD_PROGNUM(rdp), vers); */ if ( pmap_set( RD_PROGNUM( rdp ), vers, SC_PROTOVAL( scp ), SC_PORT( scp ) ) ) registered_versions++ ; else msg( LOG_ERR, func, "pmap_set failed. service=%s program=%ld version=%ld", sid, RD_PROGNUM( rdp ), vers ) ; sleep(1); } if ( debug.on ) msg( LOG_DEBUG, func, "Registered %d versions of %s", registered_versions, sid ) ; return( ( registered_versions == 0 ) ? FAILED : OK ) ; }