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; }
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; }