viced: add opt to allow admin writes on RO servers 07/13707/7
authorMarcio Barbosa <mbarbosa@sinenomine.net>
Thu, 14 Nov 2019 20:29:56 +0000 (17:29 -0300)
committerBenjamin Kaduk <kaduk@mit.edu>
Fri, 6 Dec 2019 04:10:48 +0000 (23:10 -0500)
Add the new option -admin-write to allow write requests from superusers
on file servers running in readonly mode (-readonly). This lets sites
run fileservers in readonly mode for normal users, but allows members of
the system:administrators group to modify content.

Change-Id: Id8ed3513a748815c07cb98e426c1d21ac300b416
Reviewed-on: https://gerrit.openafs.org/13707
Reviewed-by: Andrew Deason <adeason@sinenomine.net>
Tested-by: Andrew Deason <adeason@sinenomine.net>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

doc/man-pages/pod8/fragments/dafileserver-synopsis.pod
doc/man-pages/pod8/fragments/fileserver-options.pod
doc/man-pages/pod8/fragments/fileserver-synopsis.pod
src/viced/afsfileprocs.c
src/viced/viced.c

index 91a1550..1e74123 100644 (file)
@@ -15,6 +15,7 @@ B<dafileserver>
     S<<< [B<-novbc>] >>>
     S<<< [B<-implicit> <I<admin mode bits: rlidwka>>] >>>
     S<<< [B<-readonly>] >>>
+    S<<< [B<-admin-write>] >>>
     S<<< [B<-hr> <I<number of hours between refreshing the host cps>>] >>>
     S<<< [B<-busyat> <I<< redirect clients when queue > n >>>] >>>
     S<<< [B<-nobusy>] >>>
index 378f630..1652303 100644 (file)
@@ -127,6 +127,12 @@ permissions, see the B<fs setacl> reference page.
 
 Don't allow writes to this fileserver.
 
+=item B<-admin-write>
+
+Allows write requests for members of system:administrators on the read-only
+fileserver in question. The C<-admin-write> option has no effect when the
+C<-readonly> is not specified.
+
 =item B<-hr> <I<number of hours between refreshing the host cps>>
 
 Specifies how often the File Server refreshes its knowledge of the
index c949d6e..203d7a3 100644 (file)
@@ -15,6 +15,7 @@ B<fileserver>
     S<<< [B<-novbc>] >>>
     S<<< [B<-implicit> <I<admin mode bits: rlidwka>>] >>>
     S<<< [B<-readonly>] >>>
+    S<<< [B<-admin-write>] >>>
     S<<< [B<-hr> <I<number of hours between refreshing the host cps>>] >>>
     S<<< [B<-busyat> <I<< redirect clients when queue > n >>>] >>>
     S<<< [B<-nobusy>] >>>
index 53fc8ac..8f72110 100644 (file)
@@ -179,6 +179,7 @@ afs_int32 BlocksSpare = 1024;       /* allow 1 MB overruns */
 afs_int32 PctSpare;
 extern afs_int32 implicitAdminRights;
 extern afs_int32 readonlyServer;
+extern afs_int32 adminwriteServer;
 extern int CopyOnWrite_calls, CopyOnWrite_off0, CopyOnWrite_size0;
 extern afs_fsize_t CopyOnWrite_maxsize;
 
@@ -1007,6 +1008,30 @@ VolumeRootVnode(Vnode * targetptr)
 
 }                              /*VolumeRootVnode */
 
+/**
+ * Check if server can perform writes.
+ *
+ * This functions checks if the fileserver is read-only for the client received
+ * as an argument. Read-only fileservers allow write requests for members of
+ * system:administrators when started with both -readonly and -admin-write.
+ *
+ * @param[in]  client  calling user
+ *
+ * @return 1 if not read-only for this user; 0 otherwise
+ */
+static int
+IsWriteAllowed(struct client *client)
+{
+    if (readonlyServer) {
+       if (adminwriteServer && !VanillaUser(client)) {
+           /* admins can write */
+           return 1;
+       }
+       return 0;
+    }
+    return 1;
+}
+
 /*
  * Check if target file has the proper access permissions for the Fetch
  * (FetchData, FetchACL, FetchStatus) and Store (StoreData, StoreACL,
@@ -1077,7 +1102,7 @@ Check_PermissionRights(Vnode * targetptr, struct client *client,
                      AUD_END);
        }
     } else {                   /* a store operation */
-       if (readonlyServer) {
+       if (!IsWriteAllowed(client)) {
            return (VREADONLY);
        }
        if ((rights & PRSFS_INSERT) && OWNSp(client, targetptr)
@@ -2013,9 +2038,10 @@ HandleLocking(Vnode * targetptr, struct client *client, afs_int32 rights, ViceLo
 /* Checks if caller has the proper AFS and Unix (WRITE) access permission to the target directory; Prfs_Mode refers to the AFS Mode operation while rights contains the caller's access permissions to the directory. */
 
 static afs_int32
-CheckWriteMode(Vnode * targetptr, afs_int32 rights, int Prfs_Mode)
+CheckWriteMode(Vnode * targetptr, afs_int32 rights, int Prfs_Mode,
+              struct client *client)
 {
-    if (readonlyServer)
+    if (!IsWriteAllowed(client))
        return (VREADONLY);
     if (!(rights & Prfs_Mode))
        return (EACCES);
@@ -3281,7 +3307,7 @@ SAFSS_RemoveFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     SetVolumeSync(Sync, volptr);
 
     /* Does the caller has delete (& write) access to the parent directory? */
-    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
+    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE, client))) {
        goto Bad_RemoveFile;
     }
 
@@ -3420,7 +3446,7 @@ SAFSS_CreateFile(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     SetVolumeSync(Sync, volptr);
 
     /* Can we write (and insert) onto the parent directory? */
-    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
+    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client))) {
        goto Bad_CreateFile;
     }
 
@@ -3614,10 +3640,11 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
     /* set volume synchronization information */
     SetVolumeSync(Sync, volptr);
 
-    if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE))) {
+    if ((errorCode = CheckWriteMode(oldvptr, rights, PRSFS_DELETE, client))) {
        goto Bad_Rename;
     }
-    if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT))) {
+    if ((errorCode = CheckWriteMode(newvptr, newrights, PRSFS_INSERT,
+                                   client))) {
        goto Bad_Rename;
     }
 
@@ -3697,7 +3724,7 @@ SAFSS_Rename(struct rx_call *acall, struct AFSFid *OldDirFid, char *OldName,
         goto Bad_Rename;
     }
     if (!code) {
-       if (readonlyServer) {
+       if (!IsWriteAllowed(client)) {
            errorCode = VREADONLY;
            goto Bad_Rename;
        }
@@ -4073,7 +4100,7 @@ SAFSS_Symlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     SetVolumeSync(Sync, volptr);
 
     /* Does the caller has insert (and write) access to the parent directory? */
-    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT)))
+    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client)))
        goto Bad_SymLink;
 
     /*
@@ -4082,7 +4109,7 @@ SAFSS_Symlink(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
      * to do this.
      */
     if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
-       if (readonlyServer) {
+       if (!IsWriteAllowed(client)) {
            errorCode = VREADONLY;
            goto Bad_SymLink;
        }
@@ -4253,7 +4280,7 @@ SAFSS_Link(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     SetVolumeSync(Sync, volptr);
 
     /* Can the caller insert into the parent directory? */
-    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
+    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client))) {
        goto Bad_Link;
     }
 
@@ -4437,10 +4464,11 @@ SAFSS_MakeDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
      * implcit a access that goes with dir ownership, and proceed to
      * subvert quota in the volume.
      */
-    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))
-       || (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE))) {
+    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client))
+       || (errorCode = CheckWriteMode(parentptr, rights, PRSFS_WRITE,
+                                      client))) {
 #else
-    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT))) {
+    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_INSERT, client))) {
 #endif /* DIRCREATE_NEED_WRITE */
        goto Bad_MakeDir;
     }
@@ -4586,7 +4614,7 @@ SAFSS_RemoveDir(struct rx_call *acall, struct AFSFid *DirFid, char *Name,
     SetVolumeSync(Sync, volptr);
 
     /* Does the caller has delete (&write) access to the parent dir? */
-    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE))) {
+    if ((errorCode = CheckWriteMode(parentptr, rights, PRSFS_DELETE, client))) {
        goto Bad_RemoveDir;
     }
 
@@ -5944,7 +5972,7 @@ SRXAFS_SetVolumeStatus(struct rx_call * acall, afs_int32 avolid,
                          &rights, &anyrights)))
        goto Bad_SetVolumeStatus;
 
-    if (readonlyServer) {
+    if (!IsWriteAllowed(client)) {
        errorCode = VREADONLY;
        goto Bad_SetVolumeStatus;
     }
index 832b4b1..93ec003 100644 (file)
@@ -127,6 +127,7 @@ int rxMaxMTU = -1;
 afs_int32 implicitAdminRights = PRSFS_LOOKUP;  /* The ADMINISTER right is
                                                 * already implied */
 afs_int32 readonlyServer = 0;
+afs_int32 adminwriteServer = 0;
 
 int stackSize = 24000;
 int fiveminutes = 300;         /* 5 minutes.  Change this for debugging only */
@@ -889,6 +890,7 @@ enum optionsList {
     OPT_implicit,
     OPT_lock,
     OPT_readonly,
+    OPT_adminwrite,
     OPT_saneacls,
     OPT_buffers,
     OPT_callbacks,
@@ -982,6 +984,9 @@ ParseArgs(int argc, char *argv[])
 #endif
     cmd_AddParmAtOffset(opts, OPT_readonly, "-readonly", CMD_FLAG,
                        CMD_OPTIONAL, "be a readonly fileserver");
+    cmd_AddParmAtOffset(opts, OPT_adminwrite, "-admin-write", CMD_FLAG,
+                       CMD_OPTIONAL, "if read-only, allow writes for users "
+                       "from system:administrators");
     cmd_AddParmAtOffset(opts, OPT_saneacls, "-saneacls", CMD_FLAG,
                        CMD_OPTIONAL, "set the saneacls capability bit");
 
@@ -1183,6 +1188,7 @@ ParseArgs(int argc, char *argv[])
     cmd_OptionAsFlag(opts, OPT_lock, &SawLock);
 #endif
     cmd_OptionAsFlag(opts, OPT_readonly, &readonlyServer);
+    cmd_OptionAsFlag(opts, OPT_adminwrite, &adminwriteServer);
     cmd_OptionAsFlag(opts, OPT_saneacls, &saneacls);
     cmd_OptionAsInt(opts, OPT_buffers, &buffs);