DIRECTORY AccessControl USING[AccessFailed, LockFailed, OperationFailed, StaticallyInvalid, Unknown], AccessControlCache USING[VerifyClient], AccessControlFile USING[LockConflict, LockItem, LockFileOrPageRun], AccessControlMain USING[ChangeSpaceViaOwnerName, CommonChangeOwnerAndHeader, CommonChangeOwner, GetOwnerRecordForReadAndUnlock, PhaseOneSpaceOwnerChanges, ReadAllOwnerProperties], AccessControlMainAux USING[ReadOwnerAccessListFromRecord, ReadOwnerAccListFromRecord], AccessControlPrivate USING[FileDataRec, InternalAccessControlLogicError, OwnerAccListType, PntrAccList, SpecialOwnerForAlpineAdmin, StringRep], AccessControlLight, AccessControlTransMap USING[EnableAlpineWheel, Handle, IsAlpineWheel], AccessControlUtility USING[Compare, CompareCaseMatters, MakeRNameFromStringRep], AlpineEnvironment USING[AccessList, AccessRights, Conversation, LockMode, LockOption, nullRootFile, OpenFileID, OwnerName, OwnerProperty, OwnerPropertySet, OwnerPropertyValuePair, PageCount, Principal, Property, PropertyValuePair, RName, VolumeGroupID, VolumeID], AlpineFile USING[GetUniversalFile, LockFailed, PropertySet, ReadProperties, Unknown], AlpineIdentity USING[myLocalConversation], AlpineInternal USING[TransHandle], AlpineVolume USING[GetEnclosingGroup], ClientMap USING[GetName], Convert USING[RopeFromInt], Rope USING [Cat, ROPE], SkiPatrolHooks USING[TransIDFromTransHandle], SkiPatrolLog USING[notice, OpFailureInfo]; AccessControlLightImpl: CEDAR PROGRAM IMPORTS AC: AccessControl, ACC: AccessControlCache, ACF: AccessControlFile, ACM: AccessControlMain, ACMA: AccessControlMainAux, ACP: AccessControlPrivate, ACU: AccessControlUtility, AF: AlpineFile, AID: AlpineIdentity, AV: AlpineVolume, ClientMap, Convert, Rope, SkiPatrolHooks, SkiPatrolLog, TM: AccessControlTransMap EXPORTS AccessControl, AccessControlLight = BEGIN OPEN AE: AlpineEnvironment, AI: AlpineInternal; TheWorld: AE.RName _ "USRegistries^.Internet"; AddOwner: PUBLIC PROCEDURE[conversation: AE.Conversation, transHandle: AI.TransHandle, volGroupID: AE.VolumeGroupID, ownerName: AE.OwnerName, overCommitQuotaIfNeeded: BOOLEAN, ownerProperties: LIST OF AE.OwnerPropertyValuePair] RETURNS[spaceLeftOnVolumeGroup: AE.PageCount] = TRUSTED BEGIN -- non system-fatal errors: AC.AccessFailed[alpineWheel], AC.LockFailed[timeout], AC.OperationFailed[duplicateOwner, ownerRecordFull, ownerDatabaseFull, totalQuotaExceeded], AC.StaticallyInvalid(badLengthName, badOwnerPropList, reservedOwnerName), AC.Unknown[transID, volumeGroupID]. quota: AE.PageCount; myLockItem: ACF.LockItem; IF NOT TM.IsAlpineWheel[transHandle, conversation] THEN ERROR AC.AccessFailed[alpineWheel]; IF ACU.Compare[ownerName, ACP.SpecialOwnerForAlpineAdmin] THEN ERROR AC.StaticallyInvalid; [, quota, ownerProperties] _ ApplyMinsDefaultsAndFilterRequestedWriteProperties[ownerProperties, ownerName, TRUE]; ownerProperties _ CONS[[spaceInUse[0]], ownerProperties]; DO BEGIN RETURN[ACM.CommonChangeOwnerAndHeader[volGroupID, add, transHandle, ownerName, overCommitQuotaIfNeeded, ownerProperties, quota ! ACF.LockConflict => BEGIN myLockItem.mode _ lockItem.mode; WITH l: lockItem SELECT FROM file => myLockItem.whatToLock _ file[l.transID, l.universalFile, l.refPattern]; pageRun => myLockItem.whatToLock _ pageRun[l.openFileID, l.pageRun]; ENDCASE; GOTO lockConflict; END]]; EXITS lockConflict => ACF.LockFileOrPageRun[myLockItem]; -- may error AC.OperationFailed[lockTimeout]. END; ENDLOOP; END; RemoveOwner: PUBLIC PROCEDURE[conversation: AE.Conversation, transHandle: AI.TransHandle, volGroupID: AE.VolumeGroupID, ownerName: AE.OwnerName] = TRUSTED BEGIN -- non system-fatal errors: AC.AccessFailed[alpineWheel], AC.LockFailed[timeout], AC.OperationFailed[ownerRecordInUse, spaceInUseByThisOwner], AC.StaticallyInvalid(badLengthName, reservedOwnerName), AC.Unknown[owner, transID, volumeGroupID]. myLockItem: ACF.LockItem; IF NOT TM.IsAlpineWheel[transHandle, conversation] THEN ERROR AC.AccessFailed[alpineWheel]; IF ACU.Compare[ownerName, ACP.SpecialOwnerForAlpineAdmin] THEN ERROR AC.StaticallyInvalid; DO BEGIN [] _ ACM.CommonChangeOwnerAndHeader[volGroupID, remove, transHandle, ownerName, TRUE, NIL, 0 ! ACF.LockConflict => BEGIN myLockItem.mode _ lockItem.mode; WITH l: lockItem SELECT FROM file => myLockItem.whatToLock _ file[l.transID, l.universalFile, l.refPattern]; pageRun => myLockItem.whatToLock _ pageRun[l.openFileID, l.pageRun]; ENDCASE; GOTO lockConflict; END]; RETURN; EXITS lockConflict => ACF.LockFileOrPageRun[myLockItem]; -- may error AC.OperationFailed[lockTimeout]. END; ENDLOOP; END; WriteOwnerProperties: PUBLIC PROCEDURE[conversation: AE.Conversation, transHandle: AI.TransHandle, volGroupID: AE.VolumeGroupID, ownerName: AE.OwnerName, overCommitQuotaIfNeeded: BOOLEAN, ownerProperties: LIST OF AE.OwnerPropertyValuePair] = TRUSTED BEGIN -- non system-fatal errors: AC.AccessFailed[alpineWheel, ownerEntry], AC.LockFailed[timeout], AC.OperationFailed[ownerRecordFull, ownerRecordInUse, regServersUnavailable, totalQuotaExceeded], Ac.StaticallyInvalid(badLengthName, badOwnerPropList, reservedOwnerName), AC.Unknown[owner, transID, volumeGroupID]. needHeader: BOOLEAN; quota: AE.PageCount; myLockItem: ACF.LockItem; IF ACU.Compare[ownerName, ACP.SpecialOwnerForAlpineAdmin] THEN ERROR AC.StaticallyInvalid; [needHeader, quota, ownerProperties] _ ApplyMinsDefaultsAndFilterRequestedWriteProperties[ownerProperties, ownerName, FALSE]; IF needHeader THEN BEGIN IF (NOT TM.IsAlpineWheel[transHandle, conversation]) THEN ERROR AC.AccessFailed[alpineWheel]; DO BEGIN [] _ ACM.CommonChangeOwnerAndHeader[volGroupID, writeProps, transHandle, ownerName, overCommitQuotaIfNeeded, ownerProperties, quota ! ACF.LockConflict => BEGIN myLockItem.mode _ lockItem.mode; WITH l: lockItem SELECT FROM file => myLockItem.whatToLock _ file[l.transID, l.universalFile, l.refPattern]; pageRun => myLockItem.whatToLock _ pageRun[l.openFileID, l.pageRun]; ENDCASE; GOTO lockConflict; END]; RETURN; EXITS lockConflict => ACF.LockFileOrPageRun[myLockItem]; -- may error AC.OperationFailed[lockTimeout]. END; ENDLOOP; END ELSE BEGIN IF (NOT TM.IsAlpineWheel[transHandle, conversation]) THEN FOR ownerProperty: LIST OF AE.OwnerPropertyValuePair _ ownerProperties, ownerProperty.rest UNTIL ownerProperty = NIL DO SELECT ownerProperty.first.property FROM createAccessList => IF (NOT CheckClientInOwnerAccessLists[conversation, transHandle, volGroupID, ownerName, [create: FALSE, modify: TRUE]][modify]) THEN ERROR AC.AccessFailed[ownerEntry]; rootFile => IF (NOT CheckClientInOwnerAccessLists[conversation, transHandle, volGroupID, ownerName, [create: TRUE, modify: FALSE]][create]) THEN ERROR AC.AccessFailed[ownerEntry]; modifyAccessList => ERROR AC.AccessFailed[ownerEntry]; ENDCASE => ERROR ACP.InternalAccessControlLogicError; ENDLOOP; DO BEGIN ACM.CommonChangeOwner[volGroupID, transHandle, ownerName, ownerProperties ! ACF.LockConflict => BEGIN myLockItem.mode _ lockItem.mode; WITH l: lockItem SELECT FROM file => myLockItem.whatToLock _ file[l.transID, l.universalFile, l.refPattern]; pageRun => myLockItem.whatToLock _ pageRun[l.openFileID, l.pageRun]; ENDCASE; GOTO lockConflict; END]; RETURN; EXITS lockConflict => ACF.LockFileOrPageRun[myLockItem]; -- may error AC.OperationFailed[lockTimeout]. END; ENDLOOP; END; END; ReadOwnerProperties: PUBLIC PROCEDURE[conversation: AE.Conversation, transHandle: AI.TransHandle, volGroupID: AE.VolumeGroupID, ownerName: AE.OwnerName, desiredOwnerProperties: AE.OwnerPropertySet] RETURNS [ownerProperties: LIST OF AE.OwnerPropertyValuePair] = TRUSTED BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.StaticallyInvalid(badLengthName), AC.Unknown[owner, transID, volumeGroupID]. myLockItem: ACF.LockItem; DO BEGIN RETURN[ACM.ReadAllOwnerProperties[volGroupID, transHandle, ownerName, desiredOwnerProperties ! ACF.LockConflict => BEGIN myLockItem.mode _ lockItem.mode; WITH l: lockItem SELECT FROM file => myLockItem.whatToLock _ file[l.transID, l.universalFile, l.refPattern]; pageRun => myLockItem.whatToLock _ pageRun[l.openFileID, l.pageRun]; ENDCASE; GOTO lockConflict; END]]; EXITS lockConflict => ACF.LockFileOrPageRun[myLockItem]; -- may error AC.OperationFailed[lockTimeout]. END; ENDLOOP; END; ChangeSpaceViaOwner: PUBLIC PROCEDURE[transHandle: AI.TransHandle, volGroupID: AE.VolumeGroupID, ownerName: AE.OwnerName, nPages: AE.PageCount] RETURNS [okay: BOOLEAN] = TRUSTED BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.StaticallyInvalid(badLengthName), AC.Unknown[owner, transID, volumeGroupID]. myLockItem: ACF.LockItem; IF ((nPages = 0) OR (ACU.Compare[ownerName, ACP.SpecialOwnerForAlpineAdmin])) THEN RETURN[TRUE]; DO BEGIN RETURN[ACM.ChangeSpaceViaOwnerName[volGroupID, transHandle, ownerName, nPages ! ACF.LockConflict => BEGIN myLockItem.mode _ lockItem.mode; WITH l: lockItem SELECT FROM file => myLockItem.whatToLock _ file[l.transID, l.universalFile, l.refPattern]; pageRun => myLockItem.whatToLock _ pageRun[l.openFileID, l.pageRun]; ENDCASE; GOTO lockConflict; END]]; EXITS lockConflict => ACF.LockFileOrPageRun[myLockItem]; -- may error AC.OperationFailed[lockTimeout]. END; ENDLOOP; END; ChangeSpaceForOwner: PUBLIC PROCEDURE [conversation: AE.Conversation, transHandle: AI.TransHandle, volGroupID: AE.VolumeGroupID, ownerName: AE.OwnerName, nPages: AE.PageCount] = BEGIN -- non system-fatal errors: AC.AccessFailed[alpineWheel], AC.LockFailed[timeout], AC.OperationFailed[quotaExceeded], AC.StaticallyInvalid(badLengthName), AC.Unknown[owner, transID, volumeGroupID]. IF NOT TM.IsAlpineWheel[transHandle, conversation] THEN ERROR AC.AccessFailed[alpineWheel]; IF NOT ChangeSpaceViaOwner[transHandle, volGroupID, ownerName, nPages] THEN { logProc: PROC [SkiPatrolLog.OpFailureInfo]; IF (logProc _ SkiPatrolLog.notice.operationFailed) # NIL THEN logProc[[ what: quotaExceeded, where: "AccessControlLightImpl.ChangeSpaceForOwner", transID: SkiPatrolHooks.TransIDFromTransHandle[transHandle], message: Rope.Cat["Quota exceeded for ", ownerName, "; nPages = ", Convert.RopeFromInt[nPages]] ]]; ERROR AC.OperationFailed[quotaExceeded]; }; END; InconsistencyBetweenFilePropAndOwnerDataBase: ERROR = CODE; ChangeSpaceViaOpenFileID: PUBLIC PROCEDURE[conversation: AE.Conversation, transHandle: AI.TransHandle, openFileID: AE.OpenFileID, nPages: AE.PageCount] RETURNS [okay: BOOLEAN] = BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.Unknown[openFileID, transID, volumeGroupID]. ownerName: AE.OwnerName _ ReadOwnerName[conversation, openFileID]; IF ACU.Compare[ownerName, ACP.SpecialOwnerForAlpineAdmin] THEN RETURN[TRUE]; RETURN[ChangeSpaceViaOwner[transHandle, GetVolGroupIDFromOpenFileID[conversation, openFileID], ownerName, nPages ! AC.StaticallyInvalid => GOTO horrible; AC.Unknown => IF why = owner THEN GOTO horrible]]; EXITS horrible => ERROR InconsistencyBetweenFilePropAndOwnerDataBase; END; PermissionToCreateFilesForThisOwner: PUBLIC PROCEDURE[conversation: AE.Conversation, transHandle: AI.TransHandle, volGroupID: AE.VolumeGroupID, ownerName: AE.OwnerName] RETURNS [okay: BOOLEAN] = BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.OperationFailed[regServersUnavailable], AC.StaticallyInvalid(badLengthName, reservedOwnerName), AC.Unknown[owner, transID, volumeGroupID]. IF conversation = AID.myLocalConversation THEN RETURN[TRUE]; IF TM.IsAlpineWheel[transHandle, conversation] THEN BEGIN IF ACU.Compare[ownerName, ACP.SpecialOwnerForAlpineAdmin] THEN ERROR AC.StaticallyInvalid ELSE RETURN[TRUE]; END; RETURN[CheckClientInOwnerAccessLists[conversation, transHandle, volGroupID, ownerName, [create: TRUE, modify: FALSE]][create]]; END; PermissionToModifyFileAccessList: PUBLIC PROCEDURE[conversation: AE.Conversation, transHandle: AI.TransHandle, openFileID: AE.OpenFileID] RETURNS [okay: BOOLEAN] = BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.OperationFailed[regServersUnavailable], AC.StaticallyInvalid(badLengthName, reservedOwnerName), AC.Unknown[openFileID, transID, volumeID, volumeGroupID]. volGroupID: AE.VolumeGroupID; ownerName: AE.OwnerName _ ReadOwnerName[conversation, openFileID]; IF TM.IsAlpineWheel[transHandle, conversation] THEN BEGIN IF ACU.Compare[ownerName, ACP.SpecialOwnerForAlpineAdmin] THEN ERROR AC.StaticallyInvalid ELSE RETURN[TRUE]; END; volGroupID _ GetVolGroupIDFromOpenFileID[conversation, openFileID]; RETURN[CheckClientInOwnerAccessLists[conversation, transHandle, volGroupID, ownerName, [create: TRUE, modify: FALSE]][create]]; END; CheckClientInOwnerAccessLists: PROCEDURE[conversation: AE.Conversation, transHandle: TM.Handle, volGroupID: AE.VolumeGroupID, ownerName: AE.OwnerName, reqLists: ARRAY ACP.OwnerAccListType OF BOOLEAN] RETURNS [inList: ARRAY ACP.OwnerAccListType OF BOOLEAN] = TRUSTED BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.OperationFailed[regServersUnavailable], AC.StaticallyInvalid(badLengthName), AC.Unknown[owner, transID, volumeGroupID]. fileDataRec: ACP.FileDataRec; myLockItem: ACF.LockItem; DO BEGIN ACM.GetOwnerRecordForReadAndUnlock[volGroupID, transHandle, ownerName, @fileDataRec ! ACF.LockConflict => BEGIN myLockItem.mode _ lockItem.mode; WITH l: lockItem SELECT FROM file => myLockItem.whatToLock _ file[l.transID, l.universalFile, l.refPattern]; pageRun => myLockItem.whatToLock _ pageRun[l.openFileID, l.pageRun]; ENDCASE; GOTO lockConflict; END]; EXIT; EXITS lockConflict => ACF.LockFileOrPageRun[myLockItem]; -- may error AC.OperationFailed[lockTimeout]. END; ENDLOOP; FOR listType: ACP.OwnerAccListType IN ACP.OwnerAccListType DO inList[listType] _ (IF reqLists[listType] THEN IsClientInOwnerAccList[conversation, ACMA.ReadOwnerAccListFromRecord[@fileDataRec, listType], ownerName] ELSE FALSE); ENDLOOP; END; PermissionToAccessFile: PUBLIC PROCEDURE[conversation: AE.Conversation, transHandle: AI.TransHandle, openFileID: AE.OpenFileID, requestedAccess: AE.AccessRights, lockOption: AE.LockOption _ [read,wait]] RETURNS [okay: BOOLEAN] = BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.OperationFailed[regServersUnavailable], AC.StaticallyInvalid(reservedOwnerName), AC.Unknown[openFileID, transID]. IF conversation = AID.myLocalConversation THEN RETURN[TRUE]; IF TM.IsAlpineWheel[transHandle, conversation] THEN BEGIN IF ACU.Compare[ReadOwnerName[conversation, openFileID, lockOption], ACP.SpecialOwnerForAlpineAdmin] THEN ERROR AC.StaticallyInvalid ELSE RETURN[TRUE]; END; SELECT requestedAccess FROM readWrite => RETURN[IsClientInFileAccessList[conversation, openFileID, ReadFileAccessList[conversation, openFileID, readWrite, lockOption], lockOption]]; readOnly => okay _ IsClientInFileAccessList[conversation, openFileID, ReadFileAccessList[conversation, openFileID, readOnly, lockOption], lockOption] OR IsClientInFileAccessList[conversation, openFileID, ReadFileAccessList[conversation, openFileID, readWrite, lockOption], lockOption]; ENDCASE => ERROR; END; GetDefaultForFileAccessList: PUBLIC PROCEDURE[transHandle: AI.TransHandle, volGroupID: AE.VolumeGroupID, ownerName: AE.OwnerName, accessListType: AE.AccessRights] RETURNS[accessList: AlpineEnvironment.AccessList] = BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC..StaticallyInvalid(badLengthName), AC.Unknown[owner, transID, volumeGroupID]. accessList _ NIL; IF ACU.Compare[ownerName, ACP.SpecialOwnerForAlpineAdmin] THEN RETURN; SELECT accessListType FROM readWrite => TRUSTED BEGIN fileDataRec: ACP.FileDataRec; myLockItem: ACF.LockItem; DO BEGIN ACM.GetOwnerRecordForReadAndUnlock[volGroupID, transHandle, ownerName, @fileDataRec ! ACF.LockConflict => BEGIN myLockItem.mode _ lockItem.mode; WITH l: lockItem SELECT FROM file => myLockItem.whatToLock _ file[l.transID, l.universalFile, l.refPattern]; pageRun => myLockItem.whatToLock _ pageRun[l.openFileID, l.pageRun]; ENDCASE; GOTO lockConflict; END]; EXIT; EXITS lockConflict => ACF.LockFileOrPageRun[myLockItem]; -- may error AC.OperationFailed[lockTimeout]. END; ENDLOOP; accessList _ ACMA.ReadOwnerAccessListFromRecord[@fileDataRec, create, ownerName]; END; ENDCASE => accessList _ CONS["world", accessList]; END; ApplyMinsDefaultsAndFilterRequestedWriteProperties: PUBLIC PROCEDURE[ownerProperties: LIST OF AE.OwnerPropertyValuePair, ownerName: AE.OwnerName, supplyDefaults: BOOLEAN] RETURNS[quotaPresent: BOOLEAN, quota: AE.PageCount, newOwnerProperties: LIST OF AE.OwnerPropertyValuePair] = TRUSTED BEGIN -- non system-fatal errors: AC.StaticallyInvalid(badOwnerPropList). ownerPropertySet: AE.OwnerPropertySet _ ALL[FALSE]; quotaPresent _ FALSE; quota _ 0; newOwnerProperties _ NIL; FOR ownerProperty: LIST OF AE.OwnerPropertyValuePair _ ownerProperties, ownerProperty.rest UNTIL ownerProperty = NIL DO IF ownerPropertySet[ownerProperty.first.property] THEN ERROR AC.StaticallyInvalid; ownerPropertySet[ownerProperty.first.property] _ TRUE; WITH prop: ownerProperty.first SELECT FROM createAccessList => newOwnerProperties _ CONS[[createAccessList[ApplyMinToOwnerAccessList[prop.createAccessList, create, ownerName]]], newOwnerProperties]; modifyAccessList => newOwnerProperties _ CONS[[modifyAccessList[ApplyMinToOwnerAccessList[prop.modifyAccessList, modify, ownerName]]], newOwnerProperties]; rootFile => newOwnerProperties _ CONS[[rootFile[prop.rootFile]], newOwnerProperties]; quota => BEGIN quotaPresent _ TRUE; newOwnerProperties _ CONS[[quota[prop.quota]], newOwnerProperties]; END; ENDCASE => ERROR AC.StaticallyInvalid; ENDLOOP; IF supplyDefaults THEN BEGIN IF NOT ownerPropertySet[createAccessList] THEN newOwnerProperties _ CONS[[createAccessList[GetDefaultForOwnerAccessList[create, ownerName]]], newOwnerProperties]; IF NOT ownerPropertySet[modifyAccessList] THEN newOwnerProperties _ CONS[[modifyAccessList[GetDefaultForOwnerAccessList[modify, ownerName]]], newOwnerProperties]; IF NOT ownerPropertySet[quota] THEN BEGIN newOwnerProperties _ CONS[[quota[0]], newOwnerProperties]; quotaPresent _ TRUE; END; IF NOT ownerPropertySet[rootFile] THEN newOwnerProperties _ CONS[[rootFile[AE.nullRootFile]], newOwnerProperties]; END; END; ApplyMinToOwnerAccessList: PROCEDURE [accessList: AE.AccessList, accListType: ACP.OwnerAccListType, ownerName: AE.OwnerName] RETURNS[newAccessList: AE.AccessList] = BEGIN -- non system-fatal errors: none. ownerSeen: BOOLEAN _ FALSE; newAccessList _ NIL; FOR list: AE.AccessList _ accessList, list.rest UNTIL list = NIL DO SELECT TRUE FROM ACU.Compare[list.first, "world"], ACU.CompareCaseMatters[list.first, "*"] => NULL; ACU.Compare[list.first, "owner"], ACU.Compare[list.first, ownerName] => NULL; ENDCASE => newAccessList _ CONS[list.first, newAccessList]; ENDLOOP; newAccessList _ CONS["Owner", newAccessList]; END; GetDefaultForOwnerAccessList: PROCEDURE [accListType: ACP.OwnerAccListType, ownerName: AE.OwnerName] RETURNS[accessList: AE.AccessList] = BEGIN -- non system-fatal errors: none. IF ACU.Compare[ownerName, ACP.SpecialOwnerForAlpineAdmin] THEN RETURN[NIL] ELSE RETURN[LIST["Owner"]]; END; IsClientInOwnerAccList: PROCEDURE[conversation: AE.Conversation, pntrAccList: ACP.PntrAccList, ownerName: AE.OwnerName] RETURNS [okay: BOOLEAN] = TRUSTED BEGIN -- non system-fatal errors: AC.OperationFailed[regServersUnavailable]. clientName: AE.Principal; accessList: AE.AccessList _ NIL; pntrStringRep: LONG POINTER TO ACP.StringRep _ @pntrAccList.principals; TRUSTED { clientName _ ClientMap.GetName[conversation] }; IF ((pntrAccList.owner OR pntrAccList.world ) AND (IsClientInListOfVanillaNames[clientName, LIST[ownerName]])) THEN RETURN[TRUE]; IF pntrAccList.world THEN accessList _ CONS[TheWorld, accessList]; FOR accListCount: CARDINAL IN [0..pntrAccList.count) DO name: AE.RName; size: CARDINAL; [name, size] _ ACU.MakeRNameFromStringRep[pntrStringRep]; accessList _ CONS[name, accessList]; pntrStringRep _ pntrStringRep + size; ENDLOOP; RETURN[IsClientInListOfVanillaNames[clientName, accessList]]; END; IsClientInFileAccessList: PROCEDURE[conversation: AE.Conversation, openFileID: AE.OpenFileID, accessList: AE.AccessList, lockOption: AE.LockOption] RETURNS [okay: BOOLEAN] = BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.OperationFailed[regServersUnavailable], AC.Unknown[openFileID, transID]. newAccessList: AE.AccessList _ NIL; worldSeen: BOOLEAN _ FALSE; ownerName: AE.Principal = ReadOwnerName[conversation, openFileID, lockOption]; clientName: AE.Principal; TRUSTED { clientName _ ClientMap.GetName[conversation] }; FOR list: AE.AccessList _ accessList, list.rest UNTIL list = NIL DO SELECT TRUE FROM ACU.Compare[list.first, "world"] OR ACU.CompareCaseMatters[list.first, "*"] => { IF ACU.Compare[ownerName, clientName] THEN RETURN[TRUE]; worldSeen _ TRUE; }; ACU.Compare[list.first, "owner"] => IF ACU.Compare[ownerName, clientName] THEN RETURN[TRUE]; ENDCASE => newAccessList _ CONS[list.first, newAccessList]; ENDLOOP; IF worldSeen THEN newAccessList _ CONS[TheWorld, newAccessList]; okay _ IsClientInListOfVanillaNames[clientName, newAccessList]; END; IsClientInListOfVanillaNames: PROCEDURE[clientName: AE.Principal, accessList: AE.AccessList] RETURNS [okay: BOOLEAN] = BEGIN -- non system-fatal errors: AC.OperationFailed[regServersUnavailable]. FOR list: AE.AccessList _ accessList, list.rest -- check for direct match. UNTIL list = NIL DO IF ACU.Compare[list.first, clientName] THEN RETURN[TRUE]; ENDLOOP; RETURN[ACC.VerifyClient[clientName, accessList]]; -- check in group. END; GetVolGroupIDFromOpenFileID: PROCEDURE[conversation: AE.Conversation, openFileID: AE.OpenFileID] RETURNS[volGroupID: AE.VolumeGroupID] = TRUSTED BEGIN -- non system-fatal errors: AC.Unknown[openFileID, transID]. ENABLE AF.Unknown => SELECT what FROM openFileID => GOTO unkOpenFileID; transID => GOTO untTransID; ENDCASE => NULL; RETURN[AV.GetEnclosingGroup[AID.myLocalConversation, , AF.GetUniversalFile[ conversation, openFileID].volumeID]]; EXITS unkOpenFileID => ERROR AC.Unknown[openFileID]; untTransID => ERROR AC.Unknown[transID]; END; ReadOwnerName: PROCEDURE[conversation: AE.Conversation, openFileID: AE.OpenFileID, lockOption: AE.LockOption _ [read,wait]] RETURNS[ownerName: AE.OwnerName] = TRUSTED BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.Unknown[openFileID, transID]. WITH pVP: ReadFileProperty[conversation, openFileID, owner, lockOption].first SELECT FROM owner => ownerName _ pVP.owner; ENDCASE => ERROR; END; ReadFileAccessList: PROCEDURE[conversation: AE.Conversation, openFileID: AE.OpenFileID, accessListType: AE.AccessRights, lockOption: AE.LockOption] RETURNS[fileAccessList: AE.AccessList] = TRUSTED BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.Unknown[openFileID, transID]. desiredProperty: AE.Property _ (SELECT accessListType FROM readOnly => readAccess, ENDCASE => modifyAccess); WITH pVP: ReadFileProperty[conversation, openFileID, desiredProperty, lockOption].first SELECT FROM readAccess => BEGIN IF desiredProperty # readAccess THEN ERROR; fileAccessList _ pVP.readAccess; END; modifyAccess => BEGIN IF desiredProperty # modifyAccess THEN ERROR; fileAccessList _ pVP.modifyAccess; END; ENDCASE => ERROR; END; ReadFileProperty: PROCEDURE[conversation: AE.Conversation, openFileID: AE.OpenFileID, desiredProperty: AE.Property, lockOption: AE.LockOption] RETURNS[list: LIST OF AE.PropertyValuePair] = TRUSTED BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.Unknown[openFileID, transID]. propSet: AF.PropertySet _ ALL[FALSE]; propSet[desiredProperty] _ TRUE; RETURN[AF.ReadProperties[conversation, openFileID, propSet, [read, lockOption.ifConflict] ! AF.Unknown => SELECT what FROM openFileID => GOTO unkOpenFile; transID => GOTO unkTransID; ENDCASE => NULL; AF.LockFailed => SELECT why FROM conflict => GOTO conflict; timeout => GOTO deadlock; ENDCASE => NULL]]; EXITS conflict => ERROR AC.LockFailed[conflict]; deadlock => ERROR AC.LockFailed[timeout]; unkOpenFile => ERROR AC.Unknown[openFileID]; unkTransID => ERROR AC.Unknown[transID]; END; AlpineWheelsOwnerName: AE.OwnerName _ NIL; AssertAlpineWheel: PUBLIC PROCEDURE[conversation: AE.Conversation, transHandle: AI.TransHandle, assert: BOOLEAN] RETURNS [okay: BOOLEAN] = BEGIN -- non system-fatal errors: AC.OperationFailed[regServersUnavailable]. IF assert THEN BEGIN principal: AE.Principal; TRUSTED BEGIN principal _ ClientMap.GetName[conversation]; END; IF NOT ACC.VerifyClient[principal, LIST[AlpineWheelsOwnerName]] THEN RETURN[FALSE]; END; TM.EnableAlpineWheel[transHandle, conversation, assert]; RETURN[TRUE]; END; PhaseOneSpaceAndOwnerChanges: PUBLIC PROCEDURE[transHandle: TM.Handle] = TRUSTED BEGIN -- non system-fatal errors: AC.LockFailed[timeout], AC.Unknown[transID]. myLockItem: ACF.LockItem; DO BEGIN ACM.PhaseOneSpaceOwnerChanges[transHandle ! ACF.LockConflict => BEGIN myLockItem.mode _ lockItem.mode; WITH l: lockItem SELECT FROM file => myLockItem.whatToLock _ file[l.transID, l.universalFile, l.refPattern]; pageRun => myLockItem.whatToLock _ pageRun[l.openFileID, l.pageRun]; ENDCASE; GOTO lockConflict; END]; RETURN; EXITS lockConflict => ACF.LockFileOrPageRun[myLockItem]; -- may error AC.OperationFailed[lockTimeout]. END; ENDLOOP; END; SetAccessControlLightInitialized: PUBLIC PROCEDURE[alpineWheels: AE.OwnerName] = BEGIN -- non system-fatal errors: none. AlpineWheelsOwnerName _ alpineWheels; END; END. Edit Log Initial: Kolling: January 11, 1983 5:52 pm: upper level module for "light" operations. Edited on July 24, 1984 2:55:28 pm PDT, by Kupfer *AccessControlLightImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Hauser, March 7, 1985 1:55:33 pm PST Carl Hauser, August 8, 1985 2:37:11 pm PDT Last edited by Kolling on July 14, 1983 11:15 am Last Edited by: Kupfer, August 6, 1984 2:35:26 pm PDT Technology export restrictions require some care in determining what constitutes "The world" vanilla owner procedures: an asserted AW can do anything. The owner and clients in the modify list can set the create list. The owner and clients in the create list can set the rootFile. Disk space allocation and deallocation: Just like ChangeSpaceViaOwner, but does an Alpine Wheels check. For debugging. Checking permissions: the file access list can be modified by the owner or anyone in the current owner create list. Owner is not checked for explicitly below because the owner create list minimum has owner. the only access checking procedure that uses only the file properties database. procedure that supplies defaults for the file access lists: procedures to manipulate the user supplied owner properties: checks list of requested properties for writing, for duplicates and illegals (spaceInUse). Also notes if the caller must get the owner database header to set any of these properties (quotaPresent). Under supplyDefaults, the defaults supplied are for the two access lists, the root file (just to reserve space) and the quota. the caller is not allowed to specify world. We filter out duplicate settings of owner, as a by-product. procedures to search access lists: this checks a file access list, which may contain "world", "*", or "owner". does not expect "world", "*", or "owner". Just does a vanilla check of match or in names. misc.: We log (SkiPatrolLog) the Lock failure at a lower level. Processing at end of a transaction: Add SkiPatrolLog probe. changes to: ChangeSpaceForOwner, ReadFileProperty Edited on August 6, 1984 2:34:30 pm PDT, by Kupfer Remove the possible race condition in SkiPatrolLog probes by assigning the PROC to a temporary variable. changes to: ChangeSpaceForOwner Êq˜Jšœ™šœ Ïmœ1™Jšžœ <˜Bš žœžœ žœžœžœ˜RJšžœ žœžœ˜!—šžœžœžœžœ˜KJ˜%—šž˜Jšœžœžœ˜.Jšœžœžœ˜(—Jšžœ˜J˜J˜J˜——šŸ œž œžœžœ5˜{šžœ žœž˜*Jšžœ T˜ZšžœJžœž˜YJ˜—Jšžœžœ˜Jšžœ˜J˜J˜J˜——šŸœž œžœžœ ˜Wšœžœ*žœžœž˜lJšžœ T˜Zšœžœ žœžœ˜RJšžœ˜—šžœTžœž˜cšœž˜Jšžœžœžœ˜+J˜ Jšžœ˜—šœž˜Jšžœ žœžœ˜-J˜"Jšžœ˜——Jšžœžœ˜Jšžœ˜J˜J˜J˜——šŸœž œžœžœ ˜Uš œžœ&žœžœžœžœž˜nJšžœ T˜ZJšœ žœžœžœ˜%Jšœžœ˜ šžœžœP˜Yš œžœ žœžœžœž˜PJšœ žœžœ˜Jšžœžœžœ žœžœ žœžœ˜h——šž˜Jšœ9™9Jšœžœ˜*Jšœ žœžœ˜)Jšœžœžœ˜,Jšœžœžœ˜(—Jšžœ˜J˜J˜J˜J˜J˜——Jšœžœ žœ˜.J˜J˜šŸœžœž œžœ˜Ošžœžœžœžœ˜:Jšžœ F˜Lšžœž˜Jšž˜Jšœ žœ ˜Jšžœžœ.žœ˜?šžœžœžœžœ˜?Jšžœžœžœ˜—Jšžœ˜—Jšžœ6˜8Jšžœžœ˜ Jšžœ˜J˜J˜J˜——Jšœ#™#J˜J˜J˜šŸœžœž œ ˜;šžœ ž˜Jšžœ H˜NJšœ žœ ˜šž˜Jšž˜šžœ&˜)šœžœžœ!˜<šžœ žœž˜J˜OJ˜D—Jšžœžœžœ˜!——Jšžœ˜Jšžœžœ! -˜gJšžœ˜Jšžœ˜Jšžœ˜J˜J˜J˜J˜———šŸ œžœž œžœ ˜PJšžœ !˜'J˜%Jšžœ˜J˜J˜J˜J˜—Jšžœ˜J˜˜J˜J˜—J˜VJ˜˜1J™Jšœ Ïr%™1—™2J™hJšœ ¡™—J™—…—c|ˆ