/* * Remove all NULL pointers from a pset */ void pset_compact( register pset_h pset ) { register unsigned u ; for ( u = 0 ; u < pset_count( pset ) ; ) { POINTER ptr = pset_pointer( pset, u ); if ( ptr != NULL ) u++ ; else pset_delete( pset, ptr ) ; } /* See if we can reclaim some memory, make sure we are 2 below for some hysteresis */ if ((int)( pset->max - pset->alloc_step - 2) > (int)pset_count( pset )) { /* This rounds up to the next unit of steps */ POINTER *new_ptrs ; unsigned new_max = ((pset_count( pset ) / pset->alloc_step) + 1)*pset->alloc_step; new_ptrs = (POINTER *) realloc( (char *)pset->ptrs, new_max * sizeof( POINTER ) ) ; if ( new_ptrs == NULL ) return; pset->max = new_max ; pset->ptrs = new_ptrs ; } }
static void scrub_global_access_list( void ) { unsigned count; const char *func = "scrub_global_no_access_list"; if ( global_no_access == NULL ) count = 0; else count = pset_count( global_no_access ); if ( count ) { int found_one = 0; unsigned u; time_t nowtime = time(NULL); for (u=0; u < count; u++) { char *exp_time; time_t stored_time; exp_time = pset_pointer( global_no_access_time, u ) ; stored_time = atol(exp_time); if (stored_time == -1) /* never let them off */ continue; if (difftime(nowtime, (time_t)stored_time) >= 0.0) { __pset_pointer ptr; pset_pointer(global_no_access, u) = NULL; ptr = global_no_access_time->ptrs[ u ]; free(ptr); pset_pointer(global_no_access_time, u ) = NULL; found_one = 1; } } if (found_one) { pset_compact( global_no_access ); pset_compact( global_no_access_time ); msg(LOG_INFO, func, "At least 1 DENY_TIME has expired, global_no_access list updated"); } /* If there's still more on the list, start another callback. */ count = pset_count( global_no_access ); if ( count ) timer_id = xtimer_add( scrub_global_access_list, 60 ); else { timer_id = 0; msg(LOG_INFO, func, "global_no_access list is empty."); } } }
/* xtimer_poll: * Traverses the pset_h of timers, and executes the callback for expired * timers. Timers that are expired, and have their callback executed * are removed from the list of timers. */ int xtimer_poll(void) { unsigned int i; if( xtimer_list == NULL ) return(0); for( i = 0; i < pset_count( xtimer_list ); i++ ) { xtime_h *cur_timer = pset_pointer( xtimer_list, i ); time_t cur_time = time(NULL); /* The list is sorted, low to high. If there's no * timers left, return. */ if( cur_timer->when > cur_time ) { return(0); } cur_timer->timerfunc(); pset_delete( xtimer_list, cur_timer ); free(cur_timer); i--; cur_timer = NULL; } return(0); }
/* * Count the number of references to the specified service contained * in the specified table of servers; put the number of servers * in *countp */ static int count_refs( struct service *sp, pset_h servers, unsigned *countp ) { unsigned u ; struct server *serp ; int refs = 0 ; unsigned count = 0 ; for ( u = 0 ; u < pset_count( servers ) ; u++ ) { serp = SERP( pset_pointer( SERVERS( ps ), u ) ) ; if ( SERVER_SERVICE( serp ) == sp ) { refs++ ; count++ ; } if ( SERVER_CONNSERVICE( serp ) == sp ) refs++ ; /* * XXX: in the future we may want to check if the given service * is any of the alternative services (currently only SPECIAL * services can be alternative services and SPECIAL services * are not included in the service table) */ } *countp = count ; return( refs ) ; }
/* * Remove an element from a pset */ void psi_remove( psi_h iter ) { if ( iter->current < pset_count( iter->pset ) ) { pset_remove_index( iter->pset, iter->current ) ; iter->step = 0; } }
/* They hit a real server...note, this is likely to be a child process. */ status_e check_sensor( const union xsockaddr *addr) { if ( (global_no_access) && pset_count( global_no_access ) ) { if (addrlist_match( global_no_access, SA(addr))) return FAILED; } return OK; }
/* * Apply a function to all pointers of a pset */ void pset_apply( register pset_h pset, void (*func)(), register void *arg ) { register unsigned u ; for ( u = 0 ; u < pset_count( pset ) ; u++ ) if ( arg ) (*func)( arg, pset_pointer( pset, u ) ) ; else (*func)( pset_pointer( pset, u ) ) ; }
static void dump_services( int fd ) { unsigned u ; /* * Dump the current configuration (services + defaults) */ Sprint( fd, "Services + defaults:\n" ) ; sc_dump( DEFAULTS( ps ), fd, 0, TRUE ) ; for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) svc_dump( SP( pset_pointer( SERVICES( ps ), u ) ), fd ) ; }
void ti_dump( pset_h iset, int fd ) { unsigned u ; for ( u = 0 ; u < pset_count( iset ) ; u++ ) { struct time_interval *tip = TIP( pset_pointer( iset, u ) ) ; Sprint( fd, " %02d:%02d-%02d:%02d", tip->min_start / 60, tip->min_start % 60, tip->min_end / 60, tip->min_end % 60 ) ; } }
/* * Returns only if there is an I/O error while communicating with the server */ static void di_mux(void) { struct intercept_s *ip = &dgram_intercept_state ; fd_set socket_mask ; int mask_max ; FD_ZERO( &socket_mask ) ; FD_SET( INT_REMOTE( ip ), &socket_mask ) ; mask_max = INT_REMOTE( ip ) ; for ( ;; ) { unsigned u ; channel_s *chp ; fd_set read_mask ; int n_ready ; read_mask = socket_mask ; n_ready = int_select( mask_max+1, &read_mask ) ; if ( n_ready == -1 ) return ; if ( FD_ISSET( INT_REMOTE( ip ), &read_mask ) ) { udp_remote_to_local( ip, &chp ) ; if ( chp != NULL ) { FD_SET( chp->ch_local_socket, &socket_mask ) ; if ( chp->ch_local_socket > mask_max ) mask_max = chp->ch_local_socket ; } if ( --n_ready == 0 ) continue ; } for ( u = 0 ; u < pset_count( INT_CONNECTIONS( ip ) ) ; u++ ) { chp = CHP( pset_pointer( INT_CONNECTIONS( ip ), u ) ) ; if ( FD_ISSET( chp->ch_local_socket, &read_mask ) ) { if ( udp_local_to_remote( chp ) == FAILED ) return ; if ( --n_ready == 0 ) break ; } } } }
/* Change the sets to arrays. */ foreach_irp_irg(i, irg) { pset *callee_set = (pset *)irg->callees; size_t count = pset_count(callee_set); irg->callees = NEW_ARR_F(cg_callee_entry *, count); irg->callee_isbe = NULL; size_t j = 0; foreach_pset(callee_set, cg_callee_entry, callee) { irg->callees[j++] = callee; } del_pset(callee_set); assert(j == count); pset *caller_set = (pset *)irg->callers; count = pset_count(caller_set); irg->callers = NEW_ARR_F(ir_graph *, count); irg->caller_isbe = NULL; j = 0; foreach_pset(caller_set, ir_graph, c) { irg->callers[j++] = c; } del_pset(caller_set); assert(j == count); }
/* xtimer_nexttime: * Returns the number of seconds until the next timer expires. * Returns -1 when no timers are active. */ time_t xtimer_nexttime(void) { time_t ret; if(xtimer_list == NULL) return -1; if( pset_count(xtimer_list) == 0 ) return -1; ret = ((xtime_h *)pset_pointer(xtimer_list, 0))->when - time(NULL) ; if( ret < 0 ) ret = 0; return( ret ); }
/* xtimer_remove: * Removes a timer from the list of timers. Takes the timer id as an argument * Returns: * Success: 0 * Failure: -1 */ int xtimer_remove(int xtid) { unsigned int i; int ret = -1; for( i = 0; i < pset_count( xtimer_list ); i++ ) { xtime_h *cur_timer = pset_pointer( xtimer_list, i ); if( cur_timer->xtid == xtid ) { pset_delete( xtimer_list, cur_timer ); free( cur_timer ); cur_timer = NULL; ret = 0; } } return(ret); }
/* * Returns TRUE if the current time is within at least one of the intervals */ bool_int ti_current_time_check( const pset_h intervals ) { time_t current_time ; unsigned u ; int16_t min_current ; struct tm *tmp ; (void) time( ¤t_time ) ; tmp = localtime( ¤t_time ) ; min_current = tmp->tm_hour * 60 + tmp->tm_min ; for ( u = 0 ; u < pset_count( intervals ) ; u++ ) { struct time_interval *tip ; tip = TIP( pset_pointer( intervals, u ) ) ; if ( IN_RANGE( min_current, tip->min_start, tip->min_end ) ) return( TRUE ) ; } return( FALSE ) ; }
/* xtimer_add: * Adds a timer to the pset_h of timers, and sorts the timer list (least time * remaining first). * Return values: * Success: the timer ID which can be used to later remove the timer (>0) * Failure: -1 */ int xtimer_add( void (*func)(void), time_t secs ) { xtime_h *new_xtimer = NULL; time_t tmptime; unsigned count; if( xtimer_list == NULL ) { if( xtimer_init() < 0 ) return -1; } new_xtimer = (xtime_h *)malloc(sizeof(xtime_h)); if( new_xtimer == NULL ) { return -1; } tmptime = time(NULL); if( tmptime == -1 ) { free( new_xtimer ); return -1; } new_xtimer->timerfunc = func; new_xtimer->when = tmptime + secs; if( (count = pset_count( xtimer_list )) == 0 ) { new_xtimer->xtid = 1; } else { new_xtimer->xtid = ((xtime_h *)(pset_pointer(xtimer_list, count-1)))->xtid + 1; } if( pset_add( xtimer_list, new_xtimer ) == NULL ) { free( new_xtimer ); return -1; } pset_sort( xtimer_list, xtimer_compfunc ); return(new_xtimer->xtid); }
static status_e update_env_with_strings( env_h env, pset_h strings ) { unsigned u ; const char *func = "update_env_with_strings" ; for ( u = 0 ; u < pset_count( strings ) ; u++ ) { char *p = (char *) pset_pointer( strings, u ) ; if ( env_addstr( env, p ) == ENV_ERR ) switch ( env_errno ) { case ENV_ENOMEM: out_of_memory( func ) ; return( FAILED ) ; case ENV_EBADSTRING: msg( LOG_ERR, func, "Bad environment string: %s", p ) ; break ; } } return( OK ) ; }
static status_e make_env_from_vars( struct environment *ep, env_h env, pset_h vars ) { env_h new_env ; char *varname ; unsigned u ; const char *func = "make_env_from_vars" ; if ( ( new_env = env_create( ENV_NULL ) ) == ENV_NULL ) { out_of_memory( func ) ; return( FAILED ) ; } for ( u = 0 ; u < pset_count( vars ) ; u++ ) { varname = (char *) pset_pointer( vars, u ) ; if ( env_addvar( new_env, env, varname ) == ENV_ERR ) switch ( env_errno ) { case ENV_EBADVAR: msg( LOG_ERR, func, "Unknown variable %s", varname ) ; break ; case ENV_ENOMEM: out_of_memory( func ) ; env_destroy( new_env ) ; return( FAILED ) ; } } ep->env_type = CUSTOM_ENV ; ep->env_handle = new_env ; return( OK ) ; }
static void consistency_check( enum check_type type ) { int fd ; fd_set socket_mask_copy ; unsigned u ; int errors ; unsigned total_running_servers = 0 ; unsigned total_retry_servers = 0 ; unsigned error_count = 0 ; bool_int service_count_check_failed = FALSE ; const char *func = "consistency_check" ; socket_mask_copy = ps.rws.socket_mask ; for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) { register struct service *sp = SP( pset_pointer( SERVICES( ps ), u ) ) ; char *sid = SVC_ID( sp ) ; unsigned running_servers ; unsigned retry_servers ; error_count += refcount_check( sp, &running_servers, &retry_servers ) ; if ( SVC_IS_AVAILABLE( sp ) || SVC_IS_DISABLED ( sp ) ) { /* * In this case, there may be some servers running */ if ( FD_ISSET( SVC_FD( sp ), &socket_mask_copy ) ) { if ( SVC_IS_DISABLED( sp ) ) { msg( LOG_ERR, func, "fd of disabled service %s still in socket mask", sid ) ; error_count++ ; } FD_CLR( SVC_FD( sp ), &socket_mask_copy ) ; } error_count += thread_check( sp, running_servers, retry_servers ) ; errors = service_count_check( sp, running_servers, retry_servers ) ; if ( ! errors && ! service_count_check_failed ) { total_retry_servers += retry_servers ; total_running_servers += running_servers ; } if ( errors ) { service_count_check_failed = TRUE ; error_count += errors ; } if ( SVC_IS_DISABLED( sp ) && SVC_RUNNING_SERVERS( sp ) == 0 ) { msg( LOG_ERR, func, "disabled service %s has 0 running servers\n", sid ) ; error_count++ ; continue ; } } else { msg( LOG_ERR, func, "service %s not started", SVC_ID( sp ) ) ; error_count++ ; } } if ( ! service_count_check_failed ) { if ( total_running_servers != pset_count( SERVERS( ps ) ) ) { msg( LOG_ERR, func, "total running servers (%d) != number of running servers (%d)", total_running_servers, pset_count( SERVERS( ps ) ) ) ; error_count++ ; } if ( total_retry_servers != pset_count( RETRIES( ps ) ) ) { msg( LOG_ERR, func, "total retry servers (%d) != number of retry servers (%d)", total_retry_servers, pset_count( RETRIES( ps ) ) ) ; error_count++ ; } } /* * Check if there are any descriptors set in socket_mask_copy */ for ( fd = 0 ; fd < ps.ros.max_descriptors ; fd++ ) if ( FD_ISSET( fd, &socket_mask_copy ) && ((fd != signals_pending[0]) && fd != signals_pending[1])) { msg( LOG_ERR, func, "descriptor %d set in socket mask but there is no service for it", fd ) ; error_count++ ; } if ( error_count != 0 ) msg( LOG_WARNING, func, "Consistency check detected %d errors", error_count ) ; else if ( type == USER_REQUESTED || debug.on ) msg( LOG_INFO, func, "Consistency check passed" ) ; if( type == PERIODIC ) if ( xtimer_add( periodic_check, ps.ros.cc_interval ) == -1 ) msg( LOG_ERR, func, "Failed to start consistency timer" ) ; }
/* * This function runs in the parent context and updates the global_no_access * list. */ void process_sensor( const struct service *sp, const union xsockaddr *addr) { const char *func = "process_sensor"; if (SC_DENY_TIME(SVC_CONF(sp)) != 0) /* 0 simply logs it */ { if ( pset_count( global_no_access ) < MAX_GLOBAL_NO_ACCESS) { int item_matched = addrlist_match( global_no_access, SA(addr) ); if ( item_matched == 0) { /* no match...adding to the list */ char *dup_addr = new_string(xaddrname( addr ) ); if (dup_addr == NULL ) return ; if (addrlist_add(global_no_access, dup_addr) == FAILED) msg(LOG_ERR, func, "Failed adding %s to the global_no_access list", dup_addr); else { time_t nowtime; char time_buf[40], *tmp; nowtime = time(NULL); msg(LOG_CRIT, func, "Adding %s to the global_no_access list for %d minutes", dup_addr, SC_DENY_TIME(SVC_CONF(sp))); if (SC_DENY_TIME(SVC_CONF(sp)) == -1) strcpy(time_buf, "-1"); else strx_nprint(time_buf, 38, "%ld", (time_t)nowtime+(60*SC_DENY_TIME(SVC_CONF(sp)))); tmp = new_string(time_buf); if (tmp != NULL) { if (pset_add(global_no_access_time, tmp) == NULL) { msg(LOG_ERR, func, "Failed adding %s to the global_no_access_time list. " "global_no_access list is broken, xinetd needs " "restarting.", dup_addr); /* ideally, we should rollback the previous addr addition. */ } } if (pset_count(global_no_access) && (timer_id == 0) ) timer_id = xtimer_add( scrub_global_access_list, 60 ); } free(dup_addr); } else { /* Here again, eh?...update time stamp. */ char *exp_time; time_t stored_time; item_matched--; /* Is # plus 1, to even get here must be >= 1 */ exp_time = pset_pointer( global_no_access_time, item_matched ) ; if (exp_time == NULL) return ; if ( parse_base10(exp_time, (int *)&stored_time) ) { /* if never let them off, bypass */ if (stored_time != -1) { time_t nowtime, new_time; nowtime = time(NULL); new_time = (time_t)nowtime+(60*SC_DENY_TIME(SVC_CONF(sp))); if (difftime(new_time, (time_t)stored_time) > 0.0) { /* new_time is longer save it */ char time_buf[40], *new_exp_time; strx_nprint(time_buf, 38, "%ld", (long)new_time); new_exp_time = new_string(time_buf); if ( new_exp_time ) { free(exp_time); global_no_access_time->ptrs[ (unsigned)item_matched ] = new_exp_time; } } } } } } else msg(LOG_ERR, func, "Maximum global_no_access count reached."); } }
static void tcpmux_handler( const struct server *serp ) { char svc_name[ BUFFER_SIZE ] ; int cc ; int descriptor = SERVER_FD( serp ) ; const struct service *svc = SERVER_SERVICE( serp ) ; unsigned u; struct service *sp = NULL; struct server server, *nserp; struct service_config *scp = NULL; close_all_svc_descriptors(); /* Read in the name of the service in the format "svc_name\r\n". * * XXX: should loop on partial reads (could probably use Sread() if * it wasn't thrown out of xinetd source code a few revisions back). */ do { cc = read( descriptor, svc_name, sizeof( svc_name ) ) ; } while (cc == -1 && errno == EINTR); if ( cc <= 0 ) { msg(LOG_ERR, "tcpmux_handler", "read failed"); exit(0); } if ( ( cc <= 2 ) || ( ( svc_name[cc - 1] != '\n' ) || ( svc_name[cc - 2] != '\r' ) ) ) { if ( debug.on ) msg(LOG_DEBUG, "tcpmux_handler", "Invalid service name format."); exit(0); } svc_name[cc - 2] = '\0'; /* Remove \r\n for compare */ if ( debug.on ) { msg(LOG_DEBUG, "tcpmux_handler", "Input (%d bytes) %s as service name.", cc, svc_name); } /* Search the services for the a match on name. */ for ( u = 0 ; u < pset_count( SERVICES( ps ) ) ; u++ ) { sp = SP( pset_pointer( SERVICES( ps ), u ) ) ; if ( strcasecmp( svc_name, SC_NAME( SVC_CONF( sp ) ) ) == 0 ) { /* Found the pointer. Validate its type. */ scp = SVC_CONF( sp ); /* if ( ! SVC_IS_MUXCLIENT( sp ) ) { if ( debug.on ) { msg(LOG_DEBUG, "tcpmux_handler", "Non-tcpmux service name: %s.", svc_name); } exit(0); } */ /* Send the accept string if we're a PLUS (+) client. */ if ( SVC_IS_MUXPLUSCLIENT( sp ) ) { if ( Swrite( descriptor, TCPMUX_ACK, sizeof( TCPMUX_ACK ) ) != sizeof( TCPMUX_ACK ) ) { msg(LOG_ERR, "tcpmux_handler", "Ack write failed for %s.", svc_name); exit(0); } } break; /* Time to get on with the service */ } continue; /* Keep looking */ } if ( u >= pset_count( SERVICES( ps ) ) ) { if ( debug.on ) { msg(LOG_DEBUG, "tcpmux_handler", "Service name %s not found.", svc_name); } exit(0); } if( SVC_WAITS( svc ) ) /* Service forks, so close it */ Sclose(descriptor); server.svr_sp = sp; server.svr_conn = SERVER_CONNECTION(serp); nserp = server_alloc(&server); if( SC_IS_INTERNAL( scp ) ) { SC_INTERNAL(scp, nserp); } else { exec_server(nserp); } }
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 ) ; }
void dump_internal_state(void) { int dump_fd ; const char *dump_file = DUMP_FILE ; time_t current_time ; int fd ; unsigned u ; const char *func = "dump_internal_state" ; if ( debug.on ) msg( LOG_DEBUG, func, "Dumping State" ) ; dump_fd = open( dump_file, O_WRONLY | O_CREAT | O_APPEND, DUMP_FILE_MODE); if ( dump_fd == -1 ) { msg( LOG_ERR, func, "failed to open %s: %m", dump_file ) ; return ; } if (Sbuftype( dump_fd, SIO_LINEBUF ) == SIO_ERR ) { /* * If the above function failed, Sprint will most likely * fail, too. Output a message for troubleshooting and quit. */ msg( LOG_ERR, func, "failed setting up sio buffering: %m" ) ; return; } /* * Print the program name, version, and timestamp. * Note that the program_version variable contains the program name. */ (void) time( ¤t_time ) ; Sprint( dump_fd, "INTERNAL STATE DUMP: %s\n", program_version ) ; Sprint( dump_fd, "Current time: %s\n", ctime( ¤t_time ) ) ; dump_services( dump_fd ) ; /* * Dump the server table */ Sprint( dump_fd, "Server table dump:\n" ) ; for ( u = 0 ; u < pset_count( SERVERS( ps ) ) ; u++ ) server_dump( SERP( pset_pointer( SERVERS( ps ), u ) ), dump_fd ) ; Sputchar( dump_fd, '\n' ) ; /* * Dump the retry_table */ Sprint( dump_fd, "Retry table dump:\n" ) ; for ( u = 0 ; u < pset_count( RETRIES( ps ) ) ; u++ ) server_dump( SERP( pset_pointer( RETRIES( ps ), u ) ), dump_fd ) ; Sputchar( dump_fd, '\n' ) ; /* * Dump the socket mask */ Sprint( dump_fd, "Socket mask:" ) ; for ( fd = 0 ; fd < ps.ros.max_descriptors ; fd++ ) if ( FD_ISSET( fd, &ps.rws.socket_mask ) ) Sprint( dump_fd, " %d", fd ) ; Sputchar( dump_fd, '\n' ) ; Sprint( dump_fd, "mask_max = %d\n", ps.rws.mask_max ) ; /* * Dump the descriptors that are open and are *not* in the socket mask */ Sprint( dump_fd, "Open descriptors (not in socket mask):" ) ; for ( fd = 0 ; fd < ps.ros.max_descriptors ; fd++ ) { struct stat st ; if ( FD_ISSET( fd, &ps.rws.socket_mask ) ) continue ; if ( fstat( fd, &st ) == -1 ) continue ; Sprint( dump_fd, " %d", fd ) ; } Sputchar( dump_fd, '\n' ) ; Sputchar( dump_fd, '\n' ) ; Sprint( dump_fd, "active_services = %d\n", ps.rws.active_services ) ; Sprint( dump_fd, "available_services = %d\n", ps.rws.available_services ) ; Sprint( dump_fd, "descriptors_free = %d\n", ps.rws.descriptors_free ) ; Sprint( dump_fd, "running_servers = %d\n", pset_count( SERVERS( ps ) ) ) ; Sprint( dump_fd, "Logging service = %s\n", LOG_SERVICE( ps ) != NULL ? "enabled" : "not enabled" ) ; Sputchar( dump_fd, '\n' ) ; Sprint( dump_fd, "max_descriptors = %d\n", (int)ps.ros.max_descriptors ) ; Sprint( dump_fd, "process_limit = %d\n", (int)ps.ros.process_limit ) ; Sprint( dump_fd, "config_file = %s\n", ps.ros.config_file ) ; if ( debug.on ) Sprint( dump_fd, "debug_fd = %d\n", debug.fd ) ; Sputchar( dump_fd, '\n' ) ; Sprint( dump_fd, "END OF DUMP\n\n" ) ; Sclose( dump_fd ); msg( LOG_INFO, func, "generated state dump in file %s", dump_file ) ; }
/* * Identify the attribute in <attr_name>. * * Check if * 1) the attribute has been defined already * 2) the value count is correct * 3) the assign op is appropriate * * Invoke appropriate parser. * * This function will return FAILED only if its in the default section * and an attribute cannot be ID'd. Otherwise, it returns OK. */ static status_e identify_attribute( entry_e entry_type, struct service_config *scp, const char *attr_name, enum assign_op op, pset_h attr_values ) { const struct attribute *ap ; const char *func = "identify_attribute" ; if ( entry_type == SERVICE_ENTRY ) ap = attr_lookup( service_attributes, attr_name ) ; else ap = attr_lookup( default_attributes, attr_name ) ; if ( ap == NULL ) return OK; /* We simply ignore keywords not on the list */ if ( ! MODIFIABLE( ap ) ) { if ( SC_SPECIFIED( scp, ap->a_id ) ) { parsemsg( LOG_WARNING, func, "Service %s: attribute already set: %s", SC_NAME(scp), attr_name ) ; return OK; } if ( op != SET_EQ ) { parsemsg( LOG_WARNING, func, "Service %s: operator '%s' cannot be used for attribute '%s'", SC_NAME(scp), ( op == PLUS_EQ ) ? "+=" : "-=", attr_name ) ; return OK; } } else /* modifiable attribute */ { /* * For the defaults entry, '=' and '+=' have the same meaning */ if ( entry_type == DEFAULTS_ENTRY && op == SET_EQ ) op = PLUS_EQ ; } if ( FIXED_VALUES( ap ) && (unsigned)ap->a_nvalues != pset_count( attr_values ) ) { parsemsg( LOG_WARNING, func, "attribute %s expects %d values and %d values were specified", attr_name, ap->a_nvalues, pset_count( attr_values ) ) ; return OK; } if ( (*ap->a_parser)( attr_values, scp, op ) == OK ) { /* This is the normal path. */ SC_SPECIFY( scp, ap->a_id ) ; } else if ( entry_type == SERVICE_ENTRY ) { parsemsg( LOG_ERR, func, "Error parsing attribute %s - DISABLING SERVICE", attr_name ) ; SC_DISABLE( scp ); } /* * We are in the default section and an error was detected. At * this point, we should terminate since whatever attribute * was trying to be specified cannot be propagated. */ else if ( !debug.on ) return FAILED; return OK; }