static void
ProcessNewClientConnection (
    int				* nfds,
    fd_set			* rinit,
    struct config		* config_info,
    int				accept_fd,
    int				server_idx)
{
    int				temp_sock_fd;
    struct sockaddr_in		temp_sockaddr_in;
    struct timeval		time_val;
    struct timezone		time_zone;
    int				rule_number = -1;
    int				server_fd;
    struct sockaddr_in		server_sockaddr_in;
    int				temp_sock_len = sizeof(temp_sockaddr_in);

    /*
     * The first thing we do is accept() this connection and check it
     * against configuration data to see whether its origination host
     * is allowed; next, we connect to the server found in the lookup,
     * synthesize a proxy connection setup request to be sent
     * to that server to determine whether it`s a secure server;
     * we can't block on the server reply so we go ahead and allocate
     * a data structure for this client connection, and mark its
     * state PENDING
     */

    if ((temp_sock_fd = accept(accept_fd,
                               (struct sockaddr *) &temp_sockaddr_in,
	 		       (void *)&temp_sock_len)) < 0)
    {
	(void) fprintf (stderr, "accept call for a client failed\n");
	return;
    }

    /*
     * Try to initialize and open a connection to the server. If
     * an error occurs, those functions will output an appropriate
     * message
     */
    if ((doServerConnectSetup(server_array[server_idx]->x_server_hostport,
			      &server_array[server_idx]->server_fd,
			      &server_sockaddr_in)) == FAILURE)
    {
	(void) close (temp_sock_fd);
	return;
    }
    if ((doServerConnect(&server_array[server_idx]->server_fd,
		         &server_sockaddr_in)) == FAILURE)
    {
	(void) close (temp_sock_fd);
	(void) close (server_array[server_idx]->server_fd);
	return;
    }

    server_fd = server_array[server_idx]->server_fd;

    /*
     * do config check on client source and destination (must do
     * it here because otherwise we don't have a server socket
     * to query and we may not be able to resolve server name
     * alone from xfindproxy()
     */
    if ((doConfigCheck(&temp_sockaddr_in,
		       &server_sockaddr_in,
		       config_info,
		       CLIENT,
		       &rule_number)) == FAILURE)
    {
        /*
         * log the client connection failure, close client and server
	 * sockets and return
         */
	doWriteLogEntry (inet_ntoa(temp_sockaddr_in.sin_addr),
			 inet_ntoa(server_sockaddr_in.sin_addr),
			 CLIENT_REJECT_CONFIG,
			 rule_number,
			 config_info);
	(void) close (temp_sock_fd);
        (void) close (server_fd);
        return;
    }

    /*
     * If configured authorization succeeds, go ahead and
     * allocate a client_conn_buf struct for client connection
     */
    if ((client_conn_array[temp_sock_fd] =
	    malloc(sizeof (struct client_conn_buf))) == NULL)
    {
	(void) fprintf (stderr, "malloc - client connection buffer\n");
	return;
    }
    bzero (client_conn_array[temp_sock_fd], sizeof (struct client_conn_buf));

    /*
     * save the source and destination data for this connection (since
     * the log data struct will go out of scope before we check the
     * server security extension or other loggable events)
     */
    if ((client_conn_array[temp_sock_fd]->source =
	 strdup(inet_ntoa(temp_sockaddr_in.sin_addr))) == NULL)
    {
	(void) fprintf (stderr, "malloc - client source addr\n");
	return;
    }
    if ((client_conn_array[temp_sock_fd]->destination =
	 strdup(inet_ntoa(server_sockaddr_in.sin_addr))) == NULL)
    {
	(void) fprintf (stderr, "malloc - client dest addr\n");
	return;
    }

    /*
     * allocate a buffer for the X server connection
     * and create the association between client and server
     */
    if ((client_conn_array[server_fd] =
	malloc(sizeof (struct client_conn_buf))) == NULL)
    {
	(void) fprintf (stderr, "malloc - server connection buffer\n");
	return;
    }
    bzero (client_conn_array[server_fd], sizeof (struct client_conn_buf));

    client_conn_array[server_fd]->conn_to = temp_sock_fd;
    client_conn_array[temp_sock_fd]->conn_to = server_fd;

    /*
     * save this sock fd for future reference (in timeout computation)
     */
    client_conn_array[temp_sock_fd]->fd = temp_sock_fd;

    /*
     * mark this buffer as readable and writable and waiting for
     * authentication to complete; mark the server conn buffer
     * with a special state to make sure that its reply to
     * the authentication request can be read and interpreted
     * before it is simply forwarded to the client
     */
    client_conn_array[temp_sock_fd]->state = CLIENT_WAITING;
    client_conn_array[server_fd]->state = SERVER_REPLY;

    /*
     * update the select() fd mask and the nfds
     */
    FD_SET(temp_sock_fd, rinit);
    *nfds = max(*nfds, temp_sock_fd + 1);
    FD_SET(server_fd, rinit);
    *nfds = max(*nfds, server_fd + 1);

    /*
     * this is where we initialize the current time and timeout on this
     * client_data object
     */
    gettimeofday(&time_val, &time_zone);
    client_conn_array[temp_sock_fd]->creation_time = time_val.tv_sec;
    client_conn_array[temp_sock_fd]->time_to_close =
	  config_info->client_data_timeout;

    /*
     * be sure the mark the server side of the association, too
     */
    client_conn_array[server_fd]->creation_time = time_val.tv_sec;
    client_conn_array[server_fd]->time_to_close =
	config_info->client_data_timeout;

    client_conn_array[server_fd]->fd = server_fd;
}
Exemplo n.º 2
0
void FWPprocessMessages(
    IceConn iceConn, 
    IcePointer * client_data,
    int opcode,
    unsigned long length,
    Bool swap)
{
  switch (opcode)
  { 
    /*
     * this is really the only opcode we care about -- the one
     * which indicates an XFindProxy request for a connection
     * to a specified server
     */
    case PM_GetProxyAddr:
    {
      pmGetProxyAddrMsg       	*pMsg;
      char                      *pData, *pStart;
      char                      *serviceName = NULL, *serverAddress = NULL;
      char                      *hostAddress = NULL, *startOptions = NULL;
      char                      *authName = NULL, *authData = NULL;
      int                       authLen;
      struct clientDataStruct * program_data; 
      char *			listen_port_string;
      int			pm_send_msg_len;
      pmGetProxyAddrReplyMsg *	pReply;
      char *			pReplyData;
      struct hostent * 		hostptr;
      struct sockaddr_in	server_sockaddr_in;
      struct sockaddr_in	dummy_sockaddr_in;
      char *			server_name_base;
      char *			config_failure = "unrecognized server or permission denied";
      char *			tmp_str;
      int			rule_number = -1;
      char *			colon;
      char *			tmpAddress = NULL;

      /*
       * this is where we need and get access to that client data we
       * went through such contortions to set up earlier!
       */
      program_data = (struct clientDataStruct *) client_data;
      /*
       * initial check on expected message size
       */ 
      CHECK_AT_LEAST_SIZE (iceConn, global_data.major_opcode, opcode,
          length, SIZEOF (pmGetProxyAddrMsg), IceFatalToProtocol);

      IceReadCompleteMessage (iceConn, SIZEOF (pmGetProxyAddrMsg),
          pmGetProxyAddrMsg, pMsg, pStart);

      if (!IceValidIO (iceConn))
      {
        IceDisposeCompleteMessage (iceConn, pStart);
        return;
      }

      authLen = swap ? lswaps (pMsg->authLen) : pMsg->authLen;

      pData = pStart;

      SKIP_STRING (pData, swap);      /* proxy-service */
      SKIP_STRING (pData, swap);      /* server-address */
      SKIP_STRING (pData, swap);      /* host-address */
      SKIP_STRING (pData, swap);      /* start-options */
      if (authLen > 0)
      {
        SKIP_STRING (pData, swap);              /* auth-name */
        pData += (authLen +  PAD64 (authLen));  /* auth-data */
      }
      /*
       * now a detailed check on message size
       */
      CHECK_COMPLETE_SIZE (iceConn, global_data.major_opcode, opcode,
         length, pData - pStart + SIZEOF (pmGetProxyAddrMsg),
         pStart, IceFatalToProtocol);

      pData = pStart;
      /*
       * extract message data, based on known characteristics
       * of this message type
       */
      EXTRACT_STRING (pData, swap, serviceName);
      EXTRACT_STRING (pData, swap, serverAddress);
      EXTRACT_STRING (pData, swap, hostAddress);
      EXTRACT_STRING (pData, swap, startOptions);
      if (authLen > 0)
      {
        EXTRACT_STRING (pData, swap, authName);
        authData = (char *) malloc (authLen);
        memcpy (authData, pData, authLen);
      }
#ifdef DEBUG
      (void) fprintf (stderr, 
		      "Got GetProxyAddr, serviceName = %s, serverAddr = %s\n",
              	      serviceName, serverAddress);
      (void) fprintf (stderr, 
		      "\thostAddr = %s, options = %s, authLen = %d\n",
              	      hostAddress, startOptions, authLen);
      if (authLen > 0)
          (void) fprintf (stderr, "\tauthName = %s\n", authName);
#endif
      /*
       * need to copy the host port string because strtok() changes it   
       */
      if ((tmp_str = strdup (serverAddress)) == NULL)
      {
        (void) fprintf(stderr, "malloc - serverAddress copy\n");
        goto sendFailure;
      }

      /*
       * before proceeding we want to verify that we are allowed to
       * accept connections from the host who called xfindproxy(); 
       * the thing is, we don't get that host name from Proxy Manager
       * even if the "-host <hostname>" command-line option was present
       * in xfindproxy (and even if it was we shouldn't rely on it --
       * much better to have ProxyMngr query the xfindproxy connect
       * socket for its origin); the upshot of all this that we do
       * a configuration check *only* on the destination (which we
       * assume in this case to be the serverAddress passed in by
       * xfindproxy(); so get the destination IP address!
       */
      server_name_base = strtok(tmp_str, ":");
      if ((hostptr = gethostbyname(server_name_base)) == NULL)
      {
        (void) fprintf(stderr, "gethostbyname (%s) failed\n", server_name_base);
	goto sendFailure;
      }
      memset(&server_sockaddr_in, 0, sizeof(server_sockaddr_in));
      memset(&dummy_sockaddr_in, 0, sizeof(dummy_sockaddr_in)); 
      memcpy((char *) &server_sockaddr_in.sin_addr, 
	     hostptr->h_addr,
	     hostptr->h_length);

      /*
       * need to initialize dummy to something, but doesn't matter
       * what (should eventually be the true host address); 
       * NOTE:  source configuration will always match (see XFWP man
       * page) unless sysadmin explicitly chooses to deny 
       */
      memcpy((char *) &dummy_sockaddr_in.sin_addr, 
	     hostptr->h_addr,
	     hostptr->h_length);

      if ((doConfigCheck(&dummy_sockaddr_in, 
  			 &server_sockaddr_in,
			 global_data.config_info,
			 FINDPROXY,
			 &rule_number)) == FAILURE)
      { 
        (void) fprintf(stderr, "xfindproxy failed config check\n");
      sendFailure:
        /*
         * report failure back to the ProxyMgr
         * 
         */
        pm_send_msg_len = STRING_BYTES(config_failure)
	      		+ STRING_BYTES(NULL);
        IceGetHeaderExtra(iceConn, 
	      	        program_data->major_opcode, 
	      		PM_GetProxyAddrReply,
	       		SIZEOF(pmGetProxyAddrReplyMsg),
	       		WORD64COUNT (pm_send_msg_len),
	       		pmGetProxyAddrReplyMsg,
	       		pReply,
	       		pReplyData);
        pReply->status = PM_Failure;
        STORE_STRING(pReplyData, NULL);
        STORE_STRING(pReplyData, config_failure);
        IceFlush(iceConn);
	free(tmp_str);
        return; 
      }

      /* 
       * okay, you got what you need from the PM to proceed,
       * so extract the fd of the selected connection and use
       * it to set up the remote client listen port and add 
       * the name of the X server to your list of server connections
       */

      /*
       * Before checking to see if you already have a PM connection
       * request for this server, make serverAddress a
       * FQDN so that synonomous names like oregon:0 and oregon.com:0
       * will be recognized as the same Xserver.  If this server
       * already exists, don't allocate another listen port for it -
       * use the already allocated one
       */
      colon = strchr (serverAddress, ':');
      if (colon)
      {
	  struct hostent *hostent;

	  *colon = '\0';
	  hostent = gethostbyname (serverAddress);
	  *colon = ':';

	  if (hostent && hostent->h_name) {
	      tmpAddress = (char *) malloc (strlen (hostent->h_name) + 
					    strlen (colon) + 1);
	      (void) sprintf (tmpAddress, "%s%s", hostent->h_name, colon);
	      serverAddress = tmpAddress;
	  }
      }

      if ((doCheckServerList(serverAddress, 
			    &listen_port_string,
			    program_data->config_info->num_servers)) == FAILURE)
      {
        /*
         * this server name isn't in your list; so set up a new
         * remote client listen port for it; extract the fd from
         * the connection and pass it in as index to array lookup
         */
        if ((doSetupRemClientListen(&listen_port_string,
			            program_data,
				    serverAddress)) == FAILURE)
 	{
          goto sendFailure;
	}
      }
      if (tmpAddress)
	free (tmpAddress);

      /*
       * the PM-sent server address *was* in your list, so send back
       * the rem client listen port you had already associated with 
       * that server (it will presumably be forwarded to the remote
       * client through some other channel)
       * use IceGetHeaderExtra() and the 
       */
      pm_send_msg_len = STRING_BYTES(listen_port_string)
			+ STRING_BYTES(NULL);
      IceGetHeaderExtra(iceConn, 
		        program_data->major_opcode, 
			PM_GetProxyAddrReply,
			SIZEOF(pmGetProxyAddrReplyMsg),
			WORD64COUNT (pm_send_msg_len),
			pmGetProxyAddrReplyMsg,
			pReply,
			pReplyData);
      pReply->status = PM_Success;
      STORE_STRING(pReplyData, listen_port_string);
      STORE_STRING(pReplyData, NULL); 
      IceFlush(iceConn);
      /*
       * before leaving this routine, change the select() timeout
       * here to be equal to the configured client listen timeout
       * (otherwise you'll never *get* to your listen timeout
       * if it's shorter than the startup select() default
       */
      program_data->config_info->select_timeout.tv_sec =
		program_data->config_info->client_listen_timeout;
      break;
    }

    case ICE_Error:
    {
	iceErrorMsg *pMsg;
	char *pStart;

	CHECK_AT_LEAST_SIZE (iceConn, global_data.major_opcode, ICE_Error, 
			     length, sizeof(iceErrorMsg), IceFatalToProtocol);

	IceReadCompleteMessage (iceConn, SIZEOF (iceErrorMsg),
				iceErrorMsg, pMsg, pStart);

	if (!IceValidIO (iceConn))
	{
	    IceDisposeCompleteMessage (iceConn, pStart);
	    return;
	}

	if (swap)
	{
	    pMsg->errorClass = lswaps (pMsg->errorClass);
	    pMsg->offendingSequenceNum = lswapl (pMsg->offendingSequenceNum);
	}

	(void) fprintf(stderr, "Proxy Manager reported ICE Error:\n");
	(void) fprintf(stderr, "\tclass = 0x%x, offending minor opcode = %d\n",
		       pMsg->errorClass, pMsg->offendingMinorOpcode);
	(void) fprintf(stderr, "\tseverity = %d, sequence = %ld\n",
		       pMsg->severity, (long)pMsg->offendingSequenceNum);

	IceDisposeCompleteMessage (iceConn, pStart);

	break;
    }

    default:
      break;
  } /* end switch */
}
static void
ProcessNewPMConnection (
    int				* nfds,
    fd_set			* rinit,
    struct config		* config_info,
    IceListenObj		** listen_objects,
    int				listen_fd)

{
    IceConn			new_ice_conn;
    IceAcceptStatus  		accept_status;
    int				temp_sock_fd;
    IceListenObj *		temp_obj;
    struct timeval		time_val;
    struct timezone		time_zone;
    struct sockaddr_in		temp_sockaddr_in;
    struct sockaddr_in		server_sockaddr_in;
    int				retval;
    int				addrlen = sizeof(temp_sockaddr_in);
    int				rule_number;
    int				pm_idx;

    /*
     * Only continue if there is room for another PM connection.
     */
    for (pm_idx = 0; pm_idx < config_info->num_pm_conns; pm_idx++)
    {
      if (!pm_conn_array[pm_idx])
        break;
    }
    if (pm_idx >= config_info->num_pm_conns)
    {
      (void) fprintf (stderr,
	             "Maximum number of PM connections has been reached (%d)\n",
		     config_info->num_pm_conns);

      /*
       * Must accept and then close this connection or the PM will
       * continue to poll.
       */
      temp_obj = *listen_objects;
      new_ice_conn = IceAcceptConnection(temp_obj[listen_fd], &accept_status);
      if (new_ice_conn)
        IceCloseConnection(new_ice_conn);

      return;
    }

    /*
     * accept the connection if you can, use pm_listen_array
     * index to index into ICE listen_object list (this is because the
     * listen_objects list must correspond to the pm_listen_array)
     */
    temp_obj = *listen_objects;
    new_ice_conn = IceAcceptConnection(temp_obj[listen_fd], &accept_status);
    if (!new_ice_conn)
    {
        static int	been_here;

        /*
         * ICE initialization (bug?) makes this happen the
         * first time readables is hit.
         */
        if (!been_here)
            been_here++;
        else
           (void) fprintf(stderr, "IceAcceptConnection failed (%d)\n",
	  	          accept_status);
       return;
    }

    /*
     * extract the fd from this new connection; remember, the fd of
     * the listen socket is *not* the fd of the actual connection!
     */
    temp_sock_fd = IceConnectionNumber(new_ice_conn);

    /*
     * before we get any further, do a config check on the new ICE
     * connection; start by using getpeername() to get endpoint info
     */
    retval = getpeername(temp_sock_fd,
			 (struct sockaddr*)&temp_sockaddr_in,
			 (void *)&addrlen);
    if (retval)
    {
        IceCloseConnection(new_ice_conn);
        (void) fprintf(stderr, "getpeername call failed\n");
	return;
    }

    assert(temp_sockaddr_in.sin_family == AF_INET);

    /*
     * Do a configuration check.  NOTE:  we're not doing anything
     * with the server_sockaddr_in argument
     */
    if ((doConfigCheck(&temp_sockaddr_in,
		       &server_sockaddr_in,
		       config_info,
		       PMGR,
		       &rule_number)) == FAILURE)
    {
        /*
         * close the PM connection
         *
         */
        (void) fprintf(stderr, "PM failed config check\n");
        IceCloseConnection(new_ice_conn);
        return;
    }

    /*
     * you've started the connection process; allocate a buffer
     * for this connection, then continue processing other fd's without
     * blocking while waiting to read the coming PM data; [NOTE:
     * we use the fd of the connection socket as index into the
     * pm_conn_array; this saves us much troublesome linked-list
     * management!]
     */
    if ((pm_conn_array[pm_idx] = malloc(sizeof(struct pm_conn_buf))) == NULL)
    {
        (void) fprintf (stderr, "malloc - PM connection object\n");
        return;
    }

    /*
     * save the ICEconn struct for future status checks; also
     * the fd (although you could extract it from the ICEconn
     * each time you need it, but that's a pain)
     */
    pm_conn_array[pm_idx]->fd = temp_sock_fd;
    pm_conn_array[pm_idx]->ice_conn = new_ice_conn;

    /*
     * Set the readables select() to listen for a readable on this
     * fd; remember, we're not interested in pm writables, since
     * all the negotiation is handled inside this routine; adjust
     * the nfds (must do that every time we get a new socket to
     * select() on), and then continue processing current selections
     */
    FD_SET(temp_sock_fd, rinit);
    *nfds = max(*nfds, temp_sock_fd + 1);

    /*
     * this is where we initialize the current time and timeout on this
     * pm_connection object
     */
    (void) gettimeofday(&time_val, &time_zone);
    pm_conn_array[pm_idx]->creation_time = time_val.tv_sec;
    pm_conn_array[pm_idx]->time_to_close = config_info->pm_data_timeout;
}