/* * Each interval should have the form: * hour:min-hour:min * Example: 2:30-4:15 */ status_e ti_add( pset_h iset, const char *interval_str ) { struct time_interval *tip ; int hours ; int minutes ; int min_start ; int min_end ; int p, r = 0 ; const char *func = "add_interval" ; while (interval_str[r] == ' ') r++; /* Eat white space */ if ( ( p = get_num( &hours, 0, 23, interval_str+r, ':' ) ) == -1 ) return( FAILED ) ; r += p; r++; /* Get past : */ if ( ( p = get_num( &minutes, 0, 59, interval_str+r, '-' ) ) == -1 ) return( FAILED ) ; min_start = hours * 60 + minutes ; r += p; r++; /* Get past - */ if ( ( p = get_num( &hours, 0, 23, interval_str+r, ':' ) ) == -1 ) return( FAILED ) ; r += p; r++; /* Get past : */ if ( get_num( &minutes, 0, 59, interval_str+r, NUL ) == -1 ) return( FAILED ) ; min_end = hours * 60 + minutes ; if ( min_start >= min_end ) { parsemsg( LOG_ERR, func, "invalid time interval: %s", interval_str ) ; return( FAILED ) ; } tip = NEW_TI() ; if ( tip == NULL ) { out_of_memory( func ) ; return( FAILED ) ; } tip->min_start = min_start ; tip->min_end = min_end ; if ( pset_add( iset, tip ) == NULL ) { FREE_TI( tip ) ; out_of_memory( func ) ; return( FAILED ) ; } return( OK ) ; }
/* 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); }
/* * Parse a line of the form: * name OP value value value ... * where each value is a string and OP can be '=', '+=', '-=' * * NOTE: We do not allocate space for the name and values. Instead we keep * pointers to the line. */ status_e parse_line( char *line, char **namep, enum assign_op *opp, pset_h values ) { char *value ; char *values_string ; char *attribute ; str_h strp ; const char *func = "parse_line" ; if ( ( values_string = get_attr_op( line, &attribute, opp ) ) == NULL ) return( FAILED ) ; /* * Now grab the values */ strp = str_parse( values_string, " \t", STR_RETURN_ERROR, (int *)0 ) ; if ( strp == NULL ) { parsemsg( LOG_CRIT, func, ES_NOMEM ) ; return( FAILED ) ; } while ( (value = str_component( strp )) ) { if ( pset_add( values, value ) == NULL ) { parsemsg( LOG_CRIT, func, ES_NOMEM ) ; str_endparse( strp ) ; return( FAILED ) ; } } str_endparse( strp ) ; *namep = attribute ; return( OK ) ; }
/* * 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; }
/* * 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."); } }