Beispiel #1
0
static int get_num( int *nump, 
                       int min_val, 
                       int max_val, 
                       const char *s, 
                       char stop_char )
{
   const char *func = "get_num" ;
   int i = 0;

   for ( *nump = 0 ; isdigit( s[i] ) ; i++ )
   {
      *nump *= 10 ;
      *nump += s[i] - '0' ;
   }

   if ( s[i] != stop_char )
   {
      parsemsg( LOG_ERR, func, "incorrect time interval" ) ;
      return( -1 );
   }

   if ( ! IN_RANGE( *nump, min_val, max_val ) )
   {
      parsemsg( LOG_ERR, func, "invalid time interval" ) ;
      return( -1 ) ;
   }
   return( i ) ;
}
Beispiel #2
0
/*
 * Input:
 *      a line of the form
 *            name [SPACE] OP [SPACE] value [SPACE] value ...
 *
 * Recognize the attribute name and operator and place them in *attrp, *opp
 *
 * Currently, we allow any non-space character to be used in the
 * attribute name.
 *
 * Return value: a pointer to the character after OP.
 */
static char *get_attr_op( char *line, char **attrp, enum assign_op *opp )
{
   char            *p ;
   char            *attr ;
   enum assign_op   op ;
   const char      *func = "get_attr_op" ;

   /*
    * First get the attribute name
    */
   for ( p = line ; isspace( *p ) ; p++ ) ;      /* skip spaces */
   if ( *p == NUL )
   {
      parsemsg( LOG_ERR, func, "Empty line" ) ;
      return( NULL ) ;
   }

   attr = p ;
   for ( ; ! isspace( *p ) && (*p != '='); p++ ) ;            /* skip attribute name */
   if ( *p == NUL )
   {
      parsemsg( LOG_ERR, func, "Nothing after attribute: %s", attr ) ;
      return( NULL ) ;
   }
   if( *p == '=' ) {
      *p = NUL ;         /* now attribute name is NUL terminated */
      parsemsg( LOG_ERR, func, "Attribute %s needs a space before operator", attr);
      return( NULL ) ;
   }
   *p++ = NUL ;         /* now attribute name is NUL terminated */

   while ( isspace( *p ) ) p++ ;      /* skip spaces */

   switch ( *p )
   {
      case NUL:
         parsemsg( LOG_ERR, func, "Nothing after attribute: %s", attr ) ;
         return( NULL ) ;
   
      case '=':
         op = SET_EQ ;
         break ;
      
      case '+':
      case '-':
         op = ( *p++ == '+' ) ? PLUS_EQ : MINUS_EQ ;
         if ( *p == '=' )
            break ;
         
         /* FALL THROUGH if there is no '=' after the '+' or '-' */
      
      default:
         parsemsg( LOG_ERR, func, "Bad operator for attribute: %s", attr ) ;
         return( NULL ) ;
   }
   *attrp = attr ;
   *opp = op ;
   return( ++p ) ;      /* skip the '=' */
}
Beispiel #3
0
terpmes ()
{ char mess[128];
  register char *m, *mend, *s = screen[0], *t;

  int i;

  /* Set 't' to the tail of the message, skip backward over blank & dot */  
  for (t=s+79; *t==' ' || *t=='.'; t--) ;	/* Find last non-blank */
  t++;						/* t -> beyond string */
  
  /* 
   * Loop through each message, finding the beginning and end, and 
   * copying it to mess, lower-casing it as we go. Then call parsemsg.
   */
 
  while (s<t)				      /* While more chars in msg */
  { while (*s==' ' && s<t) s++;			/* Skip leading blanks */
    for (m = mess;				/* Copy text */
	 s<t && (version < RV53A || *s != '.' || s[1] != ' ');
	 s++)	
      *m++ = isupper (*s) ? tolower (*s) : *s;	  /* Lower case the char */
    s++;					/* Skip the period, if any */
    *(mend = m) = '\0';				/* Add trailing null */
    if (mess != mend) parsemsg (mess, mend);	/* Parse it */
  }
}
Beispiel #4
0
/*
 * Find the attribute with the specified name
 */
static const struct attribute *attr_lookup(
    const struct attribute attr_array[], const char *attr_name )
{
    const struct attribute *ap ;
    const char *func = "attr_lookup" ;

    for ( ap = &attr_array[ 0 ] ; ap->a_name ; ap++ )
        if ( EQ( attr_name, ap->a_name ) )
            return ap;
    if ( attr_array == service_attributes )
        parsemsg( LOG_WARNING, func, "bad service attribute: %s", attr_name ) ;
    else
        parsemsg( LOG_WARNING, func,
                  "attribute: %s should not be in default section", attr_name ) ;
    return NULL;
}
Beispiel #5
0
/*
 * 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 ) ;
}
Beispiel #6
0
/*
 * 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 ) ;
}
Beispiel #7
0
/*
 * Read the entry line-by-line and add the information in scp
 * Use defaults to initialize modifiable entry fields.
 */
static status_e parse_entry( entry_e entry_type,
                             int fd,
                             struct service_config *scp )
{
    static pset_h      attr_values = NULL;
    char               *line ;
    char               *attr_name ;
    enum assign_op      op ;
    const char         *func = "parse_entry" ;

    if ( ! attr_values && ( attr_values = pset_create( 10, 10 ) ) == NULL )
    {
        out_of_memory( func ) ;
        return( FAILED ) ;
    }

    for ( ;; )
    {
        line = next_line( fd ) ;
        if ( line == CHAR_NULL )
        {
            parsemsg( LOG_ERR, func, "incomplete entry" ) ;
            return( FAILED ) ;
        }

        if ( line_has_only_1_char( line, ENTRY_END ) )
            return( OK ) ;

        if ( parse_line( line, &attr_name, &op, attr_values ) == FAILED )
        {
            pset_clear( attr_values ) ;
            return( FAILED ) ;
        }

        if (identify_attribute( entry_type,
                                scp, attr_name, op, attr_values ) == FAILED )
        {
            /*
             * An error was detected in the default section. We will terminate
             * since whatever attribute being specified cannot be propagated.
             */
            msg(LOG_ERR, func,
                "A fatal error was encountered while parsing the default section."
                " xinetd will exit.");
            Sclose( fd );
            terminate_program();
        }
        pset_clear( attr_values ) ;
    }
}
Beispiel #8
0
void skip_entry( int fd )
{
   for ( ;; )
   {
      char *line = next_line( fd ) ;

      if ( line == NULL )         /* reached EOF ? */
      {
         parsemsg( LOG_WARNING, "skip_entry",
            "missing %c in last service entry", ENTRY_END ) ;
         break ;
      }

      if ( line_has_only_1_char( line, ENTRY_END ) )
         break ;
   }
}
Beispiel #9
0
int
main (int argc, char *argv[])
{
  char		*l    = NULL;
  message_t	*cmsg = NULL;
  command_t	*ccmd = NULL;
  settings_t	 global_settings;

  settings		   = &global_settings;
  settings->execname	   = argv[0];
  settings->action_trigger = '`';	/* default trigger char */
  settings->verbose	   = false;
  settings->socket	   = NULL;
  
  logstr ("Radroach here\n");
  register_signals ();
  if (configure (argc, argv))
    exit (EXIT_FAILURE);
  logstr ("trusted users are: %s\n", settings->trusted);
  if (settings->aj_list)
    logstr ("channels to join: %s\n", settings->aj_list);
  server_connect (settings->host);
  setup ();
  plugins_load ("./plugins/");

  while ((l = sogetline ()) != NULL)
    {
      if (p_response (l))
	continue;
      cmsg = parsemsg (l);
      if (cmsg != NULL)
        {
          ccmd = parsecmd (cmsg->msg);
          if (ccmd != NULL)
            execute (cmsg, ccmd);
        }
      else
	free (l);
    }
  return EXIT_SUCCESS;
}
Beispiel #10
0
/*
 * 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;
}
Beispiel #11
0
/*
 * Find the next service entry.
 * Look for a line of the form:
 *
 *      <white-space> service <white-space> <service_name>
 *
 * followed by a line containing only the ENTRY_BEGIN character
 */
static entry_e find_next_entry( int fd, char **snamep )
{
    char           *p ;
    str_h           strp ;
    char           *sname = NULL;
    entry_e         entry_type=0;
    char           *line = next_line( fd ) ;
    const char     *func = "find_next_entry" ;

    if ( line == CHAR_NULL )
        return( NO_ENTRY ) ;

    strp = str_parse( line, " \t", STR_RETURN_ERROR, INT_NULL ) ;
    if ( strp == NULL )
    {
        parsemsg( LOG_CRIT, func, "str_parse failed" ) ;
        return( BAD_ENTRY ) ;
    }

    if ( ( p = str_component( strp ) ) == CHAR_NULL )
    {
        /*
         * This shouldn't happen since it implies that there is a bug
         * in next_line
         */
        parsemsg( LOG_WARNING, func, "empty line" ) ;
        str_endparse( strp ) ;
        return( BAD_ENTRY ) ;
    }

    /*
     * Look for a keyword
     */
    if ( EQ( p, KW_SERVICE ) || EQ( p, KW_INCLUDE ) || EQ(p, KW_INCLUDEDIR))
    {
        if ( EQ( p, KW_INCLUDE ))
            entry_type = INCLUDE_ENTRY;
        else if ( EQ( p, KW_INCLUDEDIR ))
            entry_type = INCLUDEDIR_ENTRY;

        /*
         * Now get the service name
         */
        if ( ( p = str_component( strp ) ) == CHAR_NULL )
        {
            parsemsg( LOG_ERR, func, "service name missing" ) ;
            str_endparse( strp ) ;
            return( BAD_ENTRY ) ;
        }

        sname = new_string( p ) ;
        if ( sname == CHAR_NULL )
        {
            out_of_memory( func ) ;
            str_endparse( strp ) ;
            return( BAD_ENTRY ) ;
        }
        str_endparse( strp ) ;

        if( (entry_type == INCLUDE_ENTRY) ||
                (entry_type == INCLUDEDIR_ENTRY))
        {
            *snamep = sname ;
            return( entry_type ) ;
        }
        else
            entry_type = SERVICE_ENTRY ;
    }
    else if ( EQ( p, KW_DEFAULTS ) )
    {
        str_endparse( strp ) ;
        entry_type = DEFAULTS_ENTRY ;
    }
    else
    {
        parsemsg( LOG_ERR, func, "missing service keyword" ) ;
        str_endparse( strp ) ;
        return( BAD_ENTRY ) ;
    }

    /*
     * Now look for ENTRY_BEGIN
     */
    line = next_line( fd ) ;
    if ( line == NULL || ! line_has_only_1_char( line, ENTRY_BEGIN ) )
    {
        parsemsg( LOG_ERR, func,
                  "Service %s: missing '%c'", sname, ENTRY_BEGIN ) ;
        if ( entry_type == SERVICE_ENTRY )
            free( sname ) ;
        return( BAD_ENTRY ) ;
    }
    *snamep = sname ;
    return( entry_type ) ;
}
Beispiel #12
0
/*
 * Read the configuration file (descriptor fd) and place all
 * services found there in the configuration.
 */
void parse_conf_file( int fd, struct configuration *confp, const char *filename)
{
    pset_h                   sconfs       = CNF_SERVICE_CONFS( confp ) ;
    struct service_config   *default_config   = CNF_DEFAULTS( confp ) ;
    boolean_e                found_defaults   = NO ;
    struct service_config    default_default_config ;
    const char              *func      = "parse_conf_file" ;
    int                      incfd;

    line_count = 0 ;
    current_file = filename;
    CLEAR( default_default_config ) ;

    for ( ;; )
    {
        entry_e   entry_type ;
        char      *service_name  = NULL;

        /*
         * if find_next_entry is successful, service_name
         * will point to malloc'ed memory
         */
        entry_type = find_next_entry( fd, &service_name ) ;
        switch ( entry_type )
        {
        case INCLUDE_ENTRY:
        {
            int saved_line_count = line_count;
            incfd = open(service_name, O_RDONLY);
            if( incfd < 0 ) {
                parsemsg( LOG_ERR, func,
                          "Unable to open included configuration file: %s",
                          service_name);
                break;
            }
            parsemsg( LOG_DEBUG,func,
                      "Reading included configuration file: %s",service_name);
            parse_conf_file(incfd, confp, service_name);
            /*
             * parse_conf_file eventually calls Srdline, try Sclosing it
             * to unmmap memory.
             */
            Sclose(incfd);
            /* Restore since we've returned from included file */
            current_file = filename;
            line_count = saved_line_count;
        }
        break;
        case INCLUDEDIR_ENTRY:
        {
            int saved_line_count = line_count;
            handle_includedir(service_name, confp);
            current_file = filename;
            line_count = saved_line_count;
        }
        break;
        case SERVICE_ENTRY:
            get_service_entry( fd, sconfs, service_name, default_config ) ;
            break ;
        case DEFAULTS_ENTRY:
            if ( found_defaults == YES )
            {
                parsemsg( LOG_ERR, func,
                          "only 1 defaults entry is allowed. This entry will be ignored" ) ;
                skip_entry( fd ) ;
            }
            else if ( parse_entry( DEFAULTS_ENTRY, fd,
                                   default_config ) == OK ) {
                found_defaults = YES ;
                /*
                 * We must check bind_address to see if it was deferred.
                 */
                if (SC_SPECIFIED( default_config, A_BIND) &&
                        SC_BIND_ADDR(default_config) == NULL)
                    M_CLEAR( default_config->sc_specified_attributes, A_BIND ) ;
            }
            break ;

        case BAD_ENTRY:
            skip_entry( fd ) ;
            break ;

        case NO_ENTRY:
            return ;
        }
        if (service_name)
            free(service_name);
    }
}
Beispiel #13
0
int main(int argc, char *argv[]){
  int sockfd, numbytes, childproc;
  int y, x , i , L, index;
  char *msg, *user, *buffer = (char*) malloc((USERNAMESIZE + MAXDATASIZE + 4)*sizeof(char));
  char *addr = NULL;
    if(argc >= 2){
      addr=argv[1];
	}
  sockfd=socksetup(addr);

    user=startscreen();
    L=strlen(user);

	//  SETTING UP ncurses WINDOWS
        WINDOW *in, *out;
        initscr();
        cbreak();
	echo();
        in = newwin(4, 0, LINES-4, 0);
        out = newwin(LINES-4, 0, 0, 0);
	scrollok(in, TRUE);
	scrollok(out, TRUE);


  childproc = fork();

  if(childproc >= 0){
    if(childproc > 0){	 //RECEIVING MESSAGES
      while((numbytes = recv(sockfd, buffer, (USERNAMESIZE + MAXDATASIZE + 4), 0)) >0) {
		if(0 < strlen(buffer)){
                  index=getuser(buffer);
                  wattron(out, A_BOLD);
                  for(i=0;i<index;i++)
                    wprintw(out, "%c", buffer[i]);
                  wattroff(out, A_BOLD);
                  wprintw(out, "%s\n", buffer + index);
                }
	    wrefresh(out);
	    wrefresh(in);
	    wmove(in, 0, 0);
        }
      } else	 	//SENDING MESSAGES
    while(1){
        mvwgetstr(in,0, 0, buffer);
	wmove(in, 0, 0);
        werase(in);
        wrefresh(in);
        msg=parsemsg(user, buffer, L);
         if (send(sockfd, msg, MAXDATASIZE + USERNAMESIZE + 4, 0) == -1)
		close(sockfd);
         }
  }

wgetch(in);
delwin(in);
delwin(out);
endwin();

  close(sockfd);
  free(buffer);

return 0;
}
Beispiel #14
0
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;
}