Note: XWorkplace Security is currently a construction site and only built if the XWPSECURITY environment variable is set.

XWorkplace Security (or XWPSec, in short) is supposed to become a framework and an implementation for implementing local security on any OS/2 system. "Local security" means that access control is enforced not only for network resources (which is what a server does before passing out files etc. to a network client), but for any resources that any running process tries to access.

In this context, "resources" are mostly files and directories. In the future, this might be extended to include printers and other hardware as well.

If you have ever run Linux, you know that you have to log on before you can do anything with the system. This is what XWPSec does as well. The current implementation consists of the following:

  1. XWPSEC32.SYS, a 32-bit ring-0 device driver which enforces access control together with XWPShell. This requires OS/2 Security Enabling Services (SES) to be installed. If you have an \OS2\SECURITY directory on your hard disk, you have SES installed already. Otherwise run "Selective install" (and reinstall fixpaks).

  2. "XWPShell", a wrapper around (and starter for) PMSHELL.EXE, the WPS process. If this program is installed in CONFIG.SYS by changing SET RUNWORKPLACE=...XWPSHELL.EXE, you will get a logon dialog after the system has started up and PM has initialized.

    After entering a valid username and password, XWPShell will start the WPS, which can be different for each user. This is done by changing the user profile (normally OS2.INI), using PrfReset.

    XWPShell is really much more than a shell. It also communicates with the ring-0 driver and maintains access control lists (ACLs) and logged-on users. For details, see below.

(Remark: With XWPSec, SES is only used with XWPSEC32.SYS. If you are familiar with SES, note that XWPShell does not use SES Logon Shell Services (LSS). In other words, XWPShell serves neither as an SES System Logon Authority (SLA) nor as a User Identification Authority (UIA). This entire funtionality has been rewritten with XWPShell becaues SES caused way too many problems. As a result, the SECURE.SYS text file in \OS2\SECURITY\SESDB is not used either.)

So how does this work?

Basically, with OS/2, local security can be implemented by passing the OS/2 kernel a table of "callouts", which are really hooks into the kernel. After the driver has loaded, a number of Dos* API calls can be intercepted and, if desired, rejected by the driver. For example, when an application calls DosOpen, the driver can return ERROR_ACCESS_DENIED, and the application will not be given access to the file.

Of course, the driver needs to know when an application is supposed to gain access to a resource. Since it is not a good idea to maintain access control lists (ACL's) at ring-0, but we should rather keep the ring-0 code to a minimum, the driver communicates with a ring-3 daemon thread in XWPSHELL.EXE to find out whether access should be granted or denied.

This basically works as follows:

  1. When XWPShell is started as the last step of CONFIG.SYS processing, it initializes PM. It then starts a new thread (the "ring-3 daemon thread") and contacts the ring-0 driver to tell it that access control should be enforced from now on. (Until then, all access requests are granted to make sure none of the processes started through CONFIG.SYS fail.)

    Together with the call into the driver, the daemon thread passes a block of memory which is needed for exchanging data with the driver.

    (Of course, XWPShell also displays the logon dialog and starts the WPS, but this is another issue.)

  2. The driver blocks the ring-3 daemon thread. To the daemon thread, it just looks like it has made a function call into the driver which can take a very long time.

  3. When an access request (e.g. DosOpen) is intercepted by the driver, which is then running at task time of the process which issued the call, the driver unblocks the ring-3 daemon thread and passes it information about the access request. To the daemon, this looks like the function call returns, and the data buffer passed to the driver has been filled with information about the access request.

  4. The ring-3 daemon thread then looks up the user ID and group ID for the process on which the driver was called. XWPShell maintains a list of all running processes and associates a user ID and group ID with each of them. As a result, each process can have different access rights.

  5. The ring-3 daemon thread then looks up whether the user on whose behalf the process is running is allowed to gain access to the resource (e.g. file or directory). For example, for opening a file for writing, the user needs write access to both the file and the directory in which the file resides. XWPShell maintains access control lists for each directory and/or file, and it does this in Unix style. See src\XWPShell\acldb.c for an introduction.

    If no information for the user ID is found, XWPShell searches again with the group ID of the user.

    If no information for the group ID is found either, XWPShell denies access.

  6. The ring-3 daemon in XWPShell calls back into the driver with the result of the access check, which is returned to the OS/2 kernel as NO_ERROR or ERROR_ACCESS_DENIED. The ring-3 daemon thread is then blocked again until the next request comes in. Go back to 3.