OPENAFS-SA-2018-001 butc: require authenticated connections with -localauth
authorBenjamin Kaduk <kaduk@mit.edu>
Thu, 6 Sep 2018 23:50:39 +0000 (18:50 -0500)
committerBenjamin Kaduk <kaduk@mit.edu>
Sun, 9 Sep 2018 22:35:29 +0000 (17:35 -0500)
The butc -localauth option is available to use the cell-wide key to
authenticate to the vlserver and buserver, which in normal deployments
will require incoming connections to be authenticated as a superuser.
In such cases, the cell-wide key is also available for use in
authenticating incoming connections to the butc, which would otherwise
have been completely unauthenticated.

Because of the security hazards of allowing unauthenticaed inbound
RPCs, especially ones that manipulate backup information and are allowed
to initiate outboud RPCs authenticated as the superuser, default to
not allowing unauthenticated inbound RPCs at all.  Provide an opt-out
command-line argument for deployments that require this functionality
and have configured their network environment (firewall/etc.) appropriately.

Change-Id: Ia6349757a4c6d59d1853df1a844e210d32c14feb

doc/man-pages/pod8/butc.pod
src/butc/butc_prototypes.h
src/butc/tcmain.c
src/butc/tcprocs.c

index e836d39..42c72da 100644 (file)
@@ -9,11 +9,13 @@ butc - Initializes the Tape Coordinator process
 
 B<butc> S<<< [B<-port> <I<port offset>>] >>> S<<< [B<-debuglevel> (0 | 1 | 2)] >>>
     S<<< [B<-cell> <I<cell name>>] >>> [B<-noautoquery>] [B<-rxbind>] [B<-localauth>]
-    [B<-auditlog> <I<file | sysvmq>> [B<-audit-interface> <I<interface>>]] [B<-help>]
+    [B<-auditlog> <I<file | sysvmq>> [B<-audit-interface> <I<interface>>]]
+    [B<-allow_unauthenticated>] [B<-help>]
 
 B<butc> S<<< [B<-p> <I<port offset>>] >>> S<<< [B<-d> (0 | 1 | 2)] >>>
     S<<< [B<-c> <I<cell name>>] >>> [B<-n>] [B<-r>] [B<-l>]
-    [B<-auditl> <I<file | sysvmq>> [-B<-audit-i> <I<interface>>]] [B<-h>]
+    [B<-auditl> <I<file | sysvmq>> [-B<-audit-i> <I<interface>>]]
+    [B<-al>] [B<-h>]
 
 =for html
 </div>
@@ -201,6 +203,16 @@ succeeded or failed.
 Specifies what audit interface to use. Defaults to C<file>. See
 L<fileserver(8)> for an explanation of each interface.
 
+=item B<-allow_unauthenticated>
+
+By default the B<butc> requires clients performing TC_ RPCs to authenticate
+themselves, behavior introduced in the fix for OPENAFS-SA-2018-001.
+This option reverts to the historical behavior of only using the rxnull
+security class for incoming connections.  Use of this option is strongly
+disrecommended; it is provided only for backwards compatibility with older
+clients in environments where B<backup> and B<butc> communicate over a secure
+network that denies access to untrusted parties.
+
 =item B<-help>
 
 Prints the online help for this command. All other valid options are
index a1d7712..85a3799 100644 (file)
@@ -35,6 +35,7 @@ extern void *KeepAlive(void *);
 /* tcmain.c */
 
 extern struct afsconf_dir *butc_confdir;
+extern int allow_unauth;
 
 #endif
 
index 7f79fa7..c539939 100644 (file)
@@ -107,6 +107,7 @@ char *centralLogFile;
 afs_int32 lastLog;             /* Log last pass info */
 int rxBind = 0;
 struct afsconf_dir *butc_confdir;
+int allow_unauth = 0;
 
 #define ADDRSPERSITE 16         /* Same global is in rx/rx_user.c */
 afs_uint32 SHostAddrs[ADDRSPERSITE];
@@ -843,8 +844,8 @@ tc_IsLocalRealmMatch(void *rock, char *name, char *inst, char *cell)
 static int
 WorkerBee(struct cmd_syndesc *as, void *arock)
 {
-    afs_int32 code;
-    struct rx_securityClass *(securityObjects[1]);
+    afs_int32 code, numClasses;
+    struct rx_securityClass *(nullObjects[1]), **secObjs, **allObjs;
     struct rx_service *service;
     time_t tokenExpires;
     char cellName[64];
@@ -1070,6 +1071,13 @@ WorkerBee(struct cmd_syndesc *as, void *arock)
 
     localauth = (as->parms[5].items ? 1 : 0);
     rxBind = (as->parms[8].items ? 1 : 0);
+    allow_unauth = (as->parms[11].items ? 1 : 0);
+
+    if (!allow_unauth && !localauth) {
+       const char *errstr = "Neither -localauth nor -allow_unauthenticated was provided; refusing to start in unintended insecure configuration\n";
+       TLog(0, "%s", (char *)errstr);
+       exit(1);
+    }
 
     if (rxBind) {
         afs_int32 ccode;
@@ -1114,19 +1122,48 @@ WorkerBee(struct cmd_syndesc *as, void *arock)
 
     /* initialize database support, volume support, and logs */
 
-    /* Create a single security object, in this case the null security
-     * object, for unauthenticated connections, which will be used to control
-     * security on connections made to this server
+    /*
+     * Create security objects for the Rx server functionality.  Historically
+     * this was a single rxnull security object, since the tape controller was
+     * run by an operator that had local access to the tape device and some
+     * administrative privilege in the cell (to be able to perform volume-level
+     * accesses), but on a machine that was not necessarily trusted to hold the
+     * cell-wide key.
+     *
+     * Such a configuration is, of course, insecure because anyone can make
+     * inbound RPCs and manipulate the database, including creating bogus
+     * dumps and restoring them!  Additionally, in modern usage, butc is
+     * frequently run with -localauth to authenticate its outbound connections
+     * to the volservers and budb with the cell-wide key, in which case the
+     * cell-wide key is present and could be used to authenticate incoming
+     * connections as well.
+     *
+     * If -localauth is in use, create the full barrage of server security
+     * objects, including rxkad, so that inbound connections can be verified
+     * to only be made by authenticated clients.  Otherwise, only the rxnull
+     * class is in use with a single server security object.  Note that butc
+     * will refuse to start in this configuration unless the
+     * "-allow_unauthenticated" flag is provided, indicating that the operator
+     * has ensured that incoming connections are appropriately restricted by
+     * firewall configuration or network topology.
      */
 
-    securityObjects[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject();
-    if (!securityObjects[RX_SECIDX_NULL]) {
-       TLog(0, "rxnull_NewServerSecurityObject");
-       exit(1);
+    if (allow_unauth) {
+       nullObjects[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject();
+       if (!nullObjects[RX_SECIDX_NULL]) {
+           TLog(0, "rxnull_NewServerSecurityObject");
+           exit(1);
+       }
+       numClasses = 1;
+       secObjs = nullObjects;
+    } else {
+       /* Must be -localauth, so the cell keys are available. */
+       afsconf_BuildServerSecurityObjects(butc_confdir, &allObjs, &numClasses);
+       secObjs = allObjs;
     }
 
     service =
-       rx_NewServiceHost(host, 0, 1, "BUTC", securityObjects, 1, TC_ExecuteRequest);
+       rx_NewServiceHost(host, 0, 1, "BUTC", secObjs, numClasses, TC_ExecuteRequest);
     if (!service) {
        TLog(0, "rx_NewService");
        exit(1);
@@ -1232,6 +1269,8 @@ main(int argc, char **argv)
     cmd_AddParm(ts, "-auditlog", CMD_SINGLE, CMD_OPTIONAL, "location of audit log");
     cmd_AddParm(ts, "-audit-interface", CMD_SINGLE, CMD_OPTIONAL,
                "interface to use for audit logging");
+    cmd_AddParm(ts, "-allow_unauthenticated", CMD_FLAG, CMD_OPTIONAL,
+               "allow unauthenticated inbound RPCs (requires firewalling)");
 
     /* Initialize dirpaths */
     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
index 7f0e40c..c51b1f1 100644 (file)
@@ -62,12 +62,12 @@ int
 callPermitted(struct rx_call *call)
 {
     /*
-     * Before this code can be used, the rx connection, on the bucoord side,
-     * must be changed so that it will set up for token passing instead of
-     * using a simple rx connection that, below, returns a value of
-     * RX_SECIDX_NULL from rx_SecurityClassOf.
+     * If in backwards compat mode, allow anyone; otherwise, only
+     * superusers are allowed.
      */
-    return 1;
+    if (allow_unauth)
+       return 1;
+    return afsconf_SuperIdentity(butc_confdir, call, NULL);
 }
 
 /* -----------------------------