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;
} /*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,
AUD_END);
}
} else { /* a store operation */
- if (readonlyServer) {
+ if (!IsWriteAllowed(client)) {
return (VREADONLY);
}
if ((rights & PRSFS_INSERT) && OWNSp(client, targetptr)
/* 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);
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;
}
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;
}
/* 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;
}
goto Bad_Rename;
}
if (!code) {
- if (readonlyServer) {
+ if (!IsWriteAllowed(client)) {
errorCode = VREADONLY;
goto Bad_Rename;
}
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;
/*
* to do this.
*/
if ((InStatus->Mask & AFS_SETMODE) && !(InStatus->UnixModeBits & 0111)) {
- if (readonlyServer) {
+ if (!IsWriteAllowed(client)) {
errorCode = VREADONLY;
goto Bad_SymLink;
}
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;
}
* 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;
}
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;
}
&rights, &anyrights)))
goto Bad_SetVolumeStatus;
- if (readonlyServer) {
+ if (!IsWriteAllowed(client)) {
errorCode = VREADONLY;
goto Bad_SetVolumeStatus;
}
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 */
OPT_implicit,
OPT_lock,
OPT_readonly,
+ OPT_adminwrite,
OPT_saneacls,
OPT_buffers,
OPT_callbacks,
#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");
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);