[distcc] Simple authentication for distcc

Grahame Bowland grahame at angrygoats.net
Wed Feb 18 19:13:19 GMT 2004


Hi guys

I'd love to hear some feedback from people on this patch. It modifies 
the distcc protocol slightly, so that connecting clients may need to 
send a "PASS" token followed by a passphrase if the server has been 
configured to require one.

The patch is simple enough - it's against the 2.12.1 from Debian.

To use passphrases with the patch, run distccd with --passphrase-file 
<filename>, where filename contains the passphrase, and either export 
DISTCC_PASSPHRASE=whatever or create a ~/.distcc/passphrase file.

I know this doesn't add any security if the local network is 
compromised, however it should mean you can run distcc without anyone by 
being able to just connect if they manage to get through your firewall. 
Also, you don't take the speed hit assocciated with distcc over SSH.

Martin already said he'd never merge a patch like this - I'm still 
willing to maintain it though :)

Cheers
Grahame

-------------- next part --------------
Only in distcc-2.12.1+auth: Makefile
diff -ur distcc-2.12.1/Makefile.in distcc-2.12.1+auth/Makefile.in
--- distcc-2.12.1/Makefile.in	2004-01-09 10:02:28.000000000 +0800
+++ distcc-2.12.1+auth/Makefile.in	2004-02-18 19:05:34.000000000 +0800
@@ -187,6 +187,7 @@
 
 distccd_obj = src/access.o						\
 	src/daemon.o  src/dopt.o src/dparent.o src/dsignal.o		\
+	src/loadfile.o							\
 	src/ncpus.o							\
 	src/prefork.o							\
 	src/serve.o src/setuid.o src/srvnet.o src/srvrpc.o		\
Only in distcc-2.12.1+auth: build-arch-stamp
Only in distcc-2.12.1+auth: build-indep-stamp
Only in distcc-2.12.1+auth: config.status
diff -ur distcc-2.12.1/debian/changelog distcc-2.12.1+auth/debian/changelog
--- distcc-2.12.1/debian/changelog	2004-02-19 02:52:53.000000000 +0800
+++ distcc-2.12.1+auth/debian/changelog	2004-02-19 02:49:39.000000000 +0800
@@ -1,3 +1,9 @@
+distcc (2.12.1-2auth) unstable; urgency=low
+
+  * add evil passphrase authentication patch
+
+ -- Grahame Bowland <grahame at angrygoats.net>  Thu, 19 Feb 2004 02:49:07 +0800
+
 distcc (2.12.1-2) unstable; urgency=low
 
   * distcc starts only if STARTDISTCC in /etc/default/distcc is
Only in distcc-2.12.1+auth/debian: distcc
Only in distcc-2.12.1+auth/debian: distcc.postinst.debhelper
Only in distcc-2.12.1+auth/debian: distcc.postrm.debhelper
Only in distcc-2.12.1+auth/debian: distcc.prerm.debhelper
Only in distcc-2.12.1+auth/debian: distcc.substvars
Only in distcc-2.12.1+auth/debian: distccmon-gnome
Only in distcc-2.12.1+auth/debian: distccmon-gnome.postinst.debhelper
Only in distcc-2.12.1+auth/debian: distccmon-gnome.postrm.debhelper
Only in distcc-2.12.1+auth/debian: distccmon-gnome.substvars
Only in distcc-2.12.1+auth/debian: files
Only in distcc-2.12.1+auth/debian: tmp
diff -ur distcc-2.12.1/src/access.c distcc-2.12.1+auth/src/access.c
--- distcc-2.12.1/src/access.c	2003-09-29 14:26:18.000000000 +0800
+++ distcc-2.12.1+auth/src/access.c	2004-02-18 19:01:22.000000000 +0800
@@ -44,6 +44,8 @@
 #include "access.h"
 #include "exitcode.h"
 
+extern char *opt_passphrase_str; 
+
 /**
  * @file
  *
@@ -124,3 +126,22 @@
         return EXIT_ACCESS_DENIED;
     }
 }
+
+
+/**
+ * Check whether a client has sent the appropriate passphrase.
+ *
+ * @returns 0 for allowed, or EXIT_ACCESS_DENIED.
+ **/
+int dcc_check_passphrase(const char *passphrase)
+{
+	if (strcmp(passphrase, opt_passphrase_str)) {
+		return EXIT_ACCESS_DENIED;
+	}
+
+	return 0;
+}
+
+
+
+
diff -ur distcc-2.12.1/src/access.h distcc-2.12.1+auth/src/access.h
--- distcc-2.12.1/src/access.h	2003-01-28 21:49:24.000000000 +0800
+++ distcc-2.12.1+auth/src/access.h	2004-02-19 02:55:37.000000000 +0800
@@ -20,6 +20,10 @@
  * USA
  */
 
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
 /* access.c */
 int dcc_parse_mask(const char *mask_spec,
                    in_addr_t *value,
@@ -29,7 +33,11 @@
                       in_addr_t value,
                       in_addr_t mask);
 
+
+int dcc_check_passphrase(const char *passphrase);
+
 struct dcc_allow_list {
     in_addr_t           addr, mask;
     struct dcc_allow_list *next;
 };
+
diff -ur distcc-2.12.1/src/clirpc.c distcc-2.12.1+auth/src/clirpc.c
--- distcc-2.12.1/src/clirpc.c	2003-09-23 12:07:01.000000000 +0800
+++ distcc-2.12.1+auth/src/clirpc.c	2004-02-19 02:23:17.000000000 +0800
@@ -44,6 +44,9 @@
 #include "hosts.h"
 #include "state.h"
 #include "arg.h"
+#include "access.h"
+
+extern char *dcc_passphrase;
 
 /**
  * @file
@@ -60,7 +63,13 @@
      return dcc_x_token_int(fd, "DIST", protover);
 }
 
-
+/*
+ * Transmit passphrase for whole request.
+ */
+static int dcc_x_passphrase(int fd)
+{
+     return dcc_x_token_string(fd, "PASS", dcc_passphrase);
+}
 
 /**
  * Transmit an argv array.
@@ -94,8 +103,13 @@
 {
     int ret;
 
-    if ((ret = dcc_x_req_header(net_fd, host->protover))
-        || (ret = dcc_x_argv(net_fd, argv)))
+    if ((ret = dcc_x_req_header(net_fd, host->protover)))
+        return ret;
+    if (dcc_passphrase) {
+        if ((ret = dcc_x_passphrase(net_fd)))
+            return ret;
+    }
+    if ((ret = dcc_x_argv(net_fd, argv)))
         return ret;
 
     if (cpp_pid) {
Only in distcc-2.12.1+auth/src: config.h
diff -ur distcc-2.12.1/src/distcc.c distcc-2.12.1+auth/src/distcc.c
--- distcc-2.12.1/src/distcc.c	2003-10-13 17:59:25.000000000 +0800
+++ distcc-2.12.1+auth/src/distcc.c	2004-02-18 19:00:46.000000000 +0800
@@ -56,6 +56,9 @@
 /* Name of this program, for trace.c */
 const char *rs_program_name = "distcc";
 
+/* Passphrase */
+char *dcc_passphrase = NULL;
+
 
 /**
  * @file
@@ -163,6 +166,8 @@
 
     dcc_trace_version();
 
+    dcc_passphrase = dcc_get_passphrase();
+
     compiler_name = (char *) dcc_find_basename(argv[0]);
 
     /* Ignore SIGPIPE; we consistently check error codes and will
diff -ur distcc-2.12.1/src/dopt.c distcc-2.12.1+auth/src/dopt.c
--- distcc-2.12.1/src/dopt.c	2004-01-09 09:07:43.000000000 +0800
+++ distcc-2.12.1+auth/src/dopt.c	2004-02-18 19:01:47.000000000 +0800
@@ -93,11 +93,14 @@
 const char *arg_pid_file = NULL;
 const char *arg_log_file = NULL;
 
+char *opt_passphrase_str = NULL;
+
 /* Enumeration values for options that don't have single-letter name.  These
  * must be numerically above all the ascii letters. */
 enum {
     opt_log_to_file = 300,
-    opt_log_level
+    opt_log_level, 
+    opt_passphrase
 };
 
 
@@ -118,6 +121,7 @@
     { "no-fork", 0,      POPT_ARG_NONE, &opt_no_fork, 0, 0, 0 },
     { "no-prefork", 0,   POPT_ARG_NONE, &opt_no_prefork, 0, 0, 0 },
     { "pid-file", 'P',   POPT_ARG_STRING, &arg_pid_file, 0, 0, 0 },
+    { "passphrase-file", 0, POPT_ARG_STRING, 0, opt_passphrase, 0, 0 },
     { "port", 'p',       POPT_ARG_INT, &arg_port,      0, 0, 0 },
     { "user", 0,         POPT_ARG_STRING, &opt_user, 'u', 0, 0 },
     { "verbose", 0,      POPT_ARG_NONE, 0, 'v', 0, 0 },
@@ -146,6 +150,7 @@
 "    -p, --port PORT            TCP port to listen on\n"
 "    --listen ADDRESS           IP address to listen on\n"
 "    -a, --allow IP[/BITS]      client address access control\n"
+"    --passphrase-file FILE     file containing required passphrase\n"
 "  Debug and trace:\n"
 "    --log-level=LEVEL          set detail level for log file\n"
 "      levels: critical, error, warning, notice, info, debug\n"
@@ -230,6 +235,20 @@
             }
             break;
 
+        case opt_passphrase:
+            {
+                const char *passphrase_file_name;
+		int lo_err;
+
+                passphrase_file_name = poptGetOptArg(po);
+		lo_err = dcc_load_file_string(passphrase_file_name, &opt_passphrase_str);
+		if (lo_err) {
+			exitcode = lo_err;
+			goto out_exit;
+		}
+            }
+            break;
+
         case 'v':
             rs_trace_set_level(RS_LOG_DEBUG);
             break;
diff -ur distcc-2.12.1/src/hosts.c distcc-2.12.1+auth/src/hosts.c
--- distcc-2.12.1/src/hosts.c	2003-07-21 10:00:38.000000000 +0800
+++ distcc-2.12.1+auth/src/hosts.c	2004-02-18 22:31:37.000000000 +0800
@@ -91,6 +91,7 @@
 #include <ctype.h>
 
 #include "distcc.h"
+#include "io.h"
 #include "trace.h"
 #include "util.h"
 #include "hosts.h"
@@ -169,6 +170,64 @@
     return EXIT_BAD_HOSTSPEC;
 }
 
+/**
+ * Get a passphrase to use for each host.
+ *
+ * Passphrase is taken from DISTCC_PASSPHRASE, if that exists.  Otherwise, it is
+ * taken from ~/.distcc/passphrase, if that exists.  Otherwise, it is taken from
+ * ${sysconfdir}/distcc/passphrase, if that exists.  Otherwise, we fail.
+ **/
+char *dcc_get_passphrase(void)
+{
+    char *env;
+    char *path;
+    char *home;
+    char *passphrase;
+    int ret;
+
+    if ((env = getenv("DISTCC_PASSPHRASE")) != NULL) {
+        rs_trace("read passphrase from environment");
+	/* avoid child processes getting this information */
+	unsetenv("DISTCC_PASSPHRASE");
+        return env;
+    }
+
+    /* ~/.distcc/passphrase */
+    if ((home = getenv("HOME")) != NULL) {
+        asprintf(&path, "%s/.distcc/passphrase", home);
+        if (access(path, R_OK) == 0) {
+            ret = dcc_load_file_string(path, &passphrase);
+	    if (ret) {
+                rs_trace("error reading passphrase from %s: %s", path, strerror(errno));
+		free(path);
+                return NULL;
+            }
+            free(path);
+            return passphrase;
+        } else {
+            rs_trace("not reading %s: %s", path, strerror(errno));
+            free(path);
+        }
+    }
+
+    asprintf(&path, "%s/distcc/passphrase", SYSCONFDIR);
+    if (access(path, R_OK) == 0) {
+        ret = dcc_load_file_string(path, &passphrase);
+        if (ret) {
+             rs_trace("error reading passphrase from %s: %s", path, strerror(errno));
+             free(path);
+             return NULL;
+        }
+        free(path);
+        return passphrase;
+    } else {
+        rs_trace("not reading %s: %s", path, strerror(errno));
+        free(path);
+    }
+    
+    return NULL;
+}
+
 
 /**
  * Parse an optionally present multiplier.
diff -ur distcc-2.12.1/src/hosts.h distcc-2.12.1+auth/src/hosts.h
--- distcc-2.12.1/src/hosts.h	2003-07-18 11:10:16.000000000 +0800
+++ distcc-2.12.1+auth/src/hosts.h	2004-02-18 18:55:45.000000000 +0800
@@ -63,6 +63,8 @@
 int dcc_get_hostlist(struct dcc_hostdef **ret_list,
                      int *ret_nhosts);
 
+char *dcc_get_passphrase(void);
+
 int dcc_free_hostdef(struct dcc_hostdef *host);
 
 
diff -ur distcc-2.12.1/src/rpc.h distcc-2.12.1+auth/src/rpc.h
--- distcc-2.12.1/src/rpc.h	2003-07-22 15:27:17.000000000 +0800
+++ distcc-2.12.1+auth/src/rpc.h	2004-02-18 16:28:02.000000000 +0800
@@ -41,4 +41,5 @@
 
 /* srvrpc.c */
 int dcc_r_request_header(int ifd, enum dcc_protover *);
+int dcc_r_passphrase(int ifd);
 int dcc_r_argv(int ifd, /*@out@*/ char ***argv);
diff -ur distcc-2.12.1/src/serve.c distcc-2.12.1+auth/src/serve.c
--- distcc-2.12.1/src/serve.c	2003-11-17 11:00:15.000000000 +0800
+++ distcc-2.12.1+auth/src/serve.c	2004-02-18 19:02:31.000000000 +0800
@@ -87,6 +87,7 @@
 #include "daemon.h"
 #include "arg.h"
 
+extern char *opt_passphrase_str;
 
 /**
  * We copy all serious distccd messages to this file, as well as sending the
@@ -280,8 +281,15 @@
     /* Allow output to accumulate into big packets. */
     tcp_cork_sock(out_fd, 1);
 
-    if ((ret = dcc_r_request_header(in_fd, &protover))
-        || (ret = dcc_r_argv(in_fd, &argv))
+    if ((ret = dcc_r_request_header(in_fd, &protover)))
+        goto out_cleanup;
+
+    if (opt_passphrase_str) {
+        if ((ret = dcc_r_passphrase(in_fd)))
+            goto out_cleanup;
+    }
+
+    if ((ret = dcc_r_argv(in_fd, &argv))
         || (ret = dcc_scan_args(argv, &orig_input, &orig_output, &argv)))
         goto out_cleanup;
     
diff -ur distcc-2.12.1/src/srvrpc.c distcc-2.12.1+auth/src/srvrpc.c
--- distcc-2.12.1/src/srvrpc.c	2003-07-18 09:45:55.000000000 +0800
+++ distcc-2.12.1+auth/src/srvrpc.c	2004-02-18 17:43:18.000000000 +0800
@@ -48,6 +48,7 @@
 #include "filename.h"
 #include "hosts.h"
 #include "arg.h"
+#include "access.h"
 
 
 int dcc_r_request_header(int ifd,
@@ -71,7 +72,19 @@
     return 0;
 }
 
+int dcc_r_passphrase(int ifd)
+{
+	char *pass_rcv;
+	int ret;
+
+        if ((ret = dcc_r_token_string(ifd, "PASS", &pass_rcv)))
+		return ret;
 
+	ret = dcc_check_passphrase(pass_rcv);
+	if (ret)
+		rs_log_error("connection denied due to incorrect passphrase");
+	return ret;
+}
 
 /**
  * Read an argv[] vector from the network.


More information about the distcc mailing list