Exemplo n.º 1
0
Arquivo: child.c Projeto: aosm/xinetd
/*
 * This function is invoked in a forked process to run a server. 
 * If the service is internal the appropriate function is invoked
 * otherwise the server program is exec'ed.
 * This function also logs the remote user id if appropriate
 */
void child_process( struct server *serp )
{
   struct service          *sp  = SERVER_SERVICE( serp ) ;
   connection_s            *cp  = SERVER_CONNECTION( serp ) ;
   struct service_config   *scp = SVC_CONF( sp ) ;
   const char              *func = "child_process" ;

   signal_default_state();

   if ((signals_pending[0] >= 0 && Sclose(signals_pending[0])) ||
       (signals_pending[1] >= 0 && Sclose(signals_pending[1])))
   {
      msg(LOG_ERR, func, "Failed to close the signal pipe: %m");
      _exit(1);
   }
   signals_pending[0] = -1;
   signals_pending[1] = -1;

   Sclose(0);
   Sclose(1);
   Sclose(2);


#ifdef DEBUG_SERVER
   if ( debug.on )
   {
      msg( LOG_DEBUG, func, "Process %d is sleeping", getpid() ) ;
      sleep( 10 ) ;
   }
#endif

   if ( ! SC_IS_INTERCEPTED( scp ) )
   {
      set_credentials( scp ) ;
      if ( SC_SPECIFIED( scp, A_NICE ) )
         (void) nice( SC_NICE( scp ) ) ;
   }

   if ( svc_child_access_control(sp, cp) != OK )
      exit(0);

   if ( SERVER_LOGUSER( serp ) )
   {
      unsigned   timeout ;
      idresult_e result ;
      
      /*
       * We use LOGUSER_SUCCESS_TIMEOUT unless the service requires
       * identification, in which case we use an infinite timeout
       */
      timeout = SC_MUST_IDENTIFY( scp ) ? 0 : LOGUSER_SUCCESS_TIMEOUT ;
      result = log_remote_user( serp, timeout ) ;

      if ( result != IDR_OK && SC_MUST_IDENTIFY( scp ) )
      {
         svc_logprint( sp, NOID_ENTRY, "%s %s",
                  conn_addrstr( SERVER_CONNECTION( serp ) ),
                     idresult_explain( result ) ) ;
         _exit( 0 ) ;
      }
   }

#ifdef HAVE_SESSIONCREATE
   if ( scp->sc_sessioncreate == YES ) 
   {
      if ( SessionCreate(0, sessionHasTTY|sessionIsRemote) != noErr )
         svc_logprint( sp, "SessionCreate", "SessionCreate() failed!" );
   }
#endif

   /* this is where the server gets executed  -bbraun */
   if ( ! SC_IS_INTERNAL( scp ) )
   {
      if( scp->sc_redir_addr != NULL )
      {
         redir_handler( serp );
      }
      else
      {
#if defined(HAVE_SETENV)
         char buff[1024];

         strx_sprint(buff, sizeof(buff)-1, "REMOTE_HOST=%s", conn_addrstr(cp));
         if( env_addstr(SC_ENV(scp)->env_handle, buff) != ENV_OK ) {
            msg( LOG_ERR, func, "Error adding REMOTE_HOST variable for %s: %m", SC_NAME(scp) );
            _exit( 1 ) ;
         }
#endif
         exec_server( serp ) ;
      }
   }
   else
   {
      char name[ 180 ] ;
      /*
       * We don't bother to disassociate from the controlling terminal
       *   (we have a controlling terminal only if debug.on is TRUE)
       *
       * Also, for interceptor processes, we give them the name:
       *            <program_name> <service-id> interceptor
       */
      if ( SC_IS_INTERCEPTED( scp ) )
         strx_print( INT_NULL, name, sizeof( name ) - 1,
                           "%s %s interceptor", program_name, SC_ID( scp ) ) ;
      else
      {
         int namelen = sizeof( name ) - 1 ;      /* leave space for the NUL */
         char host[NI_MAXHOST];
         size_t hostlen = NI_MAXHOST;
         socklen_t addrlen = 0;
         union xsockaddr *sinp = CONN_XADDRESS(SERVER_CONNECTION(serp));
         int len;

         if( sinp == NULL )
            exit(0);

         if( SC_IPV6(scp) ) addrlen = sizeof(struct sockaddr_in6);
         else if( SC_IPV4(scp) ) addrlen = sizeof(struct sockaddr_in);

         len = strx_nprint(name, namelen, "(%s service) %s", program_name,
            SC_ID( scp ) ) ;

         if( getnameinfo( SA(sinp), addrlen, host, hostlen, NULL, 0, 0) != 0 )
               strcpy(host, "unknown");

         if ( SC_IPV6(scp) && SC_ACCEPTS_CONNECTIONS( scp ) && 
               !IN6_IS_ADDR_UNSPECIFIED(&sinp->sa_in6.sin6_addr) )
            strx_print( INT_NULL, &name[ len ], namelen - len, " %s" , host ) ;
         if ( SC_IPV4(scp) && SC_ACCEPTS_CONNECTIONS( scp ) )
            strx_print( INT_NULL, &name[ len ], namelen - len, " %s", host ) ;
      }
      rename_process( name ) ;
      SVC_INTERNAL( sp, serp ) ;
   }
   _exit( 0 ) ;
   /* NOTREACHED */
}
Exemplo n.º 2
0
/*
 * This function always runs in a forked process.
 */
idresult_e log_remote_user( const struct server *serp, unsigned timeout )
{
    static char         buf[ IBUFSIZE ] ;
    int                 cc ;
    union xsockaddr     sin_local, sin_remote, sin_contact, sin_bind;
    volatile unsigned   local_port;
    volatile unsigned   remote_port;
    int                 sd ;
    socklen_t           sin_len ;
    char               *p ;
    const char         *func = "log_remote_user" ;

    if ( timeout && signal( SIGALRM, sigalrm_handler ) == SIG_ERR )
    {
        msg( LOG_ERR, func, "signal: %m" ) ;
        return( IDR_ERROR ) ;
    }

    /*
     * Determine local and remote addresses
     */
    sin_len = sizeof( sin_local ) ;
    if ( getsockname( SERVER_FD( serp ), &sin_local.sa, &sin_len ) == -1 )
    {
        msg( LOG_ERR, func, "(%d) getsockname: %m", getpid() ) ;
        return( IDR_ERROR ) ;
    }

    if ( CONN_XADDRESS( SERVER_CONNECTION( serp ) ) == NULL )
    {
        /*
         * This shouldn't happen since identification only works for
         * connection-based services.
         */
        msg( LOG_ERR, func, "connection has no address" ) ;
        return( IDR_ERROR ) ;
    }

    CLEAR( sin_contact );
    sin_remote = *CONN_XADDRESS( SERVER_CONNECTION( serp ) ) ;
    sin_contact = sin_remote;
    memcpy( &sin_bind, &sin_local, sizeof(sin_bind) ) ;
    local_port = 0;
    remote_port = 0;
    if( sin_remote.sa.sa_family == AF_INET ) {
        local_port = ntohs( sin_local.sa_in6.sin6_port ) ;
        remote_port = ntohs( sin_remote.sa_in6.sin6_port ) ;
        sin_contact.sa_in6.sin6_port = htons( IDENTITY_SERVICE_PORT ) ;
        sin_bind.sa_in.sin_port = 0 ;
    } else if( sin_remote.sa.sa_family == AF_INET6 ) {
        local_port = ntohs( sin_local.sa_in.sin_port ) ;
        remote_port = ntohs( sin_remote.sa_in.sin_port ) ;
        sin_contact.sa_in.sin_port = htons( IDENTITY_SERVICE_PORT ) ;
        sin_bind.sa_in6.sin6_port = 0 ;
    }

    /*
     * Create a socket, bind it, and set the close-on-exec flag on the
     * descriptor. We set the flag in case we are called as part of a
     * successful attempt to start a server (i.e. execve will follow).
     * The socket must be bound to the receiving address or ident might
     * fail for multi-homed hosts.
     */
    sd = socket( sin_remote.sa.sa_family, SOCK_STREAM, 0 ) ;
    if ( sd == -1 )
    {
        msg( LOG_ERR, func, "socket creation: %m" ) ;
        return( IDR_ERROR ) ;
    }
    if ( bind(sd, &sin_bind.sa, sizeof(sin_bind.sa)) == -1 )
    {
        msg( LOG_ERR, func, "socket bind: %m" ) ;
        (void) Sclose( sd ) ;
        return( IDR_ERROR ) ;
    }
    if ( fcntl( sd, F_SETFD, FD_CLOEXEC ) == -1 )
    {
        msg( LOG_ERR, func, "fcntl F_SETFD: %m" ) ;
        (void) Sclose( sd ) ;
        return( IDR_ERROR ) ;
    }

    if ( timeout ) {
        if ( sigsetjmp( env, 1 ) == 0 )
            START_TIMER( timeout ) ;
        else {
            Sclose( sd ) ;
            return( IDR_TIMEDOUT ) ;
        }
    }

    if ( connect( sd, &sin_contact.sa, sizeof( sin_contact ) ) == -1 )
    {
        if ( timeout ) {
            STOP_TIMER() ;
            signal ( SIGALRM, SIG_DFL ) ;
        }
        Sclose( sd );
        return( IDR_NOSERVER ) ;
    }

    cc = strx_nprint( buf, sizeof( buf ),
                      "%d,%d\r\n", remote_port, local_port ) ;
    if ( write_buf( sd, buf, cc ) == FAILED )
    {
        if ( timeout ) {
            STOP_TIMER() ;
            signal ( SIGALRM, SIG_DFL ) ;
        }
        Sclose( sd );
        return( IDR_ERROR ) ;
    }

    p = get_line( sd, buf, sizeof( buf ) ) ;

    if ( timeout ) {
        STOP_TIMER() ;
        signal ( SIGALRM, SIG_DFL ) ;
    }

    if ( p == NULL ) {
        Sclose( sd );
        return( IDR_RESPERR ) ;
    }

    /*
     * Verify that the received line is OK
     */
    if ( ( p = verify_line( buf, local_port, remote_port ) ) == NULL )
    {
        msg(LOG_ERR, func, "Bad line received from identity server at %s: %s",
            xaddrname( &sin_remote ), buf ) ;
        Sclose( sd );
        return( IDR_BADRESP ) ;
    }

    svc_logprint( SERVER_CONNSERVICE( serp ), USERID_ENTRY, "%s", p ) ;
    return( IDR_OK ) ;
}