2005-01-20 23:22:22 +00:00
|
|
|
// Berkeley Open Infrastructure for Network Computing
|
|
|
|
// http://boinc.berkeley.edu
|
|
|
|
// Copyright (C) 2005 University of California
|
2004-01-30 22:19:19 +00:00
|
|
|
//
|
2005-01-20 23:22:22 +00:00
|
|
|
// This is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
// License as published by the Free Software Foundation;
|
|
|
|
// either version 2.1 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This software is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
// See the GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// To view the GNU Lesser General Public License visit
|
|
|
|
// http://www.gnu.org/copyleft/lesser.html
|
|
|
|
// or write to the Free Software Foundation, Inc.,
|
|
|
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2004-01-30 22:19:19 +00:00
|
|
|
|
2005-07-31 23:33:12 +00:00
|
|
|
// The plumbing of GUI RPC, server side
|
|
|
|
// (but not the actual RPCs)
|
|
|
|
|
2004-02-28 19:11:40 +00:00
|
|
|
#ifdef _WIN32
|
2004-06-16 23:16:08 +00:00
|
|
|
#include "boinc_win.h"
|
2004-03-04 11:41:43 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef _WIN32
|
2005-11-21 18:34:44 +00:00
|
|
|
#include "config.h"
|
2004-03-04 11:41:43 +00:00
|
|
|
#include <stdio.h>
|
2005-12-16 03:45:01 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
2004-01-21 07:07:16 +00:00
|
|
|
#include <unistd.h>
|
2005-12-16 03:45:01 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
2004-01-21 07:07:16 +00:00
|
|
|
#include <sys/socket.h>
|
2005-12-16 03:45:01 +00:00
|
|
|
#endif
|
2005-10-17 20:21:57 +00:00
|
|
|
#include <sys/stat.h>
|
2004-01-21 07:07:16 +00:00
|
|
|
#include <sys/un.h>
|
2004-01-21 22:54:35 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <string.h>
|
2004-04-15 20:42:15 +00:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
2004-07-10 07:27:00 +00:00
|
|
|
#include <arpa/inet.h>
|
2004-03-04 11:41:43 +00:00
|
|
|
#endif
|
2004-01-21 07:07:16 +00:00
|
|
|
|
2004-04-07 06:51:42 +00:00
|
|
|
#include "util.h"
|
2004-05-05 21:15:34 +00:00
|
|
|
#include "error_numbers.h"
|
2004-01-21 07:07:16 +00:00
|
|
|
#include "parse.h"
|
2005-03-07 06:09:04 +00:00
|
|
|
#include "network.h"
|
|
|
|
#include "filesys.h"
|
2005-10-27 20:03:51 +00:00
|
|
|
#include "md5_file.h"
|
2004-04-08 08:15:23 +00:00
|
|
|
|
2004-07-10 07:27:00 +00:00
|
|
|
#include "file_names.h"
|
2004-04-08 08:15:23 +00:00
|
|
|
#include "client_msgs.h"
|
2004-01-21 07:07:16 +00:00
|
|
|
#include "client_state.h"
|
|
|
|
|
2004-06-30 18:17:21 +00:00
|
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
|
2004-01-21 07:07:16 +00:00
|
|
|
GUI_RPC_CONN::GUI_RPC_CONN(int s) {
|
|
|
|
sock = s;
|
2005-03-07 06:09:04 +00:00
|
|
|
auth_needed = false;
|
2004-01-21 07:07:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GUI_RPC_CONN::~GUI_RPC_CONN() {
|
2004-09-05 18:46:19 +00:00
|
|
|
boinc_close_socket(sock);
|
2004-01-21 07:07:16 +00:00
|
|
|
}
|
|
|
|
|
2005-07-23 08:10:39 +00:00
|
|
|
GUI_RPC_CONN_SET::GUI_RPC_CONN_SET() {
|
|
|
|
lsock = -1;
|
2005-12-24 06:32:07 +00:00
|
|
|
last_rpc_time = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GUI_RPC_CONN_SET::got_recent_rpc(double interval) {
|
|
|
|
if (!last_rpc_time) return false;
|
|
|
|
if (gstate.now < last_rpc_time + interval) return true;
|
|
|
|
return false;
|
2005-07-23 08:10:39 +00:00
|
|
|
}
|
|
|
|
|
2005-03-07 06:09:04 +00:00
|
|
|
int GUI_RPC_CONN_SET::get_password() {
|
2005-10-15 05:38:47 +00:00
|
|
|
FILE* f;
|
2005-10-27 20:03:51 +00:00
|
|
|
int retval;
|
|
|
|
|
2005-03-07 06:09:04 +00:00
|
|
|
strcpy(password, "");
|
|
|
|
if (boinc_file_exists(GUI_RPC_PASSWD_FILE)) {
|
2005-10-15 05:38:47 +00:00
|
|
|
f = fopen(GUI_RPC_PASSWD_FILE, "r");
|
2005-03-07 06:09:04 +00:00
|
|
|
if (f) {
|
|
|
|
fgets(password, 256, f);
|
|
|
|
strip_whitespace(password);
|
|
|
|
fclose(f);
|
|
|
|
}
|
2005-10-15 05:38:47 +00:00
|
|
|
} else {
|
|
|
|
// if no password file, make a random password
|
|
|
|
//
|
2005-10-27 20:03:51 +00:00
|
|
|
retval = make_random_string(password);
|
|
|
|
if (retval) {
|
|
|
|
gstate.host_info.make_random_string("guirpc", password);
|
|
|
|
}
|
2005-10-15 05:38:47 +00:00
|
|
|
f = fopen(GUI_RPC_PASSWD_FILE, "w");
|
|
|
|
if (f) {
|
|
|
|
fputs(password, f);
|
|
|
|
fclose(f);
|
|
|
|
#ifndef _WIN32
|
|
|
|
// if someone can read the password,
|
|
|
|
// they can cause code to execute as this user.
|
|
|
|
// So better protect it.
|
|
|
|
//
|
|
|
|
chmod(GUI_RPC_PASSWD_FILE, S_IRUSR|S_IWUSR);
|
|
|
|
#endif
|
|
|
|
}
|
2005-03-07 06:09:04 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-07-10 07:27:00 +00:00
|
|
|
int GUI_RPC_CONN_SET::get_allowed_hosts() {
|
2005-04-10 00:16:20 +00:00
|
|
|
int ipaddr, retval;
|
|
|
|
char buf[256], msg[256];
|
|
|
|
|
2004-07-10 07:27:00 +00:00
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE);
|
|
|
|
|
|
|
|
// open file remote_hosts.cfg and read in the
|
|
|
|
// allowed host list and resolve them to an ip address
|
|
|
|
//
|
|
|
|
FILE* f = fopen(REMOTEHOST_FILE_NAME, "r");
|
|
|
|
if (f != NULL) {
|
|
|
|
scope_messages.printf(
|
|
|
|
"GUI_RPC_CONN_SET::get_allowed_hosts(): found allowed hosts list\n"
|
|
|
|
);
|
|
|
|
|
|
|
|
// read in each line, if it is not a comment
|
2005-02-16 23:17:43 +00:00
|
|
|
// then resolve the address and add to our allowed list
|
|
|
|
//
|
2004-07-10 07:27:00 +00:00
|
|
|
memset(buf,0,sizeof(buf));
|
|
|
|
while (fgets(buf, 256, f) != NULL) {
|
|
|
|
strip_whitespace(buf);
|
|
|
|
if (!(buf[0] =='#' || buf[0] == ';') && strlen(buf) > 0 ) {
|
2005-04-10 00:16:20 +00:00
|
|
|
retval = resolve_hostname(buf, ipaddr, msg);
|
|
|
|
if (!retval) {
|
2004-07-10 07:27:00 +00:00
|
|
|
allowed_remote_ip_addresses.push_back((int)ntohl(ipaddr));
|
2004-09-05 18:46:19 +00:00
|
|
|
}
|
2004-07-10 07:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-01-21 07:07:16 +00:00
|
|
|
int GUI_RPC_CONN_SET::insert(GUI_RPC_CONN* p) {
|
|
|
|
gui_rpcs.push_back(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-05-05 21:15:34 +00:00
|
|
|
int GUI_RPC_CONN_SET::init() {
|
2004-09-05 18:46:19 +00:00
|
|
|
sockaddr_in addr;
|
2004-01-21 07:07:16 +00:00
|
|
|
int retval;
|
|
|
|
|
2004-07-10 07:27:00 +00:00
|
|
|
get_allowed_hosts();
|
2005-03-07 06:09:04 +00:00
|
|
|
get_password();
|
2004-07-10 07:27:00 +00:00
|
|
|
|
2004-04-15 20:42:15 +00:00
|
|
|
lsock = socket(AF_INET, SOCK_STREAM, 0);
|
2004-06-12 04:45:36 +00:00
|
|
|
if (lsock < 0) {
|
|
|
|
msg_printf(NULL, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"GUI RPC failed to create socket: %d", lsock
|
2004-06-12 04:45:36 +00:00
|
|
|
);
|
2004-05-05 21:15:34 +00:00
|
|
|
return ERR_SOCKET;
|
2004-01-21 07:07:16 +00:00
|
|
|
}
|
2004-04-15 20:42:15 +00:00
|
|
|
|
2005-12-02 22:29:35 +00:00
|
|
|
memset(&addr, 0, sizeof(addr));
|
2004-04-15 20:42:15 +00:00
|
|
|
addr.sin_family = AF_INET;
|
2005-11-26 00:59:45 +00:00
|
|
|
|
2005-12-13 08:04:57 +00:00
|
|
|
if (gstate.cmdline_gui_rpc_port) {
|
|
|
|
addr.sin_port = htons(gstate.cmdline_gui_rpc_port);
|
2005-11-26 00:59:45 +00:00
|
|
|
} else {
|
2005-12-20 07:35:50 +00:00
|
|
|
addr.sin_port = htons(GUI_RPC_PORT);
|
2005-11-26 00:59:45 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 00:04:35 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
#else
|
2005-04-11 20:30:24 +00:00
|
|
|
if (gstate.allow_remote_gui_rpc || allowed_remote_ip_addresses.size() > 0) {
|
|
|
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(NULL, MSG_INFO, "Remote control allowed");
|
2005-04-11 20:30:24 +00:00
|
|
|
} else {
|
2005-04-19 19:50:58 +00:00
|
|
|
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(NULL, MSG_INFO, "Local control only allowed");
|
2005-04-11 20:30:24 +00:00
|
|
|
}
|
2005-04-16 00:04:35 +00:00
|
|
|
#endif
|
2004-04-15 20:42:15 +00:00
|
|
|
|
2004-06-12 04:45:36 +00:00
|
|
|
int one = 1;
|
|
|
|
setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char*)&one, 4);
|
|
|
|
|
2005-05-06 01:54:00 +00:00
|
|
|
retval = bind(lsock, (const sockaddr*)(&addr), (boinc_socklen_t)sizeof(addr));
|
2004-01-21 07:07:16 +00:00
|
|
|
if (retval) {
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(NULL, MSG_ERROR, "GUI RPC bind failed: %d", retval);
|
2005-12-20 07:35:50 +00:00
|
|
|
boinc_close_socket(lsock);
|
|
|
|
lsock = -1;
|
|
|
|
return ERR_BIND;
|
2004-01-21 07:07:16 +00:00
|
|
|
}
|
2005-12-13 08:04:57 +00:00
|
|
|
msg_printf(NULL, MSG_INFO, "Listening on port %d", htons(addr.sin_port));
|
2005-11-26 00:59:45 +00:00
|
|
|
|
2004-01-21 07:07:16 +00:00
|
|
|
retval = listen(lsock, 999);
|
|
|
|
if (retval) {
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(NULL, MSG_ERROR, "GUI RPC listen failed: %d", retval);
|
2004-08-16 09:41:02 +00:00
|
|
|
boinc_close_socket(lsock);
|
|
|
|
lsock = -1;
|
2004-05-05 21:15:34 +00:00
|
|
|
return ERR_LISTEN;
|
2004-01-21 07:07:16 +00:00
|
|
|
}
|
2004-05-12 21:21:09 +00:00
|
|
|
return 0;
|
2004-01-21 07:07:16 +00:00
|
|
|
}
|
|
|
|
|
2005-02-10 00:35:00 +00:00
|
|
|
static void show_connect_error(in_addr ia) {
|
|
|
|
static double last_time=0;
|
|
|
|
static int count=0;
|
|
|
|
|
|
|
|
if (last_time == 0) {
|
2005-06-07 19:22:50 +00:00
|
|
|
last_time = gstate.now;
|
2005-02-10 00:35:00 +00:00
|
|
|
count = 1;
|
|
|
|
} else {
|
2005-06-07 19:22:50 +00:00
|
|
|
if (gstate.now - last_time < 600) {
|
2005-02-10 00:35:00 +00:00
|
|
|
count++;
|
|
|
|
return;
|
|
|
|
}
|
2005-06-07 19:22:50 +00:00
|
|
|
last_time = gstate.now;
|
2005-02-10 00:35:00 +00:00
|
|
|
}
|
|
|
|
msg_printf(
|
|
|
|
NULL, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"GUI RPC request from non-allowed address %s",
|
2005-02-10 00:35:00 +00:00
|
|
|
inet_ntoa(ia)
|
|
|
|
);
|
|
|
|
if (count > 1) {
|
|
|
|
msg_printf(
|
|
|
|
NULL, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"%d connections rejected in last 10 minutes",
|
2005-02-10 00:35:00 +00:00
|
|
|
count
|
|
|
|
);
|
|
|
|
}
|
|
|
|
count = 0;
|
|
|
|
}
|
|
|
|
|
2005-08-16 21:31:27 +00:00
|
|
|
void GUI_RPC_CONN_SET::get_fdset(FDSET_GROUP& fg, FDSET_GROUP& all) {
|
2005-08-16 20:48:21 +00:00
|
|
|
unsigned int i;
|
|
|
|
GUI_RPC_CONN* gr;
|
|
|
|
|
|
|
|
if (lsock < 0) return;
|
|
|
|
for (i=0; i<gui_rpcs.size(); i++) {
|
|
|
|
gr = gui_rpcs[i];
|
2005-08-16 21:31:27 +00:00
|
|
|
int s = gr->sock;
|
|
|
|
FD_SET(s, &fg.read_fds);
|
|
|
|
FD_SET(s, &fg.exc_fds);
|
|
|
|
if (s > fg.max_fd) fg.max_fd = s;
|
|
|
|
|
|
|
|
FD_SET(s, &all.read_fds);
|
|
|
|
FD_SET(s, &all.exc_fds);
|
|
|
|
if (s > all.max_fd) all.max_fd = s;
|
2005-08-16 20:48:21 +00:00
|
|
|
}
|
|
|
|
FD_SET(lsock, &fg.read_fds);
|
2005-08-16 21:31:27 +00:00
|
|
|
if (lsock > fg.max_fd) fg.max_fd = lsock;
|
|
|
|
FD_SET(lsock, &all.read_fds);
|
|
|
|
if (lsock > all.max_fd) all.max_fd = lsock;
|
2005-08-16 20:48:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GUI_RPC_CONN_SET::got_select(FDSET_GROUP& fg) {
|
2004-08-16 09:41:02 +00:00
|
|
|
int sock, retval;
|
|
|
|
vector<GUI_RPC_CONN*>::iterator iter;
|
|
|
|
GUI_RPC_CONN* gr;
|
2005-04-09 23:19:38 +00:00
|
|
|
bool is_local = false;
|
2004-08-16 09:41:02 +00:00
|
|
|
|
2005-08-16 20:48:21 +00:00
|
|
|
if (lsock < 0) return;
|
2004-06-09 18:17:25 +00:00
|
|
|
|
2005-08-16 20:48:21 +00:00
|
|
|
if (FD_ISSET(lsock, &fg.read_fds)) {
|
2004-08-16 09:41:02 +00:00
|
|
|
struct sockaddr_in addr;
|
2004-01-21 07:07:16 +00:00
|
|
|
|
2005-10-27 18:58:43 +00:00
|
|
|
// For unknown reasons, the FD_ISSET() above succeeds
|
|
|
|
// after a SIGTERM, SIGHUP, SIGINT or SIGQUIT is received,
|
|
|
|
// even if there is no data available on the socket.
|
|
|
|
// This causes the accept() call to block, preventing the main
|
|
|
|
// loop from processing the exit request.
|
|
|
|
// This is a workaround for that problem.
|
|
|
|
//
|
|
|
|
if (gstate.requested_exit) {
|
|
|
|
return;
|
|
|
|
}
|
2005-10-26 00:58:33 +00:00
|
|
|
|
2005-05-06 01:54:00 +00:00
|
|
|
boinc_socklen_t addr_len = sizeof(addr);
|
2006-01-16 19:54:44 +00:00
|
|
|
sock = accept(lsock, (struct sockaddr*)&addr, (boinc_socklen_t*)&addr_len);
|
2005-12-02 22:29:35 +00:00
|
|
|
if (sock == -1) {
|
|
|
|
return;
|
|
|
|
}
|
2004-07-15 20:05:04 +00:00
|
|
|
|
2004-08-16 09:41:02 +00:00
|
|
|
int peer_ip = (int) ntohl(addr.sin_addr.s_addr);
|
2004-07-15 20:05:04 +00:00
|
|
|
|
2004-08-16 09:41:02 +00:00
|
|
|
// check list of allowed remote hosts
|
|
|
|
bool allowed = false;
|
|
|
|
vector<int>::iterator remote_iter;
|
2004-07-10 07:27:00 +00:00
|
|
|
|
2004-08-16 09:41:02 +00:00
|
|
|
remote_iter = allowed_remote_ip_addresses.begin();
|
|
|
|
while (remote_iter != allowed_remote_ip_addresses.end() ) {
|
|
|
|
int remote_host = *remote_iter;
|
|
|
|
if (peer_ip == remote_host) allowed = true;
|
|
|
|
remote_iter++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// accept the connection if:
|
|
|
|
// 1) allow_remote_gui_rpc is set or
|
|
|
|
// 2) client host is included in "remote_hosts" file or
|
|
|
|
// 3) client is on localhost
|
|
|
|
//
|
2005-04-09 23:19:38 +00:00
|
|
|
if (peer_ip == 0x7f000001) {
|
|
|
|
allowed = true;
|
|
|
|
is_local = true;
|
|
|
|
}
|
|
|
|
|
2005-04-11 20:30:24 +00:00
|
|
|
if (!(gstate.allow_remote_gui_rpc) && !(allowed)) {
|
2004-08-16 09:41:02 +00:00
|
|
|
in_addr ia;
|
|
|
|
ia.s_addr = htonl(peer_ip);
|
2005-02-10 00:35:00 +00:00
|
|
|
show_connect_error(ia);
|
2004-08-16 09:41:02 +00:00
|
|
|
boinc_close_socket(sock);
|
|
|
|
} else {
|
2005-02-16 23:17:43 +00:00
|
|
|
gr = new GUI_RPC_CONN(sock);
|
2005-03-07 06:09:04 +00:00
|
|
|
if (strlen(password)) {
|
|
|
|
gr->auth_needed = true;
|
|
|
|
}
|
2005-04-09 23:19:38 +00:00
|
|
|
gr->is_local = is_local;
|
2004-08-16 09:41:02 +00:00
|
|
|
insert(gr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
iter = gui_rpcs.begin();
|
|
|
|
while (iter != gui_rpcs.end()) {
|
|
|
|
gr = *iter;
|
2005-08-16 20:48:21 +00:00
|
|
|
if (FD_ISSET(gr->sock, &fg.exc_fds)) {
|
2004-08-16 09:41:02 +00:00
|
|
|
delete gr;
|
2006-01-10 20:40:16 +00:00
|
|
|
iter = gui_rpcs.erase(iter);
|
|
|
|
continue;
|
2004-01-21 07:07:16 +00:00
|
|
|
}
|
2006-01-10 20:40:16 +00:00
|
|
|
iter++;
|
2004-08-16 09:41:02 +00:00
|
|
|
}
|
|
|
|
iter = gui_rpcs.begin();
|
|
|
|
while (iter != gui_rpcs.end()) {
|
|
|
|
gr = *iter;
|
2005-08-16 20:48:21 +00:00
|
|
|
if (FD_ISSET(gr->sock, &fg.read_fds)) {
|
2004-08-16 09:41:02 +00:00
|
|
|
retval = gr->handle_rpc();
|
|
|
|
if (retval) {
|
2004-01-21 07:07:16 +00:00
|
|
|
delete gr;
|
2006-01-10 20:40:16 +00:00
|
|
|
iter = gui_rpcs.erase(iter);
|
2004-08-16 09:41:02 +00:00
|
|
|
continue;
|
2004-01-21 07:07:16 +00:00
|
|
|
}
|
|
|
|
}
|
2004-08-16 09:41:02 +00:00
|
|
|
iter++;
|
2004-01-21 07:07:16 +00:00
|
|
|
}
|
|
|
|
}
|
2004-12-08 00:40:19 +00:00
|
|
|
|
2005-01-02 18:29:53 +00:00
|
|
|
const char *BOINC_RCSID_88dd75dd85 = "$Id$";
|