Blob Blame History Raw
From 86d0e9fbd1589dc1849829b3fac1cd6cc45abfa8 Mon Sep 17 00:00:00 2001
From: David Anderson <davea@ssl.berkeley.edu>
Date: Tue, 27 Oct 2020 19:21:49 -0700
Subject: [PATCH 1/4] client: allow an empty GUI RPC password, but generate
 alert message

boinccmd: show alert messages after attach RPCs

PR #3709 disallowed empty GUI RPC password files.
This increased security on shared machines.
But it meant that on Linux, after installing BOINC as a package,
the user had to locate and change the protection
and/or the ownership of the password file, which is undesirable.

This change allows empty password files but tells the user
that they should think about the security implications.
With the Manager this is delivered as a notice.
With boinccmd the message is written to stderr after an attach operation.
---
 client/boinc_cmd.cpp      | 26 ++++++++++++++++++++++++++
 client/gui_rpc_server.cpp | 17 ++++++++---------
 2 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/client/boinc_cmd.cpp b/client/boinc_cmd.cpp
index 38b8170a4c..fd05474f76 100644
--- a/client/boinc_cmd.cpp
+++ b/client/boinc_cmd.cpp
@@ -163,6 +163,30 @@ void acct_mgr_do_rpc(
     }
 }
 
+// Get messages from client, and show any that are USER_ALERT priority.
+// Intended use: show user that GUI RPCs are not password-protected.
+// For now, do this after attach to project or AM
+//
+void show_alerts(RPC_CLIENT &rpc) {
+    MESSAGES messages;
+    int retval = rpc.get_messages(0, messages);
+    if (retval) {
+        fprintf(stderr, "Can't get alerts from client: %s\n",
+            boincerror(retval)
+        );
+        return;
+    }
+    for (unsigned int j=0; j<messages.messages.size(); j++) {
+        MESSAGE& md = *messages.messages[j];
+        if (md.priority != MSG_USER_ALERT) continue;
+        if (!md.project.empty()) continue;
+        strip_whitespace(md.body);
+        fprintf(stderr, "\nAlert from client: %s\n",
+            md.body.c_str()
+        );
+    }
+}
+
 int main(int argc, char** argv) {
     RPC_CLIENT rpc;
     int i, retval, port=0;
@@ -382,6 +406,7 @@ int main(int argc, char** argv) {
         canonicalize_master_url(url, sizeof(url));
         char* auth = next_arg(argc, argv, i);
         retval = rpc.project_attach(url, auth, "");
+        show_alerts(rpc);
     } else if (!strcmp(cmd, "--file_transfer")) {
         FILE_TRANSFER ft;
 
@@ -529,6 +554,7 @@ int main(int argc, char** argv) {
             char* am_name = next_arg(argc, argv, i);
             char* am_passwd = next_arg(argc, argv, i);
             acct_mgr_do_rpc(rpc, am_url, am_name, am_passwd);
+            show_alerts(rpc);
         } else if (!strcmp(op, "info")) {
             ACCT_MGR_INFO ami;
             retval = rpc.acct_mgr_info(ami);
diff --git a/client/gui_rpc_server.cpp b/client/gui_rpc_server.cpp
index 3b14a255f9..c0593d682d 100644
--- a/client/gui_rpc_server.cpp
+++ b/client/gui_rpc_server.cpp
@@ -120,7 +120,7 @@ bool GUI_RPC_CONN_SET::recent_rpc_needs_network(double interval) {
 }
 
 // read the GUI RPC password from gui_rpc_auth.cfg;
-// create one if missing or empty.
+// create one if missing
 //
 void GUI_RPC_CONN_SET::get_password() {
     int retval;
@@ -132,16 +132,15 @@ void GUI_RPC_CONN_SET::get_password() {
             strip_whitespace(password);
         }
         fclose(f);
-        if (strlen(password)) {
-            return;
-        }
 
-        // File is empty; don't allow this.
-        // Fall through and create a password.
+        // if password is empty, allow it but issue a warning
         //
-        msg_printf(NULL, MSG_INFO,
-            "%s is empty - assigning new GUI RPC password", GUI_RPC_PASSWD_FILE
-        );
+        if (!strlen(password)) {
+            msg_printf(NULL, MSG_USER_ALERT,
+                "Warning: GUI RPC password is empty.  BOINC can be controlled by any user on this computer.  See https://boinc.berkeley.edu/gui_rpc_passwd.php for more information."
+            );
+        }
+        return;
     }
 
     // make a random password

From 1cca463736f10710731915faac79c7da2c080665 Mon Sep 17 00:00:00 2001
From: David Anderson <davea@ssl.berkeley.edu>
Date: Fri, 30 Oct 2020 19:16:33 -0700
Subject: [PATCH 2/4] client: strip whitespace when read GUI RPC passwd file

---
 lib/gui_rpc_client.cpp | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/lib/gui_rpc_client.cpp b/lib/gui_rpc_client.cpp
index 1980d6760d..61d1be67e4 100644
--- a/lib/gui_rpc_client.cpp
+++ b/lib/gui_rpc_client.cpp
@@ -478,16 +478,10 @@ int read_gui_rpc_password(char* buf, string& msg) {
         return ERR_FOPEN;
 #endif
     }
-    char* p = fgets(buf, 256, f);
-    if (p) {
-        // trim CR
-        //
-        int n = (int)strlen(buf);
-        if (n && buf[n-1]=='\n') {
-            buf[n-1] = 0;
-        }
+    buf[0] = 0;
+    if (fgets(buf, 256, f)) {
+        strip_whitespace(buf);
     }
     fclose(f);
     return 0;
 }
-

From 2c7c925101ec623e88672ab59ed54298e7bbb444 Mon Sep 17 00:00:00 2001
From: David Anderson <davea@ssl.berkeley.edu>
Date: Sat, 7 Nov 2020 12:40:41 -0800
Subject: [PATCH 3/4] client, linux: improve error msg if can't find GUI RPC
 auth file

---
 lib/gui_rpc_client.cpp | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/lib/gui_rpc_client.cpp b/lib/gui_rpc_client.cpp
index 61d1be67e4..0df494aa5b 100644
--- a/lib/gui_rpc_client.cpp
+++ b/lib/gui_rpc_client.cpp
@@ -455,8 +455,13 @@ int read_gui_rpc_password(char* buf, string& msg) {
                 return ERR_FOPEN;
             }
         } else {
-            sprintf(msg_buf, "%s not found.  Try reinstalling BOINC.",
-                GUI_RPC_PASSWD_FILE
+            char buf2[MAXPATHLEN];
+            if (!getcwd(buf2, MAXPATHLEN)) {
+                strcpy(buf2, "");
+            }
+            sprintf(msg_buf, "No BOINC data directory was specified, and %s was not found in the current directory (%s).  See https://boinc.berkeley.edu/gui_rpc.php for more information.",
+                GUI_RPC_PASSWD_FILE,
+                buf2
             );
             msg = msg_buf;
             return ERR_FOPEN;

From a11bb44f131be94c55f78f6b71513722ed2d88ed Mon Sep 17 00:00:00 2001
From: David Anderson <davea@ssl.berkeley.edu>
Date: Tue, 10 Nov 2020 15:19:23 -0800
Subject: [PATCH 4/4] client, Linux: look for GUI RPC pwd in
 /var/lib/boinc-client after exhausting other options

---
 lib/common_defs.h      |  1 +
 lib/gui_rpc_client.cpp | 50 +++++++++++++++++++++++++++++++-----------
 2 files changed, 38 insertions(+), 13 deletions(-)

diff --git a/lib/common_defs.h b/lib/common_defs.h
index e8082d1346..060ed2a8eb 100644
--- a/lib/common_defs.h
+++ b/lib/common_defs.h
@@ -377,5 +377,6 @@ struct DEVICE_STATUS {
 #define DEFAULT_SS_EXECUTABLE       "boincscr"
 #endif
 #define LINUX_CONFIG_FILE           "/etc/boinc-client/config.properties"
+#define LINUX_DEFAULT_DATA_DIR      "/var/lib/boinc-client"
 
 #endif
diff --git a/lib/gui_rpc_client.cpp b/lib/gui_rpc_client.cpp
index 0df494aa5b..22e9b0997c 100644
--- a/lib/gui_rpc_client.cpp
+++ b/lib/gui_rpc_client.cpp
@@ -401,15 +401,22 @@ int RPC::parse_reply() {
 
 // Look for a GUI RPC password file and read it.
 // If fail, return a prescriptive message.
-// Win/Mac: look in current dir.
-// Linux: also look in a directory specified in
-// /etc/boinc-client/config.properties
+// Win/Mac: look in
+//  - current dir
+// Linux: look in:
+//  - current dir
+//  - a directory specified in /etc/boinc-client/config.properties
+//  - /var/lib/boinc-client
 //
+// Note: the Manager (on all platforms) has a -datadir cmdline option.
+// If present, it chdirs to that directory.
+
 int read_gui_rpc_password(char* buf, string& msg) {
     char msg_buf[1024];
     FILE* f = fopen(GUI_RPC_PASSWD_FILE, "r");
     if (!f) {
 #if defined(__linux__)
+        char path[MAXPATHLEN];
         if (errno == EACCES) {
             sprintf(msg_buf,
                 "%s exists but can't be read.  Check the file permissions.",
@@ -418,9 +425,12 @@ int read_gui_rpc_password(char* buf, string& msg) {
             msg = msg_buf;
             return ERR_FOPEN;
         }
+
+        // look for config file
+        //
         FILE* g = fopen(LINUX_CONFIG_FILE, "r");
         if (g) {
-            char buf2[MAXPATHLEN], path[MAXPATHLEN];
+            char buf2[MAXPATHLEN];
             char *p = 0;
             while (fgets(buf2, MAXPATHLEN, g)) {
                 strip_whitespace(buf2);
@@ -455,16 +465,30 @@ int read_gui_rpc_password(char* buf, string& msg) {
                 return ERR_FOPEN;
             }
         } else {
-            char buf2[MAXPATHLEN];
-            if (!getcwd(buf2, MAXPATHLEN)) {
-                strcpy(buf2, "");
+            // no config file; look in default data dir
+            //
+            sprintf(path, "%s/%s", LINUX_DEFAULT_DATA_DIR, GUI_RPC_PASSWD_FILE);
+            f = fopen(path, "r");
+            if (!f) {
+                if (errno == EACCES) {
+                    sprintf(msg_buf,
+                        "%s exists but can't be read.  Check the file permissions.",
+                        path
+                    );
+                    msg = msg_buf;
+                    return ERR_FOPEN;
+                }
+                char buf2[MAXPATHLEN];
+                if (!getcwd(buf2, MAXPATHLEN)) {
+                    strcpy(buf2, "");
+                }
+                sprintf(msg_buf, "No BOINC data directory was specified, and %s was not found in the current directory (%s).  See https://boinc.berkeley.edu/gui_rpc.php for more information.",
+                    GUI_RPC_PASSWD_FILE,
+                    buf2
+                );
+                msg = msg_buf;
+                return ERR_FOPEN;
             }
-            sprintf(msg_buf, "No BOINC data directory was specified, and %s was not found in the current directory (%s).  See https://boinc.berkeley.edu/gui_rpc.php for more information.",
-                GUI_RPC_PASSWD_FILE,
-                buf2
-            );
-            msg = msg_buf;
-            return ERR_FOPEN;
         }
 #else
         // non-Linux