DEFINITION MODULE MultiUserD; (*$ Implementation:=FALSE *)
(* Frank J. Beckmann	22.10.1993 *)


FROM SYSTEM IMPORT
 ADDRESS;

FROM ExecD IMPORT
 MinNode, TaskPtr, MsgPortPtr, Message;
FROM UtilityD IMPORT
 tagUser;


CONST
 multiUserName="multiuser.library";


(*
        Reserved users/groups
    
        WARNING: a uid may NOT be zero, a gid may be zero
*)

CONST
 ownerNobody=0;
 ownerSystem=MAX(LONGCARD);
 
 rootUid=MAX(CARDINAL);
 rootGid=MAX(CARDINAL);
 
 nobodyUid=0;
 
 useridsize=32;
 groupidsize=32;
 passwordsize=32;
 usernamesize=220;
 groupnamesize=220;
 homedirsize=256;


(*
        Password File
    
    
        For each user, the Password File must contain a line like this:
    
        <UserID>|<Password>|<uid>|<gid>|<UserName>|<HomeDir>|<Shell>
    
        with:
    
           <UserID>    User Login ID (max. muUSERIDSIZE-1 characters)
           <PassKey>   Encrypted Password
           <uid>       User Number (1 - 65535)
           <gid>       Primary Group Number (0 - 65535)
           <UserName>  Full User Name (max. muUSERNAMESIZE-1 characters)
           <HomeDir>   Home directory (max. muHOMEDIRSIZE-1 characters)
           <Shell>     Default Shell (not used yet, AS225 compatibility)
*)

CONST
 passwdFileName="passwd";  (* for AS225 compatibility *)


(*
        Group File
    
    
        This file gives more information about the groups and defines
        the secondary groups (other than the primary group) a user
        belongs to. It exists out of two parts, separated by a blank line.
    
        The first part contains lines with the format:
    
        <GroupID>|<gid>|<MgrUid>|<GroupName>
    
        with:
    
           <GroupID>   Group short ID (max. muGROUPIDSIZE-1 characters)
           <gid>       Group Number (0 - 65535)
           <MgrUid>    User Number of this group's manager, 0 for no
                       manager. A group's manager must not belong to the
                       group.
           <GroupName> Full Group Name (max. muGROUPNAMESIZE-1 characters)
    
        NOTE: Not every group must have a line in this file, but at least
              one group must have one.
    
    
        The seconds part contains lines with the format:
    
        <uid>:<gid>[,<gid>...]
    
        with:
    
           <uid>       User Number (1 - 65535)
           <gid>       Group Number (0 - 65535)
    
        If you think you'll exceed the maximum line length (circa 1K),
        you may use more than one line per user.
*)

CONST
 groupFileName="MultiUser.group";


(*
        Configuration File
    
    
        This file contains lines with options in the form <OPT>=<val>.
        0 is used for OFF, 1 for ON.
        Defaults to the values between square brackets.
    
        LIMITDOSSETPROTECTION   dos.library/SetProtection() cannot change
                                protection bits for GROUP and OTHER [1]
        PROFILE                 execute the Profile if it exists [1]
        LASTLOGINREQ            display the Lastlogin requester [1]
        LOGSTARTUP              log startup [0]
        LOGLOGIN                log successful logins [0]
        LOGLOGINFAIL            log failed logins [0]
        LOGPASSWD               log successful password changes [0]
        LOGPASSWDFAIL           log failed password changes [0]
        LOGCHECKPASSWD          log successful password checks [0]
        LOGCHECKPASSWDFAIL      log failed password checks [0]
        PASSWDUIDLEVEL          users with a uid greather than or equal to
                                <val> can change their passwords [0]
        PASSWDGIDLEVEL          users with a gid greather than or equal to
                                <val> can change their passwords [0]
    
        NOTE: if a user has a uid less than the PASSWDUIDLEVEL AND a gid
              less than PASSWDGIDLEVEL he/she is NOT allowed to change
              his/her password!
*)

CONST
 configFileName="MultiUser.config";


(*
        Log File
*)

CONST
 logFileName="MultiUser.log";
 

(*
        Lastlogin File
*)

CONST
 lastLoginFileName=".lastlogin";


(*
        Profile
*)

CONST
 profileFileName=".profile";


(*
        Plan file
*)

CONST
 planFileName=".plan";


(*
        Key File
    
    
        This file must be present in the root directory of every volume
        that uses the MultiUserFileSystem. It must contain 3 lines:
    
           - a pseudo random ASCII key (max. 1023 characters).
           - the directory of the password file, if located on this volume,
             otherwise an empty line (no spaces!).
               e.g. ":inet/db" for AS225 compatibility
           - the directory of the configuration file, if located on this
             volume, otherwise an empty line (no spaces!).
               e.g. ":MultiUser"
    
        If there is ANY inconsistency the system will refuse to work!!
*)

CONST
 keyFileName=":.MultiUser.keyfile";


(*
        Tags for muLogoutA()
                 muLoginA()
                 muSetDefProtectionA()
*)

TYPE
 muTags=(
  muInput:=tagUser+1,	(* filehandle - default is Input() *)
  muOutput,		(* filehandle - default is Output() *)
  muGraphical,		(* boolean - default is FALSE *)
  muPubScrName,		(* name of public screen *)
  muTask,		(* task (NOT the name!!) *)
  muOwn,		(* make a task owned by this user *)
  muGlobal,		(* change it for all tasks on the *)
			(* same level as this one *)
  muQuiet,		(* for muLogoutA(), don't give a *)
			(* login prompt, simply logout *)
  muUserID,		(* UserID for muLoginA(), must be *)
  			(* used together with muT_Password!! *)
  muPassword,		(* Password for muLoginA(), must be *)
			(* used together with muT_UserID!! *)
  muDefProtection,	(* Default protection bits *)
  			(* default is RWED GROUP R OTHER R *)
  muAll			(* for muLogoutA(), logout until *)
			(* user stack is empty *)
 );


(*
        Public User Information Structure
    
    
        For future compatibility, you should ALWAYS use muAllocUserInfo()
        to allocate this structure. NEVER do it by yourself!!
*)

TYPE
 UserInfo=RECORD
  userID: ARRAY [0..useridsize-1] OF CHAR;
  uid: CARDINAL;
  gid: CARDINAL;
  userName: ARRAY [0..usernamesize-1] OF CHAR;
  homeDir: ARRAY [0..homedirsize-1] OF CHAR;
  numSecGroups: CARDINAL;		(* Number of Secondary Groups this *)
  					(* user belongs to *)
  secGroups: ADDRESS;			(* POINTER TO ARRAY OF CARDINAL *)
  					(* Points to an array of NumSecGroups *)
  					(* Secondary Group Numbers *)
 END;

 UserInfoPtr=POINTER TO UserInfo;


(*
        Public Group Information Structure
    
    
        For future compatibility, you should ALWAYS use muAllocGroupInfo()
        to allocate this structure. NEVER do it by yourself!!
*)

TYPE
 GroupInfo=RECORD
  groupID: ARRAY [0..groupidsize-1] OF CHAR;
  gid: CARDINAL;
  mgrUid: CARDINAL;				(* Manager of this group *)
  groupName: ARRAY [0..groupnamesize-1] OF CHAR;
 END;

 GroupInfoPtr=POINTER TO GroupInfo;


(*
        KeyTypes for muGetUserInfo()
                     muGetGroupInfo()
*)

CONST
 keyTypeFirst=0;
 keyTypeNext=1;
 keyTypeGid=4;


(*
        KeyTypes for muGetUserInfo() only
*)

CONST
 keyTypeUserID=2;
 keyTypeUid=3;
 keyTypeGidNext=5;
 keyTypeUserName=6;		(* Case-insensitive *)
 keyTypeWUserID=7;		(* Case-insensitive, wild cards allowed *)
 keyTypeWUserName=8;		(* Case-insensitive, wild cards allowed *)
 keyTypeWUserIDNext=9;
 keyTypeWUserNameNext=10;


(*
        KeyTypes for muGetGroupInfo() only
*)

CONST
 keyTypeGroupID=11;		(* Case-sensitive *)
 keyTypeWGroupID=12;		(* Case-insensitive, wild cards allowed *)
 keyType_WGroupIDNext=13;
 keyTypeGroupName=14;		(* Case-insensitive *)
 keyTypeWGroupName=15;		(* Case-insensitive, wild cards allowed *)
 keyTypeWGroupNameNext=16;
 keyTypeMgrUid=17;
 keyTypeMgrUidNext=18;


(*
        Extended Owner Information Structure
    
    
        A pointer to this structure is returned by muGetTaskExtOwner().
        You MUST use muFreeExtOwner() to deallocate it!!
*)

TYPE
 ExtOwner=RECORD
  uid: CARDINAL;
  gid: CARDINAL;
  numSecGroups: CARDINAL;	(* Number of Secondary Groups this *)
  				(* user belongs too. *)
 END;

 (* NOTE: This structure is followed by a UWORD array containing *)
 (*       the Secondary Group Numbers *)

 ExtOwnerPtr=POINTER TO ExtOwner;


(*
	Portectionn bits
*)

 (* Regular RWED bits are 0 == allowed. *)
 (* NOTE: GRP and OTR RWED permissions are 0 == not allowed! *)

TYPE
 ProtectionFlags=(
  delete,		(* prevent file from being deleted *)
  execute,		(* ignored by system, used by Shell *)
  write,		(* ignored by old filesystem *)
  read,			(* ignored by old filesystem *)
  archive,		(* cleared whenever file is changed *)
  pure,			(* program is reentrant and rexecutable *)
  script,		(* program is a script (execute) file *)
  
  grpDelete,		(* Group: prevent file from being deleted *)
  grpExecute,		(* Group: file is executable *)
  grpWrite,		(* Group: file is writable *)
  grpRead,		(* Group: file is readable *)
  otrDelete,		(* Other: prevent file from being deleted *)
  otrExecute,		(* Other: file is executable *)
  otrWrite,		(* Other: file is writable *)
  otrRead,		(* Other: file is readable *)
  pf16, pf17, pf18, pf19, pf20, pf21, pf22, pf23, 
  pf24, pf25, pf26, pf27, pf28, pf29, pf30,
  setUid		(* Change owner during execution *)
 );

 ProtectionFlagSet=SET OF ProtectionFlags;
 

(*
        Default Protection Bits
*)

CONST
 defprotection=ProtectionFlagSet{otrRead, grpRead};


(*
        Relations returned by muGetRelationshipA()
*)

TYPE
 Relations=(
  relbRootUid,			(* User == super user *)
  relbRootGid,			(* User belongs to the super user group *)
  relbNobody,			(* User == nobody *)
  relbUidMatch,			(* User == owner *)
  relbGidMatch,			(* User belongs to owner group *)
  relbPrimGid,			(* User's primary group == owner group *)
  relbNoOwner			(* Owner == nobody *)
 );

 RelationSet=SET OF Relations;


(*
        Monitor Structure
    
    
        The use of this structure is restricted to root.
        Do not modify or reuse this structure while it is active!
*)

TYPE
 MonitorModes=(ignore, sendSignal, sendMessage);
 
 MonitorTriggers=(
  mtOwnerChange,		(* Task Owner Change *)
  				(*    From:    uid of old user *)
  				(*    To:      uid of new user *)
  mtLogin,			(* successful Login/Logout *)
  				(*    From:    uid of old user *)
  				(*    To:      uid of new user *)
  				(*    UserID:  UserID of new user *)
  mtLoginFail,			(* unsuccessful Login/Logout *)
  				(*    From:    uid of old user *)
  				(*    UserID:  UserID of new user *)
  mtPasswd,			(* successful Passwd *)
  				(*    From:    uid of user *)
  mtPasswdFail,			(* unsuccessful Passwd *)
  				(*    From:    uid of user *)
  mtCheckPasswd,		(* successful CheckPasswd *)
  				(*    From:    uid of user *)
  mtCheckPasswdFail		(* unsuccessful CheckPasswd *)
  				(*    From:    uid of user *)
 );
 
 MonitorTriggerSet=SET OF MonitorTriggers;

 (* NOTE: This structure may be extended in future! *)
 
 Monitor=RECORD
  node: MinNode;
  mode: MonitorModes;
  triggers: MonitorTriggerSet;
  CASE :INTEGER OF
  | 0: task: TaskPtr;		(* for SEND_SIGNAL *)
       signalNum: LONGCARD;
  | 1: port: MsgPortPtr;	(* for SEND_MESSAGE *)
  END;
 END;

 MonitorPtr=POINTER TO Monitor;

(*
        Monitor Message
    
    
        Sent to the application if SEND_MESSAGE is specified.
        Do NOT forget to reply!
*)

 MonMsg=RECORD
  execMsg: Message;
  monitor: MonitorPtr;		(* The monitor that sent the message *)
  trigger: MonitorTriggers;	(* The trigger that caused the message *)
  from: CARDINAL;
  to: CARDINAL;
  userID: ARRAY [0..useridsize-1] OF CHAR;
 END;

END MultiUserD.
