1 Introduction
2 Ground Rules

Building a File System
3 File Systems
4 File Content Data Structure
5 Allocation Cluster Manager
6 Exceptions and Emancipation
7 Base Classes, Testing, and More
8 File Meta Data
9 Native File Class
10 Our File System
11 Allocation Table
12 File System Support Code
13 Initializing the File System
14 Contiguous Files
15 Rebuilding the File System
16 Native File System Support Methods
17 Lookups, Wildcards, and Unicode, Oh My
18 Finishing the File System Class

The Init Program
19 Hardware Abstraction and UOS Architecture
20 Init Command Mode
21 Using Our File System
22 Hardware and Device Lists
23 Fun with Stores: Partitions
24 Fun with Stores: RAID
25 Fun with Stores: RAM Disks
26 Init wrap-up

The Executive
27 Overview of The Executive
28 Starting the Kernel
29 The Kernel
30 Making a Store Bootable
31 The MMC
32 The HMC
33 Loading the components
34 Using the File Processor
35 Symbols and the SSC
36 The File Processor and Device Management
37 The File Processor and File System Management
38 Finishing Executive Startup

Users and Security
39 Introduction to Users and Security
40 More Fun With Stores: File Heaps
41 File Heaps, part 2
42 SysUAF
43 TUser
44 SysUAF API

Terminal I/O
45 Shells and UCL
46 UOS API, the Application Side
47 UOS API, the Executive Side
48 I/O Devices
49 Streams
50 Terminal Output Filters
51 The TTerminal Class
52 Handles
53 Putting it All Together
54 Getting Terminal Input
55 QIO
56 Cooking Terminal Input
57 Putting it all together, part 2
58 Quotas and I/O

UCL
59 UCL Basics
60 Symbol Substitution
61 Command execution
62 Command execution, part 2
63 Command Abbreviation
64 ASTs
65 Expressions, Part 1
66 Expressions, Part 2: Support code
67 Expressions, part 3: Parsing
68 SYS_GETJPIW and SYS_TRNLNM
69 Expressions, part 4: Evaluation

UCL Lexical Functions
70 PROCESS_SCAN
71 PROCESS_SCAN, Part 2
72 TProcess updates
73 Unicode revisted
74 Lexical functions: F$CONTEXT
75 Lexical functions: F$PID
76 Lexical Functions: F$CUNITS
77 Lexical Functions: F$CVSI and F$CVUI
78 UOS Date and Time Formatting
79 Lexical Functions: F$CVTIME
80 LIB_CVTIME
81 Date/Time Contexts
82 SYS_GETTIM, LIB_Get_Timestamp, SYS_ASCTIM, and LIB_SYS_ASCTIM
83 Lexical Functions: F$DELTA_TIME
84 Lexical functions: F$DEVICE
85 SYS_DEVICE_SCAN
86 Lexical functions: F$DIRECTORY
87 Lexical functions: F$EDIT and F$ELEMENT
88 Lexical functions: F$ENVIRONMENT
89 SYS_GETUAI
90 Lexical functions: F$EXTRACT and F$IDENTIFIER
91 LIB_FAO and LIB_FAOL
92 LIB_FAO and LIB_FAOL, part 2
93 Lexical functions: F$FAO
94 File Processing Structures
95 Lexical functions: F$FILE_ATTRIBUTES
96 SYS_DISPLAY
97 Lexical functions: F$GETDVI
98 Parse_GetDVI
99 GetDVI
100 GetDVI, part 2
101 GetDVI, part 3
102 Lexical functions: F$GETJPI
103 GETJPI
104 Lexical functions: F$GETSYI
105 GETSYI
106 Lexical functions: F$INTEGER, F$LENGTH, F$LOCATE, and F$MATCH_WILD
107 Lexical function: F$PARSE
108 FILESCAN
109 SYS_PARSE
110 Lexical Functions: F$MODE, F$PRIVILEGE, and F$PROCESS
111 File Lookup Service
112 Lexical Functions: F$SEARCH
113 SYS_SEARCH
114 F$SETPRV and SYS_SETPRV
115 Lexical Functions: F$STRING, F$TIME, and F$TYPE
116 More on symbols
117 Lexical Functions: F$TRNLNM
118 SYS_TRNLNM, Part 2
119 Lexical functions: F$UNIQUE, F$USER, and F$VERIFY
120 Lexical functions: F$MESSAGE
121 TUOS_File_Wrapper
122 OPEN, CLOSE, and READ system services

UCL Commands
123 WRITE
124 Symbol assignment
125 The @ command
126 @ and EXIT
127 CRELNT system service
128 DELLNT system service
129 IF...THEN...ELSE
130 Comments, labels, and GOTO
131 GOSUB and RETURN
132 CALL, SUBROUTINE, and ENDSUBROUTINE
133 ON, SET {NO}ON, and error handling
134 INQUIRE
135 SYS_WRITE Service
136 OPEN
137 CLOSE
138 DELLNM system service
139 READ
140 Command Recall
141 RECALL
142 RUN
143 LIB_RUN
144 The Data Stream Interface
145 Preparing for execution
146 EOJ and LOGOUT
147 SYS_DELPROC and LIB_GET_FOREIGN

CUSPs and utilities
148 The I/O Queue
149 Timers
150 Logging in, part one
151 Logging in, part 2
152 System configuration
153 SET NODE utility
154 UUI
155 SETTERM utility
156 SETTERM utility, part 2
157 SETTERM utility, part 3
158 AUTHORIZE utility
159 AUTHORIZE utility, UI
160 AUTHORIZE utility, Access Restrictions
161 AUTHORIZE utility, Part 4
162 AUTHORIZE utility, Reporting
163 AUTHORIZE utility, Part 6
164 Authentication
165 Hashlib
166 Authenticate, Part 7
167 Logging in, part 3
168 DAY_OF_WEEK, CVT_FROM_INTERNAL_TIME, and SPAWN
169 DAY_OF_WEEK and CVT_FROM_INTERNAL_TIME
170 LIB_SPAWN
171 CREPRC
172 CREPRC, Part 2
173 COPY
174 COPY, part 2
175 COPY, part 3
176 COPY, part 4
177 LIB_Get_Default_File_Protection and LIB_Substitute_Wildcards
178 CREATESTREAM, STREAMNAME, and Set_Contiguous
179 Help Files
180 LBR Services
181 LBR Services, Part 2
182 LIBRARY utility
183 LIBRARY utility, Part 2
184 FS Services
185 FS Services, Part 2
186 Implementing Help
187 HELP
188 HELP, Part 2
189 DMG_Get_Key and LIB_Put_Formatted_Output
190 LIBRARY utility, Part 3
191 Shutting Down UOS
192 SHUTDOWN
193 WAIT
194 SETIMR
195 WAITFR and Scheduling
196 REPLY, OPCOM, and Mailboxes
197 REPLY utility
198 Mailboxes

Glossary/Index


Downloads

F$SETPRV and SYS_SETPRV

This UCL lexical function can set the current process' active privileges. Here is the definition.

F$SETPRV enables or disables one or more user privileges. It returns a list of the current user privileges. A privilege can only be enabled if the user is authorized to have that privilege.

Format
F$SETPRV(privileges)

Return Value
A string containing the privileges for the current process before they were changed by the F$SETPRV function.

Arguments
privileges

A string containing one or more privilege names. If multiple privileges are provided, they must be delimited by commas (,).

Description
The F$SETPRV lexical function invokes the SETPRV system service to enable or disable specific user privileges. It returns a list of user privileges that represent the state of the specified privileges that were held by the process before F$SETPRV was executed. That list can be passed to F$SETPRV to reset the privileges to their original state. Note that attempting to set privileges not authorized to the user will fail.

Example
$ OLDPRIVS = F$SETPRV("BYPASS,GRPPRV")

In this example, OLDPRIVS is set to the current state of the BYPASS and GRPPRV privileges, and the BYPASS and GRPPRV privileges are set.

        Function_SETPRV : begin
                              if( Missing_Parentheses( '(' ) ) then
                              begin
                                  exit ;
                              end ;
                              if( Process_Setprv( Err, Context ) ) then
                              begin
                                  exit ;
                              end ;
                              if( Missing_Parentheses( ')' ) ) then
                              begin
                                  exit ;
                              end ;
                              S := Context ;
                          end ;
This code is added to the Function_Reference.

function Process_Setprv( var Err : integer ; var Context : string ) : boolean ;

var I : integer ;
    P : int64 ;
    Newprivs, S : string ;
    DMask, EMask, Current : int64 ; // Privilege masks to disable, enable, and what is current

begin
    // Setup...
    Result := False ; // Assume no problems
    Context := '' ;

    // Get parameters...
    Newprivs := uppercase( trim( Get_Parameter( Err, Context ) ) ) ;
    if( Err <> 0 ) then
    begin
        exit ;
    end ;
    if( length( Newprivs ) = 0 ) then
    begin
        exit ;
    end ;
This new function obtains the parameter. If the parameter is null, we exit because there is nothing to be done.

    // Get current privileges...
    S := Get_JPI( 0, JPI_CURPRIV ) ;
    Current := Get_Integer_From_String( S ) ;

    // Process the specific privileges...
    DMask := 0 ;
    EMask := 0 ;
Next, we ask for the current process privileges via the GETJPI system service and set Current to that privilege mask. Then we prepare to iterate through the privileges passed to the function.

    I := pos( ',', Newprivs + ',' ) ;
    while( length( Newprivs ) > 0 ) do
    begin
        // Get next privilege in list...
        S := trim( copy( Newprivs, 1, I - 1 ) ) ;
        Newprivs := copy( Newprivs, I + 1, length( Newprivs ) ) ;

        // Process the privilege...
        if( copy( S, 1, 2 ) = 'NO' ) then
        begin
            S := copy( S, 3, length( S ) ) ;
            P := String_To_Privilege( S ) ;
            if( P = 0 ) then
            begin
                Err := UCL_IVKEYW ;
                Context := S ;
                exit ;
            end ;
            DMask := DMask or P ;
        end else
        begin
            P := String_To_Privilege( S ) ;
            if( P = 0 ) then
            begin
                Err := UCL_IVKEYW ;
                Context := S ;
                exit ;
            end ;
            EMask := EMask or P ;
        end ;
Now we iterate through the specified privileges. First we extract the next privilege name in the string (delimited by a comma). If the first two characters are "NO", this is the negation of a privilege name. In that case, we trim the "NO" and then get the privilege flag value. If the privilege name is invalid, P will be 0 - in which case we exit with an error. Otherwise, we add the flag to the DMask. If the name doesn't start with "NO", we get the flag and add it to the EMask variable (exiting if the privilege name is invalid).

        // Build result string...
        if( length( Context ) > 0 ) then
        begin
            Context := Context + ',' ;
        end ;
        if( ( Current and P ) = 0 ) then
        begin
            Context := Context + 'NO' ;
        end ;
        Context := Context + Privileges_To_String( P ) ;

        // Find end of next privilege name
        I := pos( ',', Newprivs + ',' ) ;
    end ; // while( length( Newprivs ) > 0 )
Next, we see if the privilege flag is already set in the current privileges. If so, we add the name to the result string (Context). If not, we add the name to the result string, prefixed with "NO". If this isn't the first time through the loop, we add a comma before the new name.

    // Enable privileges...
    if( EMask <> 0 ) then
    begin
        SYS_SETPRV( 1, int64( @EMask ), 1, 0 ) ;
    end ;

    // Disable privileges...
    if( DMask <> 0 ) then
    begin
        SYS_SETPRV( 0, int64( @DMask ), 1, 0 ) ;
    end ;
end ; // Process_Setprv
Now, we call the SYS_SETPRIV service to enable anything in the EMasks bitmask (assuming it is non-zero). Then we call the service to disable anything in DMasks.


Now let's look at the definition of the SETPRV service, and then it's code.

The SETPRV service enables or disabled the specified privileges for the calling process.

Format
SYS_SETPRV(enflag, privaddr, permanent, curprivaddr)

Arguments
enflag

If 0, the passed privileges are disabled. If 1, the passed privileges are enabled. If any other value is passed, an error is returned.

privaddr

Address of the 64-bit privilege mask indicating which privileges to enabled or disable.

permanent

Indicates whether the privilege change should affect the current image (value of 0), or the process privileges (value of 1.) In the case of permanent privileges being affected, both the process privileges and current privileges are affected.

curprivaddr

Address of where to return the current privilege mask prior to the requested changes. If 0, the current privileges are not returned. The value of the permanent parameter indicates if the current image privileges or the current process privileges are returned.

Description
This system service enables or disabled privileges. When a process is created, the user authorized privileges, process authorized privileges, and current privileges are all set to the UAF privilege mask defined for the user (thus, they are all the same).

SETPRV cannot change the user authorized privileges. Only privileges existing in the user authorized privileges can be set, unless the user authorized privileges include the SETPRV privilege. Any other privileges not in the user authorized privileges bitmask cannot be changed by this service.

When an image is run, any privileges assigned to that image are combined with the current process privileges until the image ends - at which point the process privileges are copied to the current privileges. While the image is running, this service can only be used to modify privileges possessed in the user authorized privileges and/or the privileges authorized for the image. The following table lists the UOS privileges:
PrivilegeDescription
ACNTAllows creation of processes in which accounting is disabled
ALLSPOOLAllows allocation of a spooled device
ALTPRIAllows process to increase its own priority, set the base priority of a target process, and change the priority of its batch and print jobs
AUDITAllows appending audit records to the system security audit log file
BUGCHKAllows bugcheck error log entries from user, supervisor, or compatibility mode or to send messages to the system error logger
BYPASSDisregard protection
CMEXECChange to executive mode
CMKRNLChange to kernel mode
DETACHCreate detached processes of arbitrary UIC
DIAGNOSEDiagnose devices
DOWNGRADEWrite to a lower secrecy object or lower an object's classification
EXQUOTAAllows exceeding any disk volume usage quotas set for the user's account
GROUPAllow control of other processes in its own group(s)
GRPNAMAllows bypassing discretionary access controls on the system logical name tables in order to insert names into, or delete names from, the logical name table for the group(s) that the process belongs to
GRPPRVAllows process with the same group as the object owner the access rights provided by the object's system protection field
IMPORTMount a nonlabeled tape volume
LOG_IOIssue logical I/O requests
MOUNTExecute mount volume QIO
NETMBXAllow network operations
OPERAllows use of the OPCOM process to reply to users' requests, broadcast messages to all terminals, designate terminals as operator's terminals, etc
PFNMAPMap to specific physical pages
PHY_IOIssue physical I/O requests
PRMCEBAllows creation or deletion of permanent common event flag clusters
PRMGBLAllows creation or deletion of permanent global sections
PRMMBXAllows creation or deletion of a permanent mailbox
PSWARMAllows controlling whether the process can be swapped out of the balance set
READALLBypass existing restrictions to read an object
SECURITYAllows security-related functions such as modifying the system password or security audit settings
SETPRVEnable any privilege
SHAREAccess devices allocated to other users
SHMEMAllows creation of global sections and mailboxes in memory shared by multiple processors if process has other appropriate privileges.
SYSGBLCreate system-wide global sections
SYSLCKAllows locking system-wide resources or obtaining information about a system-wide resource
SYSNAMInsert system logical names in the name table
SYSPRVAccess objects through system protection field
TMPMBXAllow temporary mailbox creation
UPGRADEWrite to a higher integrity object or raise an object's integrity level
VOLPROOverride volume protection
WORLD Allows process to affect other processes on the system

Condition Values Returned
SS_NORMALAll privileges were enabled or disabled as requested.
SS_NOTALLPRIVOne or more of the specified privileges were not changed.
SS_IVSTSFLGA value other than 0 or 1 was passed to the permanent or enflag paramters.

function SYS_SETPRV( Flag, Privs, Permanent, PrivAddr : int64 ) : int64 ;

var Status : int64 ;
    SysRequest : TInteger4_Request ;

begin
    Status := 0 ;
    fillchar( SysRequest, sizeof( SysRequest ), 0 ) ;
    SysRequest.Request.Subsystem :=  UOS_Subsystem_USC ;
    SysRequest.Request.Request := UOS_USC_SetPrv ;
    SysRequest.Request.Length := sizeof( SysRequest ) - sizeof( TSystem_Request ) ;
    SysRequest.Request.Status := integer( @Status ) ;
    SysRequest.Int1 := Flag ;
    SysRequest.Int2 := Privs ;
    SysRequest.Int3 := Permanent ;
    SysRequest.Int4 := PrivAddr ;

    Call_To_Ring0( integer( @SysRequest ) ) ;

    Result := Status ;
end ;
This is the SYS unit interface to the SETPRV system service.

        UOS_USC_SETPRV:
            begin
                UE := Enter_System_Call( Request, SReq, PID, MMC, 
                    sizeof( TInteger4_Request ) - sizeof( SReq ), Address ) ;
                if( UE <> nil ) then
                begin
                    Set_Last_Error( UE ) ;
                    exit ;
                end ;
                try
                    I4_Request := PInteger4_Request( Address ) ;
                    Set_Privileges( 0, I4_Request.Int1, I4_Request.Int2, I4_Request.Int3, I4_Request.Int4 ) ;
                finally
                    Exit_System_Call( Request, PID, MMC, sizeof( TItem_Request ) - sizeof( SReq ) ) ;
                end ;
            end ;
We add this code to the USC.API method.

function TProcess.User : TUser ;

begin
    if( This_User = nil ) then
    begin
        This_User := Get_User( _User ) ;
        User_Authorized_Privileges := This_User.Auth_Privileges ;
        Authorized_Privileges := This_User.Privileges ;
        Current_Privileges := Authorized_Privileges ;
    end ;
    Result := This_User ;
end ;
We've added the setting of privileges to this function.

function TUSC.Set_Privileges( PID : TPID ;
    Flag, Privs, Permanent, PrivAddr : int64 ) : int64 ;

var Original : int64 ;
    Process : TProcess ;
    Status : integer ;

begin
    // Setup...
    Result := 0 ;
    if( PID = 0 ) then
    begin
        PID := Kernel.PID ;
    end ;
    Process := Get_Process( PID ) ;
    if( Process = nil ) then
    begin
        Generate_Exception( UOSErr_Nonexistent_Process ) ;
        exit ;
    end ;
    if( ( Permanent <> 0 ) and ( Permanent <> 1 ) ) then
    begin
        Result := SS_IVSTSFLG ;
        exit ;
    end ;
This new method handles the SETPRV service. First, we get the process, exiting if we couldn't get the instance. We also verify that the Permanent parameter is either 0 or 1.

    // Get privilege mask...
    Privs := Get_User_Integer( Kernel, PID, Privs, Status ) ;
    if( Status = UE_Error ) then
    begin
        if( MMC.Last_Error = nil ) then
        begin
            Generate_Exception( UOSErr_Memory_Address_Error ) ;
        end ;
        exit ;
    end ;
    if( Privs = 0 ) then
    begin
        exit ;
    end ;
Next we pull the privilege mask from the provided address. If the mask is 0, there is nothing to do, so we exit.

    // Write current mask...
    if( PrivAddr <> 0 ) then
    begin
        if( Permanent = 0 ) then
        begin
            //TODO:Get image privileges
        end else
        begin
            Status := Write_User_int64( Kernel, PID, PrivAddr, Process.Authorized_Privileges ) ;
        end ;
        if( Status = UE_Error ) then
        begin
            if( MMC.Last_Error = nil ) then
            begin
                Generate_Exception( UOSErr_Memory_Address_Error ) ;
            end ;
        end ;
        Result := Status ;
        exit ;
    end ; // if( PrivAddr <> 0 )
If the current privilege address is passed, we write the current privileges to that address. Note that we have not implemented the case where image privileges are requested here (or later in the code). We will handle images in a future article.

    // Disabled privileges...
    if( Flag = 0 ) then
    begin
        if( Permanent = 0 ) then
        begin
            //TODO:Set image privileges
        end else
        begin
            Process.Authorized_Privileges := Process.Authorized_Privileges and not Privs ;
            Process.Current_Privileges := Process.Current_Privileges and not Privs ;
        end ;
        exit ;
    end else
    if( Flag = 1 ) then
    begin
        // Enabled privileges...
        if( ( Process.Current_Privileges and SETPRV ) = 0 ) then // User doesn't have SETPRV privilege
        begin
            Original := Privs ;
            Privs := Privs and Process.User_Authorized_Privileges ; // Limit changes to those authorized
            if( Original <> Privs ) then
            begin
                Result := SS_NOTALLPRIV ;
            end ;
        end ;
        if( Permanent = 0 ) then
        begin
            //TODO:Set image privileges
        end else
        begin
            Process.Authorized_Privileges := Process.Authorized_Privileges or Privs ;
            Process.Current_Privileges := Process.Current_Privileges or Privs ;
        end ;
    end else
    begin
        Result := SS_IVSTSFLG ;
    end ;
end ; // TUSC.Set_Privileges
If we're being asked to disable privileges, we remove the specified flags from the appropriate privilege mask(s). We don't need to check if the user has authorization because a user can always disable their privileges.

If we're being asked to enable privileges, we need to first clear out any privileges that aren't authorized for the user. However, if the user has the SETPRV privilege, we don't clear anything because that privilege allows the user to set any desired privileges. If we clear any flags, we set the result condition to SS_NOTALLPRIV to inform the user that not all requested privileges were enabled.

Finally, if the flag isn't 0 or 1, we exit with the SS_IVSTSFLG code.

In the next article, we will examine the next lexical function.

 

Copyright © 2020 by Alan Conroy. This article may be copied in whole or in part as long as this copyright is included.