===== How To Build a VMS chroot jail ===== A VMS sysadmin recently asked us: * "I need a quick and fast way to **keep a user only in his/her own directory** (SYS$LOGIN), restricting him from changing directory and reading/accessing anything else. Is there a simple flag I can set in AUTHORIZE (SYSUAF)? I don’t want to have to change protections on other directories in the system. Reason for this: We need an external user to be able to login either via FTP or Telnet and __only__ be able to interact in his own directory (SYS$LOGIN)." This is a perfectly reasonable request, and yes, there's a reasonable way to do this, although it does require the application of Access Control Lists (ACLs) thoroughly across the system's disk volumes. The approach to this problem in VMS is similar to what Linux/Unix sysadmins refer to as a "chroot jail" or "change-root jail." Here's what we shared with that sysadmin: * There isn't a flag in AUTHORIZE to limit a users access to only their directory. * With HP TCP/IP Services v5.7 (and possibly with v5.6), it is possible to restrict FTP access to the user's login directory. For this you must be running OpenVMS v8.3 or later. If you're running an older version of the TCP/IP stack, this won't be helpful. See/check the TCP/IP version with the command TCPIP SHOW VERSION. This approach is limited to FTP access, and does not affect or control interactive use. * It is possible to set the user up with a captive account in AUTHORIZE (SYSUAF). This means that that particular user's LOGIN.COM procedure must do everything he/she needs and never provides him/her with access to the DCL prompt. This doesn't work very well for general use of the system. * The only solution is to modify security elsewhere (basically system-wide, on all disk volumes) to prevent the user's access. This is with ACLs to prevent them from accessing other disk volumes at all, and other ACLs to prevent him/her from accessing other directories on the same disk. * Blocking with file and device security does not prevent the user from doing a SET DEFAULT command, but it will prevent him/her from accessing anything in those directories or even seeing what is there. ==== Example Implementation of a VMS Jail ==== In this example, we will use ''JAIL'' for the name of a general rights-list identifier (RID) to prevent access to other restricted directories, and we'll use ''JAILBIRD'' as the username who is being restricted. We're borrowing the terms from ''chroot jail'' as used in Linux/Unix systems. ==== 1. Set Up the User's Account (to put him in JAIL) ==== The first step is to create the ''JAIL'' identifier and grant it to our ''JAILBIRD'': $ set default sys$system $ mcr authorize UAF> add /ident jail %UAF-I-RDBADDMSG, identifier JAIL value %X80010380 added to rights database UAF> grant /ident jail jailbird %UAF-I-GRANTMSG, identifier JAIL granted to JAILBIRD UAF> exit %UAF-I-NOMODS, no modifications made to system authorization file %UAF-I-NAFNOMODS, no modifications made to network proxy database %UAF-I-RDBDONEMSG, rights database modified The purpose of granting the ''JAIL'' RID to this user is to effectively "put him in jail" (makes him a ''JAIL''-holder). ==== 2. Possible Problem at this point ==== If you get an error like this when attempting to grant the JAIL RID to JAILBIRD: UAF> grant /ident jail jailbird %UAF-E-GRANTUSR, user identifier JAILBIRD does not exist; JAIL could not be granted -SYSTEM-F-NOSUCHID, unknown rights identifier ...it very likely means that you've got more than one user account which is assigned (using) the same UIC value as ''JAILBIRD'' has. Since this is a security-domain problem and solution, VMS is very strict about __requiring__ that **all users are assigned unique (that is, non-shared) UIC values**. Check for this with: $ mcr authorize show [12,233] /brief where ''[12,233]'' is the UIC assigned to ''JAILBIRD''. If only one account shows up, then the RID for that user's account itself (that is, ''JAILBIRD'' as a rights identifier) is missing. The simple fix for this is to just add that identifier: $ mcr authorize add /id jailbird /value=uic=[12,233] ...and then retry the ''UAF> grant /id jail jailbird'' command again -- it should now work. **However**, if more than one user account (including ''JAILBIRD'') shows up, then you //must// reassign one or more of the users' UIC values so that __all are unique__. For each user (including ''JAILBIRD'') who shares a UIC value, assign a new unique UIC value to each of those (except for the first one, who can keep the original UIC ''[12,233]'') like this: $ mcr authorize mod jailbird /value=uic=[12,344] ! Note: Create/assign a new, unique UIC value $ set file /owner=jailbird staff:[000000]jailbird.dir ! STAFF: is logical name for user's default disk/dir $ set file /owner=jailbird staff:[jailbird...]*.*;* ! So he owns all of his own files again... Do this for all other user accounts that are sharing that first UIC value, giving each user a new and unique UIC value (e.g., ''[12,345]'', ''[12,346]'', etc.). Remember that UIC values are expressed in octal notation. One of those users can keep the original UIC ''[12,233]'', as it will now be uniquely assigned to that remaining user. Once you've got this shared-UIC untangled, and since JAILBIRD will now have a unique UIC of his own, you can retry the ''UAF> grant /id jail jailbird'' command again, and it should work now. ==== 3. Set ACLs on all of the System's Disk Volumes ==== Next we need to block his access from all other disk volumes in the system. In this example, we'll show the application of an appropriate ACL to an //example disk// ''$1$DGA201:'', with both //before// and //after// displays of that volume's protection status. The same actions are needed on //all disk volumes// other than the one holding the ''JAIL'' user's default directory. $ show security $1$dga201: /object_class=volume QUORUM object of class VOLUME Owner: [SYSTEM] Protection: (System: RWCD, Owner: RWCD, Group: RWCD, World: RWCD) Access Control List: $ set security $1$dga201: /object_class=volume - _$ /acl=(identifier=jail,access=none) $ show security $1$dga201: /object_class=volume QUORUM object of class VOLUME Owner: [SYSTEM] Protection: (System: RWCD, Owner: RWCD, Group: RWCD, World: RWCD) Access Control List: (IDENTIFIER=JAIL,ACCESS=NONE) The system disk requires special attention. The user will need access to ''DCLTABLES.EXE'' and probably many commands and utilities on the system disk such as ''COPY'', ''DIRECTORY'' and ''EDIT''. If the VMS system disk only contains the standard OpenVMS files and utilities __and__ you trust the current security, then you can omit it from consideration. If you want to be a bit more cautious, then you can limit the ''JAIL'' user to read only access. $ set security sys$sysdevice: /object_class=volume - _$ /acl=(identifier=jail,access=READ) $ show security sys$sysdevice: /object_class=volume CLASS8 object of class VOLUME Owner: [SYSTEM] Protection: (System: RWCD, Owner: RWCD, Group: RWCD, World: RWCD) Access Control List: (IDENTIFIER=JAIL,ACCESS=READ) If there are other directories on the VMS system disk that should be blocked from the user, or if the ''JAIL'' user has their directory on that VMS system disk, then set security on that disk the same as the user's disk. In those cases, the access to system directories should be ''READ'' access (only). $ set security sys$sysdevice:[000000]sys0.dir - _$ /acl=(identifier=jail,access=read) $ set security sys$sysdevice:[000000]vms$common.dir - _$ /acl=(identifier=jail,access=read) If some common shared files are on other disk volumes, then these same considerations must be given to those volumes also. This is common with large layered products such as databases. Now we can block the ''JAIL'' user's access from all top-level directories on that user's default disk. Do __not__ block him from the Master File Directory. In this case, his default disk is referenced by the logical name ''STAFF'': $ set file staff:[000000]*.dir;1 /exclude=000000.dir - _$ /acl=(identifier=jail,access=none) ==== 4. Allow the User Access to His Own Directory ==== Then make an exception for his own directory tree. In this case, we'll allow ''JAILBIRD'' full access to all files in his directory tree. You may have reason to adjust this for specific files. $ set file staff:[000000]jailbird.dir - _$ /acl=(identifier=jailbird,access=read+write+execute) $ set file staff:[jailbird...]*.dir;1 - _$ /acl=(identifier=jailbird,access=read+write+execute) $ set file staff:[jailbird...]*.*;* /exclude=*.dir;1 - _$ /acl=(identifier=jailbird,access=read+write+execute+delete) Next, we provide for the security of any files created later in that directory tree: $ set file staff:[000000]jailbird.dir - _$ /acl=(identifier=jailbird,options=default,access=read+write+execute+delete) $ set file staff:[jailbird...]*.dir;1 - _$ /acl=(identifier=jailbird,options=default,access=read+write+execute+delete) View the results with the SHOW SECURITY command. $ show security staff:[000000]jailbird.dir DSA2:[000000]JAILBIRD.DIR;1 object of class FILE Owner: [JAILBIRD] Protection: (System: RWE, Owner: RWE, Group: RE, World: E) Access Control List: (IDENTIFIER=[JAILBIRD],OPTIONS=DEFAULT,ACCESS=READ+WRITE+EXECUTE+DELETE) (IDENTIFIER=[JAILBIRD],ACCESS=READ+WRITE+EXECUTE) (IDENTIFIER=JAIL,ACCESS=NONE) ==== 5. VMS Privilege Considerations ==== Be absolutely sure that ''JAILBIRD'' does not have any privileges which will override the security changes you have made. Basically, any ordinary users, including ''JAILBIRD'', must have only ''TMPMBX'' and ''NETMBX'' privileges -- if carefully considered, it is possible to add some other privileges. Verify that the group portion of their UIC is greater than the system parameter ''MAXSYSGROUP'' -- the typical value for ''MAXSYSGROUP'' is 10(octal) or 8(decimal), so the user's group UIC value must be greater than 8. ==== 6. Testing and Validation ==== As with all changes, the sysadmin (you!) must thoroughly test the results. It's best to do this by building a ''TESTER'' username/account and granting the ''JAIL'' RID to that user (again with the ''UAF> grant /id jail tester'' command), then you can login to that account and test for appropriate "locked-out" system responses and behaviors. If you discover undesired or surprising behavior, go back and look carefully at that disk volume's or directory's ACL protection, and fix it accordingly. Once you're happy with this behavior with your ''TESTER'' account, you can grant (and/or revoke) that ''JAIL'' RID not only to user ''JAILBIRD'', but to any other current or future user account as needed -- this approach is very general and flexible.