; ; Please note. This code has been converted from VMS V4 and ; will run on VMS Version 5.0, 5.0-1, 5.0-2 and 5.1. ; ; * WARNING * WARNING * WARNING * WARNING * * WARNING * WARNING * ; ; ; ; This routine uses the executive routine LMM$SEARCHLOG. Under VMS V5 ; LMN$SEARCHLOG is not a global routine. In order to continue using ; this routine, we had to resort a major kluge. DEC did make the ; routine LMN$SEARCH_ONE globally vectorized. We find the address ; of LMN$SEARCH_ONE in the vector table and subtract the length ; of LNM$SEARCHLOG from it (LNM$SEARCHLOG is positioned right ; in front of LNM$SEARCH_ONE in the image LOGICAL_NAMES.EXE). ; this calculation gives us the address of LNM$SEARCH_LOG. ; ; WARNING. If DEC does ANYTHING to change the length of ; LNM$SEARCHLOG or relocates it relative to LNM$SEARCH_ONE, This ; program will BREAK. Although a Kernal mode handler is established ; to attempt to prevent a crash, you can't guarentee anything when ; you blindly hop into system space in Kernal mode at IPL 2. ; ; SO: WARNING! Before attempting to run this code on ; any version of VMS other than the ones I have listed above, VERIFY ; with SDA that the start of LNM$SEARCHLOG occurs exactly 93 Hex bytes ; in front of LNM$SEARCH_LOG. Having the MicroFiche helps. ; ; You could also check by checking to see if DEC relinked ; SYS$LOADABLE_IMAGES:LOGICAL_NAMES.EXE with ANALYZE/IMAGE. ; ; Why all this trouble just to change the ownership of the JOB table?? ; ; We feel that a Change USERNAME program is not complete without ; being able to change the ownership of the JOB logical name table. ; This version uses LNM$SEARCH_LOG to find the address of the ; JOB logical name table to facilitate this change. ; ; By changing the ownership of the table, you can then remove ; privileges (except for TMPMBX) and spawn giving a good ; approximation of of non-privileged context for testing ; questionable software. If you don't change ownership ; of the JOB table, then SPAWN will be unable to place its ; logical name for the DCL context mailbox into the JOB table. ;; ; ; .title SET_USER .ident /01.2/ ; .library /SYS$LIBRARY:LIB.MLB/ .link "SYS$SYSTEM:SYS.STB"/SELECTIVE_SEARCH ; ; $pcbdef ; Process Control Block offsets $jibdef ; Job Information Block offsets $phddef ; Process Header Block offsets $lnmstrdef ; Logical name definitions $orbdef ; Object rights block defs $lnmdef ; Logical name defs $ipldef ; Processor IPL defs $psldef ; PSL bit defs $uafdef ; User Auth Database offsets ; ; ; .psect rms_data, noexe, pic, noshr ;+ ; Data used in retrieving SYSUAF records through RMS ;- infab: $fab fac = get - fnm = - dnm = - shr = ; inrab: $rab fab = infab - kbf = usekey+8 - krf = 0 - ksz = 12 - rac = key - rop = nlk - ubf = inbuff - usz = 2048 ; usekey: .ascid / / inpline: .word 0 usrprmt: .ascid /Username: / ; dir_descr: .long 32 .address defdir defdir: .byte 32[32] ; dev_descr: .long 16 .address defdev defdev: .byte 32[16] ; def_descr: .long 48 .address def_buf def_buf: .byte 32[48] ; ; ; .psect fao_data, noexe, pic, noshr ;+ ; Data used in formating messages to screen and operators console ;- term_ctrl_str: .ascid "!/Username: !AS!/Directory: !AS!/UIC: !%U!/PID: !XL!/Account: !AS!/" term_message: .long 256 .address term_msg term_msg: .byte 32[256] term_fao_arg: .long 8 .address term_ctrl_str .address term_message .address term_message .address user_descr .address def_descr term_uic: .long 0 term_pid: .long 0 .address acct_descr ; oper_ctrl_str: .ascid /SETUSER: User !AS, (PID: !XL) became !AS, (UIC: !%U)/ oper_message: .long 80 .address oper_msg oper_msg: .byte 32[80] oper_fao_arg: .long 7 .address oper_ctrl_str .address oper_message .address oper_message .address old_user_descr oper_pid: .long 0 .address user_descr oper_uic: .long 0 ; ; ; .psect jpi_data, noexe, pic, noshr ;+ ; Data returned from SYS$GETJPIW ;- uic: .long 0 ; Process's UIC group: .long 0 ; Process's group number member: .long 0 ; Process's member number pid: .long 0 ; Process's ID number ; acct_descr: .long 8 .address account account: .blkb 8 ; Descriptor for account ; old_user_descr: .long 12 .address old_user_name old_user_name: .blkb 12 ; Descriptor for old username ; user_descr: .long 12 .address username username: .blkb 12 ; Descriptor for username ; term_descr: .long 7 .address terminal terminal: .blkb 7 ; Descriptor for terminal ; retlength: .long 0 ; Dummy return length place ; old_username: .word 12 ; Length for the username .word JPI$_USERNAME ; We want the username .address old_user_name ; Where to put the username .address old_user_descr ; How long our username is ; .long 0 ; End of single request ; jpi_item: .word 4 ; Length for the processs ID .word JPI$_PID ; We want the process ID .address pid ; Where to store the process ID .address retlength ; Dummy return length ; .word 4 ; Length for the process UIC .word JPI$_UIC ; We want the process's UIC .address uic ; Where to store the UIC .address retlength ; Dummy return length ; .word 12 ; Length for the username .word JPI$_USERNAME ; We want the username .address username ; Where to put the username .address user_descr ; How long our username is ; .word 8 ; Length for the account .word JPI$_ACCOUNT ; We want the account .address account ; Where to put the account .address retlength ; Dummy return length ; .word 7 ; Length want for the terminal .word JPI$_TERMINAL ; Get the terminal of the process .address terminal ; Where to put the terminal .address term_descr ; Dummy return length ; .word 4 ; Length for the member number .word JPI$_MEM ; We want a member number .address member ; Where to put the member number .address retlength ; Dummy return length ; .word 4 ; Length for the group number .word JPI$_GRP ; We want a the group number .address group ; Where to put the group number .address retlength ; Dummy return length ; .long 0 ; End of JPI list ; ; ; .psect krnl_data, noexe, pic, noshr ;+ ; Data used in kernel mode ;- lock_dat_beg: .long 0 lock_dat_end: .long 0 lock_code_beg: .long 0 lock_code_end: .long 0 ; new_uic: .long 0 inbuff: .blkb 2048 ; table: .ascid /LNM$JOB/ lognam: .ascid /SYS$LOGIN/ mutex_flag: .long 0 ; end_dat: ; End of data used in KRNL mode ; ; ; .psect user_code, exe, pic, shr, nowrt ;+ ; Main program entry point ;- .entry set_user, ^m<> ; $getjpiw_s - itmlst = old_username ; Get the old username ; blbs r0, 10$ ; pushl r0 pushl #0 pushl #SETUSER_GETJPIERR calls #3, g^lib$stop ; 10$: pushaw inpline pushal usrprmt pushal usekey calls #3, g^lib$get_foreign ; Get username blbs r0, 20$ ; ret ; Exit on error ; 20$: pushal usekey pushal usekey pushal usekey calls #3, g^str$trim ; Trim the username read in ; tstw usekey ; Test if anything is there bneq open_uaf ; movl #1, r0 ; Leave with no error ret ; open_uaf: $open fab = infab ; Open SYSUAF blbs r0, connect_uaf ; pushl r0 pushl #0 pushl #SETUSER_ERROPENUAF calls #3, g^lib$stop ; connect_uaf: $connect rab = inrab ; Establish a connection blbs r0, get_rec ; pushl r0 pushl #0 pushl #SETUSER_ERROPENUAF calls #3, g^lib$stop ; get_rec: $get rab = inrab ; Read UAF record cmpl r0, #RMS$_RNF beql error_stop ; cmpl r0, #RMS$_NORMAL beql close_sysuaf ; error_stop: pushl r0 pushal usekey pushl #1 pushl #SETUSER_ERRSEARCH calls #4, g^lib$stop ; Signal and stop on error ; close_sysuaf: $close fab = infab ; Close UAF blbs r0, begin_locks ; pushl r0 pushl #0 pushl #SETUSER_ERRCLOSUAF calls #3, g^lib$stop ; ; lock code and data into working set ; begin_locks: moval lock_dat_beg, lock_dat_beg moval end_dat, lock_dat_end $lckpag_s - inadr = lock_dat_beg blbs r0, 20$ ; ret ; Leave on error ; 20$: moval kerstuf, lock_code_beg moval kerstuf_e, lock_code_end $lckpag_s - inadr = lock_code_beg blbs r0, 30$ ; ret ; Leave on error ; ; Pick up address of just read UAF record (now locked) ; 30$: movl inrab + rab$l_rbf, r7 movl uaf$l_uic(r7), r8 movl r8, new_uic ; ; go kernel mode ; $cmkrnl_s change_user ; Make us the new user blbs r0, 40$ ; ret ; 40$: $cmkrnl_s change_logs ; Change logical tables blbs r0, 50$ ; ret ; Leave on error ; ; Allow paging again ; 50$: $ulkpag_s - inadr = lock_dat_beg ; Don't care if these fail $ulkpag_s - inadr = lock_code_beg ; movzbl uaf$t_defdev(r7), r6 movc3 r6, 1+uaf$t_defdev(r7), defdev ; Move to descriptor movl r6, dev_descr ; movzbl uaf$t_defdir(r7), r8 movc3 r8, 1+uaf$t_defdir(r7), defdir ; Move to descriptor movl r8, dir_descr ; movc3 r6, defdev, def_buf movc3 r8, defdir, (r3) ; Concat into one string addl3 r6, r8, def_descr ; $getjpiw_s - ; Get all of our process info itmlst = jpi_item ; - we need ; blbs r0, 10$ ; pushl r0 pushl #0 pushl #SETUSER_GETJPIERR calls #3, g^lib$stop ; 10$: pushl group pushal def_descr pushal dev_descr calls #3, set_logical ; Set the proper logicals ; pushal user_descr pushal user_descr pushal user_descr calls #3, g^str$trim ; Trim current username string ; pushal old_user_descr pushal old_user_descr pushal old_user_descr calls #3, g^str$trim ; Trim the old username string ; pushal user_descr ; Set the process name calls #1, set_prcnam ; clrq -(sp) pushal def_descr calls #3, g^sys$setddir ; Set the default directory ; movl uic, oper_uic movl pid, oper_pid callg oper_fao_arg, g^sys$fao ; Format a message for operators ; pushal oper_message calls #1, oprmsg ; Send the message ; movl pid, term_pid movl uic, term_uic callg term_fao_arg, g^sys$fao ; Format a message for the terminal ; pushal term_message calls #1, g^lib$put_output ; Send a message to the terminal ; movl #SS$_NORMAL, r0 ret ; ; ; .psect kernel_code exe, pic, noshr, nowrt ; kerstuf: .entry change_user, ^m ;+ ; Set our IPL to SYNCH so that we can access the system wide databases. ;- LOCK SCHED movl ctl$gl_pcb, r11 ; get PCB addr into r11 movl r8, pcb$l_uic(r11) ; R8 has UIC movl pcb$l_jib(r11), r10 ; pick up addr of the JIB ; ; Move username and account into JIB and CTL ; movc3 #12, uaf$t_username(r7), jib$t_username(r10) movc3 #12, uaf$t_username(r7), ctl$t_username movc3 #8, uaf$t_account(r7), jib$t_account(r10) movc3 #8, uaf$t_account(r7), ctl$t_account ; UNLOCK SCHED movl #1, r0 ret ; ; ; .entry change_logs, ^m ; movab handler, (fp) ; Establish condition handler ;+ ; Set our IPL to AST delivery level so that there are no interruptions while the ; translation of the logical name is being carried out. Then lock the logical ; name mutex for reading, and then search for the specified logical name. The ; internal routine from LNMSUB in the VMS source, LNM$SEARCHLOG, finds a logical ; name and returns the address of the table it is under. We then move the ; arguments into the appropriate registers for LNM$SEARCHLOG, and make the ; call. When we are done, we lower our IPL back down to zero. ;- setipl s^#ipl$_astdel, - ; Lower IPL to AST delivery level environ=uniprocessor jsb g^lnm$lockr ; Lock tables for reading ; movb #1, mutex_flag ;*Note elevated IPL & mutex held movq lognam, r0 ; Get logical name descriptor movq table, r2 ; Get table name descriptor bicl #^xffff0000, r0 ; Clear the upper bits of R0 bicl #^xffff0000, r2 ; and R2 movl #3, r5 ; Set R5 to it's required value ;+ ; Call to LNM$SEARCHLOG expects the following registers to be set up: ; ; R0 - length of logical name string ; R1 - Address of logical name string ; R2 - Length of table name string ; R3 - Address of table name string ; R5 - Search access mode in low byte, ; caseless flag in bit 8, ; high order word 0. ; Returns: ; ; R0 low bit clear indicates search failure. ; R0 - SS$_NOLOGNAM - No logical name match found. ; R1 - Address of logical name block on which search failed ; ; R0 low bit set indictes success with: ; R1 - Address of logical name block that contains match ; ; All other registers are preserved ;- ;+ ; PLEASE TAKE HEED !!!! ; ; WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ; ; KLUGE KLUGE KLUGE KLUGE KLUGE KLUGE KLUGE KLUGE KLUGE ; ; WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ; ; The following three lines is a MAAAAAJOR kluge! In VMS V5 and access to ; system entry points were vectorized. Some routines were not considered ; necessary enough to be vectorized. So, we cannot JSB or CALL those routine ; not vectoried. BUT, in order that we can call LNM$SEARCHLOG, which we ; need in order to get the address of our job table, we have KLUGED around ; this. ; ; Vectors for routines called by JSB are 8 bytes long and look like this: ; ; JMP L^FOO ; .BLKB 2 ; ; Now, in looking through VMS Microfiche, we noticed that LNM$SEARCH_ONE ; begins right after the end of LNM$SEARCHLOG. What we do is use the ; universal symbol LNM$SEARCH_ONE to get the address of the JMP instruction ; above. The JMP instruction is two bytes long so we add 2 to the symbol ; LNM$SEARCH_ONE to get to the address JMP jumps to. That address is the ; actual virtual address of the routine LNM$SEARCH_ONE. Subtracting the ; length of LNM$SEARCHLOG from that address gets the start of LNM$SEARCHLOG. ; We found the length of LNM$SEARCHLOG by looking through the VMS Microfiche. ; ; ;- movl g^LNM$SEARCH_ONE+2, r11 ; Address after jump instruction subl2 #^X93, r11 ; Subtract length LNM$SEARCHLOG ; ************* ^^^ ************************************************* ; ^^^ ; Check this value at EVERY release of VMS ; ; jsb (R11) ; KKKLUGE!! goto LNM$SEARCHLOG movl r0, r10 ; Save the search status blbc r0, 20$ ; Branch if no name found ; movl lnmb$l_table(r1), r1 ; Get address of table header movl lnmth$l_orb(r1), r1 ; Get address of object rights block movl r8, orb$l_owner(r1) ; Set the new owner of the table ; 20$: jsb g^lnm$unlock ; Release lock on logical mutex ; setipl #0, - ; Drop our IPL to zero environ=uniprocessor clrl mutex_flag ; Clear the mutex-held flag movl r10, r0 ; Move return status back ; ret ; ;+ ; This is the condition handler in case anything happens during kernel mode ; execution. ;- .entry handler, ^m<> ; tstl mutex_flag ; Mutex held ? beql 10$ ; Branch if nope... jsb g^lnm$unlock ; Release our mutex setipl #0 ; Drop our ipl to zero ; 10$: $exit_s ; Cause process to exit kerstuf_e: ; .end set_user