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 gets called from child.c after we have been forked */
void redir_handler( struct server *serp )
{
   struct service *sp = SERVER_SERVICE( serp );
   struct service_config *scp = SVC_CONF( sp );
   int RedirDescrip = SERVER_FD( serp );
   int maxfd, num_read, num_wrote=0, ret=0;
   unsigned int sin_len = 0;
   unsigned long bytes_in = 0, bytes_out = 0;
   int no_to_nagle = 1;
   int on = 1, v6on;
   char buff[NET_BUFFER];
   fd_set rdfd, msfd;
   struct timeval *timep = NULL;
   const char *func = "redir_handler";
   union xsockaddr serveraddr ;

   if( signal(SIGPIPE, redir_sigpipe) == SIG_ERR ) 
      msg(LOG_ERR, func, "unable to setup signal handler");

   close_all_svc_descriptors();

   /* If it's a tcp service we are redirecting */
   if( scp->sc_protocol.value == IPPROTO_TCP )
   {
      memcpy(&serveraddr, scp->sc_redir_addr, sizeof(serveraddr));
      if( serveraddr.sa_in.sin_family == AF_INET ) {
         sin_len = sizeof( struct sockaddr_in );
         RedirServerFd = socket(AF_INET, SOCK_STREAM, 0);
       } else if( serveraddr.sa_in.sin_family == AF_INET6 ) {
         sin_len = sizeof( struct sockaddr_in6 );
         RedirServerFd = socket(AF_INET6, SOCK_STREAM, 0);
      } else {
         msg(LOG_ERR, func, "not a valid protocol. Use IPv4 or IPv6.");
         exit(0);
      }

      if( RedirServerFd < 0 )
      {
         msg(LOG_ERR, func, "cannot create socket: %m");
         exit(0);
      }

      if( SC_IPV6( scp ) ) {
         if( SC_V6ONLY( scp ) ) {
            v6on = 1;
         } else {
            v6on = 0;
         }
#ifdef IPV6_V6ONLY
         if( setsockopt(RedirServerFd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6on, sizeof(v6on)) < 0 ) { 
            msg( LOG_ERR, func, "Setting IPV6_V6ONLY option failed (%m)" );
         }
#endif

      }
      if( SC_KEEPALIVE( scp ) )
         if (setsockopt(RedirServerFd, SOL_SOCKET, SO_KEEPALIVE, 
                        (char *)&on, sizeof( on ) ) < 0 )
            msg(LOG_ERR, func, 
                "setsockopt SO_KEEPALIVE RedirServerFd failed: %m");
      
      if( serveraddr.sa_in.sin_family == AF_INET )
         serveraddr.sa_in.sin_port = htons(serveraddr.sa_in.sin_port);
      if( serveraddr.sa_in.sin_family == AF_INET6 )
         serveraddr.sa_in6.sin6_port = htons(serveraddr.sa_in6.sin6_port);

      if( connect(RedirServerFd, &serveraddr.sa, sin_len) < 0 )
      {
         msg(LOG_ERR, func, "can't connect to remote host %s: %m",
            xaddrname( &serveraddr ) );
         exit(0);
      }

      /* connection now established */

      if (setsockopt(RedirServerFd, IPPROTO_TCP, TCP_NODELAY, 
         (char *) &no_to_nagle, sizeof( on ) ) < 0) {

         msg(LOG_ERR, func, "setsockopt RedirServerFd failed: %m");
      }

      if (setsockopt(RedirDescrip, IPPROTO_TCP, TCP_NODELAY, 
         (char *) &no_to_nagle, sizeof( on ) ) < 0) {

         msg(LOG_ERR, func, "setsockopt RedirDescrip failed: %m");
      }

      maxfd = (RedirServerFd > RedirDescrip)?RedirServerFd:RedirDescrip;
      FD_ZERO(&msfd);
      FD_SET(RedirDescrip, &msfd);
      FD_SET(RedirServerFd, &msfd);

      while(1) {
         memcpy(&rdfd, &msfd, sizeof(rdfd));
         if (select(maxfd + 1, &rdfd, (fd_set *)0, (fd_set *)0, timep) <= 0) {
            /* place for timeout code, currently does not time out */
            break;
         }

         if (FD_ISSET(RedirDescrip, &rdfd)) {
            do {
               num_read = read(RedirDescrip,
                  buff, sizeof(buff));
               if (num_read == -1 && errno == EINTR)
                  continue;
               if (num_read <= 0)
                  goto REDIROUT;
               bytes_in += num_read;
            } while (num_read < 0);

            /* Loop until we have written everything
             * that was read */
            num_wrote = 0;
            while( num_wrote < num_read ) {
               ret = write(RedirServerFd,
                  buff + num_wrote,
                  num_read - num_wrote);
               if (ret == -1 && errno == EINTR)
                  continue;
               if (ret <= 0)
                  goto REDIROUT;
               num_wrote += ret;
            }
         }

         if (FD_ISSET(RedirServerFd, &rdfd)) {
            do {
               num_read = read(RedirServerFd,
                  buff, sizeof(buff));
               if (num_read == -1 && errno == EINTR)
                  continue;
               if (num_read <= 0)
                  goto REDIROUT;
               bytes_out += num_read;
            } while (num_read < 0);

            /* Loop until we have written everything
             * that was read */
            num_wrote = 0;
            while( num_wrote < num_read ) {
               ret = write(RedirDescrip,
                  buff + num_wrote,
                  num_read - num_wrote);
               if (ret == -1 && errno == EINTR)
                  continue;
               if (ret <= 0)
                  goto REDIROUT;
               num_wrote += ret;
            }
         }
      }
REDIROUT:
      if( M_IS_SET( (scp)->sc_log_on_success, LO_TRAFFIC ) ) {
         svc_logprint( SERVER_CONNSERVICE( serp ), "TRAFFIC",
                       "in=%lu(bytes) out=%lu(bytes)", bytes_in, bytes_out );
      }

      exit(0);
   }

   msg(LOG_ERR, func, 
   "redirect with any protocol other than tcp is not supported at this time.");
   exit(0);
}
Exemplo n.º 3
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 ) ;
}