From f5f8b9336919debc5c26c429b12a14b65e0b697c Mon Sep 17 00:00:00 2001 From: Marcio Barbosa Date: Thu, 14 Nov 2019 17:29:56 -0300 Subject: [PATCH] viced: add opt to allow admin writes on RO servers 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 Tested-by: Andrew Deason Reviewed-by: Benjamin Kaduk --- .../pod8/fragments/dafileserver-synopsis.pod | 1 + .../pod8/fragments/fileserver-options.pod | 6 +++ .../pod8/fragments/fileserver-synopsis.pod | 1 + src/viced/afsfileprocs.c | 60 ++++++++++++++++------ src/viced/viced.c | 6 +++ 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/doc/man-pages/pod8/fragments/dafileserver-synopsis.pod b/doc/man-pages/pod8/fragments/dafileserver-synopsis.pod index 91a1550..1e74123 100644 --- a/doc/man-pages/pod8/fragments/dafileserver-synopsis.pod +++ b/doc/man-pages/pod8/fragments/dafileserver-synopsis.pod @@ -15,6 +15,7 @@ B S<<< [B<-novbc>] >>> S<<< [B<-implicit> >] >>> S<<< [B<-readonly>] >>> + S<<< [B<-admin-write>] >>> S<<< [B<-hr> >] >>> S<<< [B<-busyat> n >>>] >>> S<<< [B<-nobusy>] >>> diff --git a/doc/man-pages/pod8/fragments/fileserver-options.pod b/doc/man-pages/pod8/fragments/fileserver-options.pod index 378f630..1652303 100644 --- a/doc/man-pages/pod8/fragments/fileserver-options.pod +++ b/doc/man-pages/pod8/fragments/fileserver-options.pod @@ -127,6 +127,12 @@ permissions, see the B 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> > Specifies how often the File Server refreshes its knowledge of the diff --git a/doc/man-pages/pod8/fragments/fileserver-synopsis.pod b/doc/man-pages/pod8/fragments/fileserver-synopsis.pod index c949d6e..203d7a3 100644 --- a/doc/man-pages/pod8/fragments/fileserver-synopsis.pod +++ b/doc/man-pages/pod8/fragments/fileserver-synopsis.pod @@ -15,6 +15,7 @@ B S<<< [B<-novbc>] >>> S<<< [B<-implicit> >] >>> S<<< [B<-readonly>] >>> + S<<< [B<-admin-write>] >>> S<<< [B<-hr> >] >>> S<<< [B<-busyat> n >>>] >>> S<<< [B<-nobusy>] >>> diff --git a/src/viced/afsfileprocs.c b/src/viced/afsfileprocs.c index 53fc8ac..8f72110 100644 --- a/src/viced/afsfileprocs.c +++ b/src/viced/afsfileprocs.c @@ -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; } diff --git a/src/viced/viced.c b/src/viced/viced.c index 832b4b1..93ec003 100644 --- a/src/viced/viced.c +++ b/src/viced/viced.c @@ -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); -- 1.9.4