;======================================================================== ;= = ;= Programmer: Hunter Goatley = ;= Program: SWAP.MAR = ;= Language: VAX-11 MACRO32 = ;= Purpose: Allow a privileged user to "become" another user= ;= System: VAX 11/785 VAX/VMS v4.2 = ;= Shop: WKU/ACRS Western Kentucky University = ;= Date: April 11, 1986 = ;= = ;= Based on a program originally submitted to the DECUS VAX SIG = ;= tapes by: = ;= Chris Chaundy, Univ. of Melbourne, Australia = ;= James G. Downward, KMS Fusion, Inc., Michigan = ;= = ;= This version is an all-MACRO32 program. It does a few things = ;= the original and its update don't do, such as defining some = ;= logicals in the proper mode (executive). = ;= = ;======================================================================== ;= = ;= SWAP allows a privileged user to "become" another user and = ;= then SWAP back to himself. SWAP changes the username, UIC, = ;= privileges, default directory, key logical names, and the = ;= process name to the name supplied on the DCL command line. = ;= When SWAPped, VMS thinks you are that user (so you read his = ;= MAIL, get his disk quotas, etc.). = ;= = ;= To assemble and link: = ;= = ;= $ MACRO SWAP = ;= $ LINK SWAP,SYS$SYSTEM:SYS.STB/SELECT = ;= = ;= SYS$SYSTEM:SYS.STB is the system global symbol table. = ;= Because SWAP references CTL$ locations, it must be = ;= linked with SYS.STB to resolve the external refs. = ;= = ;= SWAP will need to be re-linked with each new version = ;= of VMS that changes SYS.STB (usually every major VMS = ;= update). = ;= = ;= To run: = ;= = ;= $ SWAP :== $dev:[directory]SWAP.EXE = ;= $ SWAP = ;= = ;======================================================================== ; .PSECT DATA,NOEXE,WRT,LONG .LINK /SYS$SYSTEM:SYS.STB/ ; ;======================================================================== ;= = ;= ON_ERR macro = ;= = ;= This MACRO will check the low-order bit of R0 and branch to = ;= the address supplied if the low-order bit is clear. Useful = ;= in checking errors after system service calls. = ;= = ;= Sample call: = ;= = ;= $OPEN FAB=FILEFAB ; Open the file = ;= ON_ERR ERROR ; Error? Go handle it = ;= = ;======================================================================== ; .MACRO ON_ERR THERE,?HERE BLBS R0,HERE BRW THERE HERE: .ENDM ON_ERR ; ;======================================================================== ;= = ;= I T E M M A C R O ---- This macro is called to set up the = ;= itemlist requirements for the system = ;= service $GETJPI. = ;= = ;======================================================================== ; .MACRO ITEM BUF_LEN,ITEM_CODE,BUF_ADDR,RET_ADDR=0 .WORD BUF_LEN ; The length of the buffer .WORD ITEM_CODE ; Symbolic code specifying info item .ADDRESS BUF_ADDR ; Address of the buffer .LONG RET_ADDR ; The return length address .ENDM ITEM ; ;======================================================================== ;= = ;= D E S C M A C R O -> Macro to create a string descriptor = ;= = ;======================================================================== ; .MACRO DESC LEN,ADDR .WORD LEN ; The length of the string .BYTE DSC$K_DTYPE_T ; The type (character) .BYTE DSC$K_CLASS_S ; The class (string) .ADDRESS ADDR ; The address of the string .ENDM ; ;======================================================================== ;= = ;= PRTMSG macro = ;= = ;= This macro expands to a call to LIB$PUT_OUTPUT. It main = ;= purpose is aesthetic. = ;= = ;======================================================================== ; .MACRO PRTMSG MSGBUF PUSHAQ MSGBUF ; Push descriptor addr of message CALLS #1,G^LIB$PUT_OUTPUT ; Print it at SYS$OUTPUT .ENDM PRTMSG ; .LIBRARY /SYS$LIBRARY:LIB.MLB/ ; Needed for $PCBDEF ; $PHDDEF ; Process header symbols $JIBDEF ; Job Information Block symbols $PCBDEF ; Process's status flags $IODEF ; Symbolic definitions for $QIO $SSDEF ; Symbolic definitions for status codes $JPIDEF ; Symbolic definitions for $GETJPI $UAFDEF ; SYSUAF symbolic definitions $RMSDEF ; RMS symbols $FABDEF ; File Access Block symbols $RABDEF ; Record Access Block symbols $PRVDEF ; Privilege symbols $LNMDEF ; Logical NaMe symbols ; ;=============================================================================== ; SYSFAB: ; File Access Block for SYSUAF $FAB FNM=, - FAC=GET, - SHR= SYSRAB: ; Record Access Block for SYSUAF $RAB FAB=SYSFAB, - ; ... The File Access Block RAC=KEY, - ; ... Record ACcess is keyed KRF=0, - ; ... Key of ReFerence = position 0 KSZ=UAF$S_USERNAME, - ; ... The default Key SiZe is 32 chars KBF=FOR_BUFF, - ; ... Key is found in FOR_BUFF USZ=UAF$K_LENGTH, - ; ... Buffer is 1420 chars long UBF=SYSREC ; ... Address of SYSUAF record buffer ; SYSDESC: ; Descriptor for SYSUAF record DESC 32,.+8 ; ... SYSREC: . = .+UAF$K_LENGTH ; Buffer for SYSUAF record ; ;=============================================================================== ; FOR_DESC: ; Descriptor for foreign buffer DESC 80,FOR_BUFF ; ... FOR_BUFF: ; Buffer area for foreign command .BLKB 80 ; ... FOR_LEN: ; Length of foreign command string .WORD 0 ; ... returned ; .ALIGN LONG ; PRN_DESC: ; Descriptor for process name DESC 15,FOR_BUFF ; ... .ALIGN LONG ; LNM_LIST: ; Item list for $TRNLNM ITEM 20,LNM$_STRING,SYSREC ; ... .LONG 0 ; ... Needed to end LNM_LIST LNMTAB: .ASCID /LNM$PROCESS_TABLE/ ; The logical name table name .ALIGN LONG ; TTDESC: .ASCID /TT/ ; TT: may be used to set process name .ALIGN LONG ; PROC_NAME_LEN: ; Length of process name .LONG 0 ; ... PROC_NAME: ; Buffer for process name if same as TT: .BYTE ^A/_/ ; ... .BLKB 8 ; ... ; ;=============================================================================== ; ;**** Various logical device names ; .ALIGN LONG SYS_LOGIN: ; The LOGIN directory .ASCID /SYS$LOGIN/ ; ... ; .ALIGN LONG ; SYS_LOGIN_DEVICE: ; The LOGIN device .ASCID /SYS$LOGIN_DEVICE/ ; ... ; .ALIGN LONG ; SYS_DISK: ; The WORK device .ASCID /SYS$DISK/ ; ... ; DEFDISK: ; The default device if UAF$T_DEFDEV .ASCII /SYS$SYSDISK:/ ; ... is a blank field DEFDISK_LEN = . - DEFDISK ; ; .ALIGN LONG ; LOGIN_DIR_DESC: ; Descriptor for SYS$LOGIN equiv string DESC 0,LOGIN_DEVDIR ; ... The length will be filled in later ; .ALIGN LONG ; LOGIN_DEVDIR: ; The default device:[directory] .BLKB UAF$S_DEFDEV+UAF$S_DEFDIR ; ... Make it big enough to hold ; ... maximum size spec. ; ; ;=============================================================================== ; .ALIGN LONG ; NOPRIVS: ; Used to turn all privileges off .QUAD ^XFFFFFFFFFFFFFFFF ; ... ; MINPRIV: ; Minimum privileges needed to SWAP .QUAD ; ;=============================================================================== ; ;**** Error messages to be printed at SYS$OUTPUT ; .ALIGN LONG USER_NF_MSG: .ASCID /Username not found in SYSUAF/ .ALIGN LONG USAGE_MSG: .ASCID /Usage: SWAP / .ALIGN LONG NOT_ENUFF_PRIV: .ASCID /Need CMKRNL and SYSPRV to swap/ ; ; ;=============================================================================== ; .PSECT SWAP,EXE,NOWRT .ENTRY SWAP,^M<> ; ;*** See if the user has the privileges to SWAP (need SYSPRV and CMKRNL) ; $SETPRV_S - ; Turn on the privileges needed to swap ENBFLG=#1, - ; ... PRVADR=MINPRIV ; ... CMPL #SS$_NOTALLPRIV,R0 ; Could we turn both privileges on? BNEQU 5$ ; Yes -- go continue PRTMSG NOT_ENUFF_PRIV ; No -- print message telling user BRW LEAVE ; Die gracefully ; ;*** Get the username entered on the foreign command line ; 5$: PUSHAW FOR_LEN ; Push address for return length CLRL -(SP) ; No prompt PUSHAQ FOR_DESC ; Push the descriptor for buffer CALLS #3,G^LIB$GET_FOREIGN ; Get the foreign command line CMPW #0,FOR_LEN ; Was there a username specified? BNEQU 10$ ; ... (length^=0?) Yes -- continue PRTMSG USAGE_MSG ; ... No -- Print usage message BRW LEAVE ; ... & leave without doing anything ; ;=============================================================================== ; ;**** Get the SYSUAF record for the username specified ; 10$: $OPEN FAB=SYSFAB ; Open SYSUAF.DAT ON_ERR ERROR ; On error, go to ERROR ; $CONNECT RAB=SYSRAB ; Connect the RAB with SYSUAF ON_ERR ERROR ; On error, go to ERROR ; ;**** Read the record ; $GET RAB=SYSRAB ; Read the corresponding SYSUAF record MOVL R0,R2 ; Save the status for a second $CLOSE FAB=SYSFAB ; Close SYSUAF.DAT BLBS R2,30$ ; Success reading record? Yes => 30$ ; CMPL #RMS$_RNF,R2 ; Error => IF (RECORD NOT FOUND) BNEQU 20$ ; ... PRTMSG USER_NF_MSG ; ... THEN PRINT "Not found" BRW LEAVE ; ... 20$: MOVL R2,R0 ; ... ELSE report error BRW ERROR ; ... ; ;**** Build SYS$LOGIN from UAF$T_DEFDEV and UAF$T_DEFDIR (Make it LOGIN_DEVDIR) ; 30$: MOVAL SYSREC,R11 ; Get the SYSUAF record addr MOVAB LOGIN_DEVDIR,R6 ; Move addr to register for ease MOVZBL UAF$T_DEFDEV(R11),R0 ; Get the length of DEFDEV MOVAB UAF$T_DEFDEV+1(R11),R1 ; R1 = starting addr of DEFDEV CMPB #^A/ /,(R1) ; Is the default device = blank? BNEQU 35$ ; No -- a device name is present ; Yes -- default is SYS$SYSDISK MOVAB DEFDISK,R1 ; Yes -- R1 -> DEFDISK MOVZBL DEFDISK_LEN,R0 ; ... R0 = length of DEFDISK ; ;**** R1 = addr of default device string R0 = length of it ; 35$: MOVC3 R0,(R1),(R6) ; Move it to LOGIN_DEVDIR+1 ; MOVZBL UAF$T_DEFDIR(R11),R0 ; Get the length of the DEFDIR MOVC3 R0,UAF$T_DEFDIR+1(R11),(R3) ; Move it to LOGIN_DEVDIR after ; ... DEFDEV (R3 points there ; ... from the last MOVC3) SUBL2 R6,R3 ; Get its total length MOVW R3,LOGIN_DIR_DESC ; Store the length in the byte ; ... preceding the string (like ; ... .ASCIC) ; ;**** Define the new equivalences for SYS$DISK, SYS$LOGIN, & SYS$LOGIN_DEVICE ; $CMEXEC_S - ; Go assign new logicals SYS$DISK, ROUTIN=SETLOG ; ... SYS$LOGIN, & SYS$LOGIN_DEVICE from ; ... executive mode ; ;**** Change the UIC, account, and username to the new one ; $CMKRNL_S - ; Go change the username, account, & UIC ROUTIN=SWAPUSER ; ... from kernel mode ; ;**** Set the default directory ; PUSHAQ SYS_DISK ; Get rid of supervisor-mode SYS$DISK CALLS #1,G^LIB$DELETE_LOGICAL ; ... (It's messing up SETDDIR?!?!?!?!) ; CLRL -(SP) ; Not specifying cur-dir-addr CLRL -(SP) ; Not specifying length-addr PUSHAQ LOGIN_DIR_DESC ; Push the descriptor address CALLS #3,G^SYS$SETDDIR ; Change the default directory to it ON_ERR ERROR ; Error? ; ;**** Enable all privileges new user is authorized to have ; $SETPRV_S - ; Turn off all privileges PRVADR=NOPRIVS, - ; ... PRMFLG=#1 ; ... $SETPRV_S - ; Set the new privileges ENBFLG=#1, - ; ... PRVADR=UAF$Q_PRIV(R11), - ; R11 still has SYSREC addr PRMFLG=#1 ; ... ; ;=============================================================================== ; ;**** Try setting the process name to the USERNAME; if an error occurs, ;**** do like LOGINOUT and set the process name to "_TXcu:" ; MOVW FOR_LEN,PRN_DESC ; Move the username information to MOVAB FOR_BUFF,PRN_DESC+4 ; ... the process name descriptor $SETPRN_S - ; Try to set the process name PRCNAM=PRN_DESC ; ... BLBS R0,LEAVE ; If successful, leave MOVZBW #8,LNM_LIST ; Move PROC_NAME buffer len to LNM_LIST MOVAB PROC_NAME+1,LNM_LIST+4 ; Move the equiv str buffer to LNM_LIST MOVAL PROC_NAME_LEN,LNM_LIST+8; Move the length to LNM_LIST (reuse the ; ... $CRELNM item list) $TRNLNM_S - ; Get the terminal name TABNAM=LNMTAB, - ; ... LOGNAM=TTDESC, - ; ... ITMLST=LNM_LIST ; ... INCL PROC_NAME_LEN ; Make the length one longer (count "_") MOVW PROC_NAME_LEN,PRN_DESC ; Move the terminal information to MOVAB PROC_NAME,PRN_DESC+4 ; ... the process name descriptor $SETPRN_S - ; Try to set the process name PRCNAM=PRN_DESC ; ... BLBS R0,LEAVE ; If successful, leave $SETPRN_S ; If not, just set it to " " ; ;**** Here to EXIT quietly ; LEAVE: $EXIT_S ; Return to VMS ; ;**** Signal ERROR and exit ; ERROR: $EXIT_S CODE=R0 ; Return error status to VMS ; ;=============================================================================== ; ;**** Set logicals in EXEC mode ; .ENTRY SETLOG,^M MOVAL LNM_LIST,R2 ; Get the LNM_LIST itemlist addr MOVAL LNMTAB,R3 ; Get the log name table addr MOVAL SYSREC,R4 ; Get the addr of SYSUAF record ; ;**** Move the UAF$T_DEFDEV length and address to the LNM_LIST ; MOVZBW UAF$T_DEFDEV(R4),(R2) ; Move the length of the DEFDEV MOVAL UAF$T_DEFDEV+1(R4),4(R2) ; Move the addr of the DEFDEV ; $CRELNM_S - ; Define SYS$LOGIN_DEVICE to TABNAM=(R3), - ; ... point to UAF login device LOGNAM=SYS_LOGIN_DEVICE, - ; ... ITMLST=(R2) ; ... $CRELNM_S - ; Define SYS$DISK to point to TABNAM=(R3), - ; ... SYS$LOGIN_DEVICE LOGNAM=SYS_DISK, - ; ... ITMLST=(R2) ; ... ; ;**** Move the LOGIN_DEVDIR length and address to the LNM_LIST ; MOVW LOGIN_DIR_DESC,(R2) ; Login dir length in LNM_LIST MOVL LOGIN_DIR_DESC+4,4(R2) ; Move its addr to LNM_LIST ; $CRELNM_S - ; Define SYS$LOGIN to be the TABNAM=(R3), - ; ... login dev:[directory] LOGNAM=SYS_LOGIN, - ; ... for the new user ITMLST=(R2) ; ... RET ; Return to caller ; ;=============================================================================== ; ;**** This kernel mode routine performs the actual swap to the new user ; .ENTRY SWAPUSER,^M ; MOVAB SYSREC,R6 ; Get the SYSUAF record addr MOVL CTL$GL_PCB,R0 ; Get the addr of our PCB MOVL UAF$L_UIC(R6),PCB$L_UIC(R0) ; Set our new UIC in PCB ; ;**** JIB$S_* seem to be the only symbols defined giving the true length ;**** of the username and account in the JIB and CTL, so they are used ;**** here. ; MOVL PCB$L_JIB(R0),R7 ; Get the addr of our JIB MOVC3 #JIB$S_USERNAME,UAF$T_USERNAME(R6),JIB$T_USERNAME(R7) ; Set the username in our JIB MOVC3 #JIB$S_ACCOUNT,UAF$T_ACCOUNT(R6),JIB$T_ACCOUNT(R7) ; Set the account in our JIB MOVC3 #JIB$S_USERNAME,UAF$T_USERNAME(R6),@#CTL$T_USERNAME ; Set the username in our CTL MOVC3 #JIB$S_ACCOUNT,UAF$T_ACCOUNT(R6),@#CTL$T_ACCOUNT ; Set the account in our CTL ; MOVZBL #1,R0 ; Set up a success return RET ; ; .END SWAP