==Phrack Inc.== Volume Two, Issue 19, Phile #2 of 8 DCL Utilities for the VMS Hacker >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> By The Mentor Special thanks to Silver Spy for turning me onto DCL in the first place! ------------------------------------------------------------------------------ Anyone who spends time hacking on VAXes (by hacking, I don't just mean trying to get in... I mean *doing* something once you're in!) notices that the DCL command language is extremely powerful. I have put together a selection of utilities that not only should prove helpful to the hacker, but serve as a good example of programming in DCL. Every attempt has been made to preserve unchanged the user-environment from the initialization of the file to the exit. Any session-permanent changes are documented. Brief Overview of DCL >>>>>>>>>>>>>>>>>>>>> There are numerous files out there on DCL (the VMS help files are the best place to find information), so I'm not going to teach you how to program in it. To use the following code, isolate the section of code you want in your favorite text editor, upload it into a file, and name the file .COM. Anytime you see a file ending with .COM, you know it's a DCL file. DCL files are executed by issuing the command $@FILENAME or, in the case of a file you want to run as a separate process, $SPAWN/NOWAIT @FILENAME Table of Contents >>>>>>>>>>>>>>>>> 1. CD.DOC : This is the documentation for CD.COM (and the only documentation file in the bunch. 2. CD.COM : A change directory utility, much like the PC command CD, except more powerful. $SET DEFAULT is a pain in the ass! 3. HUNT.COM : Searches a specified node for a given user. Useful for alerting you to the presence of a sysop. 4. ALARM.COM : An alarm clock. If they check the logs at 8 a.m., you probably want to be off before then. 5. CGO.COM : Included because it's short. Allows you to compile, link, and run a C program with a one-line command. I have about 300 more pages of COM files. If you need anything, drop me a line. I'll try and help out. I can be found on Forgotten Realm, or you can call a non-hacker (local to me) IBM game board if it's an urgent message (The Bastille-- 512/353-0590 300/1200 24 hrs. It's not the best hacker board in the world, but my mail arrives daily...) Also, if programming of this type interests you, let me know! I'm considering putting up a board for the discussion of programming (compilers, AI/Expert Systems, Op Systems, etc...). If I get enough positive response, I'll go with it. Leave mail on the aforementioned systems. The Mentor CD.COM Version 5.0 VMS Change Directory Command Sub-directories are a nice feature on many computers, but they're not always easy to take advantage of. The VMS commands to access sub-directories are a little obscure, even to PC programmers who are used to using directories. The solution? CD.COM, a change directory command that works almost the same as the PC-DOS CD and PROMPT commands: CD - Display your home directory, current directory, and node name. (Similar to, but better than the VMS SHOW DEFAULT command.) CD dir_name - Move you to the [dir_name] directory. CD [dir_name] (Same as the SET DEFAULT [dir_name] command.) CD .sub_name - Move you to the [.sub_name] subdirectory. CD [.sub_name] (Same as the SET DEFAULT [.sub_name] command.) CD \ - Move you to your home (root) directory, which CD HOME is the directory you are in when you login. CD SYS$LOGIN (Same as the SET DEFAULT SYS$LOGIN command.) CD .. - Move you to the directory above your CD [-] current directory. (Same as the VMS SET DEFAULT [-] command.) CD ..sub_name - Move you "sideways" from one subdirectory CD [-.sub_name] to another subdirectory. (Same as the SET DEFAULT [-.sub_name] command.) CD * - Select a subdirectory to move to, from a list of subdirectories. CD . - Reset the current directory. CD ? - Display instructions for using CD. The VMS SET DEFAULT command has a flaw: you can change directories to a directory that doesn't exist. CD handles this more elegantly; you're left in the same directory you were in before, and this message appears: [dir_name] Directory does not exist! PC-DOS lets you display the current directory as part of the prompt. (If you haven't seen this feature, try the PC-DOS command PROMPT $P$G.) CD.COM will change the prompt for you each time you change directories if you include this line in your LOGIN.COM file: DEFINE SYS$PROMPT "ON" Without this line, your prompt is not changed from what you have it set as. Instead, your home (root) directory name, current directory name, and node name are displayed whenever you issue the CD command. Since VMS allows prompts to contain no more than 32 characters, if you change to a subdirectory that would make your prompt too long, CD automatically leaves off some of the higher level sub-directories to keep your prompt short, and displays a "*" as one of the prompt characters. CD lets you use directory names defined with with the DEFINE command. For example, if you're in one of Dr. Smiths' CS3358 classes, you might want to define his CS3358 assignments directory like this: DEFINE SMITH "DISK$CS:[CS.SMITH.3358]" Then, CD SMITH would move you to this directory. Try it! Also, some directories are already defined by the system. The SHOW LOGICAL command will give you clues to some of these system directories, if you want to go exploring. CD also supports the use of symbols for directory names. Like with PC-DOS, VMS directories and sub-directories are tree structured. The system root directory for your disk has the name [000000], and in it are the names of all the sub-directories for your disk. The directories for an imaginary user, CS335825305, would be located like this: System Root Directory: [000000] . . . . CS3358 Directories: . . . . . . *. . ... [CS3358251] [CS3358252] [CS3358253] [CS3358254] ... . . . CS3358253 Directories: . . . . *. . ... [CS3358253.04HOPE] [CS3358253.05JONES] [CS3358253.06KEY] ... . . CS335825305 Directories: . . *. *. [CS3358253.05JONES.MAIL] [CS3358253.05JONES.BULL] If you're not using sub-directories, but want to, you can create them with the CREATE command: CREATE/DIR [.sub_name] VMS allows directories to be seven or eight levels deep, but one or two levels is enough for most users. VMS also allows the symbols < and > to be used instead of [ and ], to specify directory names. CD fully supports this. Code for CD.COM >>>>>>>>>>>>>>> $! CD.COM v6.09 $! The Ultimate Change Directory Command. $! $ hdir = f$trnlnm("SYS$LOGIN") ! Home Directory $ ndir = f$edit(p1,"UPCASE") ! New Directory $ odir = f$environment("DEFAULT") ! Old Directory $ prompton = (f$edit(f$trnlnm("SYS$PROMPT"),"UPCASE") .eqs. "ON") $! $ if (ndir .eqs. "") then goto DISPLAY ! No Dir $ if (ndir .eqs. "*") then goto DIRSEARCH ! Search for Dirs $ if (ndir .eqs. "?") then goto HELP ! Instructions $! $ PARSE: $ length = f$length(ndir) ! Fix up ndir $ if (f$location("@",ndir) .eq. 0) .or. - (f$location("$",ndir) .eq. 0) then ndir = f$extract(1, length - 1, ndir) $ right = f$location("]",ndir) + 1 $ if (right .gt. length) then right = f$location(">", ndir) $ if (right .le. length) then ndir = f$extract(0, right, ndir) $! $ if (f$trnlnm(ndir) .eqs. "") then goto CASESYM ! Not Logical Name $ ndir = f$trnlnm(ndir) ! Logical Name $ goto PARSE $! $ CASESYM: $ if ("''&ndir'" .eqs. "") then goto CASE0 ! Not Symbol $ ndir = 'ndir' ! Symbol $ goto PARSE $! $ CASE0: $ len_ndir = f$length(ndir) ! Regular Dir $ if (f$location("[", ndir) .lt. len_ndir) .or. - (f$location("<", ndir) .lt. len_ndir) then goto SETDIR $! $ CASE1: ! Home Dir $ if ((ndir .nes. "HOME") .and. (ndir .nes. "\")) then goto CASE2 $ ndir = hdir $ goto SETDIR $! $ CASE2: ! . .. .dir $ if (f$location(".", ndir) .nes. 0) then goto CASE3 $ if (ndir .eqs. "..") then ndir = "-" $ if (f$extract(0, 2, ndir) .eqs. "..") - then ndir = "-" + f$extract(1, len_ndir - 1, ndir) $ ndir = "[" + ndir + "]" $ if (ndir .eqs. "[.]") then ndir = odir $ goto SETDIR $! $ CASE3: ! : $ if (f$location(":", ndir) .ge. len_ndir) then goto CASE4 $ left = f$location(":", ndir) + 1 $ symbol = f$extract(left, 1, ndir) $ if (symbol .eqs. ":") then goto CASE3B ! :: Node $ if ((symbol .eqs. "[") .or. (symbol .eqs. "<")) then goto SETDIR $ ndir = f$extract(0, left, ndir) + "[" - + f$extract(left, len_ndir - left+1, ndir) + "]" $ goto SETDIR $! $ CASE3B: ! NODE::nothing $ if (f$length(ndir)-1 .gt. left) then goto CASE3C $ ndir = ndir + "[000000]" $ goto SETDIR $! $ CASE3C: ! NODE::directory $ if ((f$location("[", ndir) - f$location("<", ndir)) .ne. 0) - then goto SETDIR $ $ ndir = f$parse(ndir,,,"NODE") + "[" + f$parse(ndir,,,"NAME") + "]" $ goto SETDIR $! $ CASE4: ! dir $ ndir = "[" + ndir + "]" $! $ SETDIR: $ set default 'ndir' $ if (f$parse("") .eqs. "") then goto DIRERROR $! $ DISPLAY: $ if ((ndir .nes. "") .and. prompton) then goto NODISPLAY $ hnode = f$getsyi("NODENAME") $ cnode = f$parse(f$trnlnm("SYS$DISK"),,,"NODE") - "::" $ if (cnode .eqs. "") then cnode = hnode $ cdir = f$environment("DEFAULT") $ write sys$output " " $ write sys$output " Home Node: ", hnode $ write sys$output " Home Directory: ", hdir $ if (cdir .eqs. hdir) .and. (cnode .eqs. hnode) then goto DISPSKIP $ write sys$output " Current Node: ", cnode $ write sys$output " Current Directory: ", cdir $ DISPSKIP: $ write sys$output " " $! $ NODISPLAY: $ ndir = f$environment("DEFAULT") $ if .not. prompton then goto END $! $ if (f$length(ndir) .ge. 32) then goto TOOLONG $! $ SETPROMPT: $ set prompt = 'ndir'" " $! $ END: $ exit $! $ DIRERROR: $ write sys$output " " $ write sys$output " ", ndir, " Directory does not exist!" $ write sys$output " " $ set default 'odir' $ ndir = odir $ goto NODISPLAY $! $! Prompt Problems------------------------------------------------------------ $! $ TOOLONG: $! Prompt is too long. Get rid of everything to the left of [ or <. If that $! doesn't work, get rid of a subdirectory at a time. As a last resort, $! set the prompt back to $. $! $ left = f$location("[", ndir) $ len_ndir = f$length(ndir) $ if (left .ge. len_ndir) then left = f$location("<",ndir) $ if (left .gt. 0) .and. (left .lt. len_ndir) - then ndir = f$extract(left, len_ndir - left, ndir) $! $ STILLTOOLONG: $ if (f$length(ndir) .lt. 32) then goto SETPROMPT $ left = f$location(".", ndir) + 1 $ len_ndir = f$length(ndir) $ if left .ge. len_ndir then ndir = "$ " $ if left .ne. len_ndir - then ndir = "[*" + f$extract(left, len_ndir - left, ndir) $ goto STILLTOOLONG $! $! Wildcard Directory--------------------------------------------------------- $! $ DIRSEARCH: $ error_message = f$environment("MESSAGE") $ on control_y then goto DIREND $ on control_c then goto DIREND $ set message/nosev/nofac/noid/notext $ write sys$output " " $ dispct = 1 $ dirct = 0 $ pauseflag = 1 $! $ DIRLOOP: $ userfile = f$search("*.dir") $ if (userfile .eqs. "") .and. (dirct .ne. 0) then goto DIRMENU $ if (userfile .eqs. "") then goto DIRNONE $ dispct = dispct + 1 $ dirct = dirct + 1 $ on severe then $ userprot = "No Priv" $ userprot = f$file_attributes(userfile,"PRO") $ if userprot .nes. "No Priv" then userprot = " " $ userfile'dirct' = "[." + f$parse(userfile,,,"NAME") + "]" $ userprot'dirct' = userprot $ lengthflag = (f$length(userfile'dirct') .gt. 18) $ if lengthflag then write sys$output - f$fao(" !3SL !34AS ", dirct, userfile'dirct'), userprot'dirct' $ if (.not. lengthflag) then write sys$output - f$fao(" !3SL !20AS ", dirct, userfile'dirct'), userprot'dirct' $ if (dispct .lt. 8) then goto DIRLOOP $ dirct = dirct + 1 $ userfile'dirct' = "" $ dirct = dirct + 1 $ userfile'dirct' = "" $ if pauseflag then goto DIRMENU $ dispct = 0 $ goto DIRLOOP $! $ DIRMENU: $ write sys$output " " $ if (userfile .eqs. "") then goto DIRMENU2 $ write sys$output " M More subdirectories" $ if pauseflag then - $ write sys$output " N More subdirectories/No pause" $! $ DIRMENU2: $ write sys$output " R Re-Display subdirectories" $ write sys$output " Q Quit (default)" $ $ DIRINQUIRE: $ write sys$output " " $ inquire dirchoice " Select One" $ write sys$output " " $! $ if (dirchoice .gt. 0) .and. - (dirchoice .le. dirct) then goto DIRCASEDIGIT $ dirchoice = f$edit(dirchoice,"UPCASE") $ if (dirchoice .eqs. "") .or. - (dirchoice .eqs. "Q") then goto DIRCASEBLANK $ if (dirchoice .eqs. "M") .or. - (dirchoice .eqs. "N") then goto DIRCASEMORE $ if (dirchoice .eqs. "R") then goto DIRCASERED $! $ DIRCASERROR: $ if (dirct .eq. 1) then write sys$output - " Select 1 to change to the ", userfile1, " subdirectory. " $ revdirct = dirct $ if (dispct .eq. 8) then revdirct = revdirct - 2 $ if (dirct .gt. 1) then write sys$output - " Valid subdirectory selections are 1 through ", revdirct, " (Octal)." $ goto DIRINQUIRE $! $ DIRCASEDIGIT: $ if (userfile'dirchoice' .eqs. "") then goto DIRCASERROR $ ndir = userfile'dirchoice' $ goto DIREND $! $ DIRCASEBLANK: $ write sys$output " Subdirectory not changed." $ write sys$output " " $ goto DIREND $! $ DIRCASEMORE: $ dispct = 0 $ if (dirchoice .eqs. "N") then pauseflag = 0 $ if (userfile .nes. "") then goto DIRLOOP $ write sys$output " No more subdirectories to display." $ goto DIRINQUIRE $! $ DIRCASERED: $ dispct = 1 $ DISPLOOP: $ if (userfile'dispct' .eqs "") then goto DISPDONT $ lengthflag = (f$length(userfile'dispct') .gt. 18) $ if lengthflag then write sys$output - f$fao(" !3SL !34AS ", dispct, userfile'dispct'), userprot'dispct' $ if (.not. lengthflag) then write sys$output - f$fao(" !3SL !20AS ", dispct, userfile'dispct'), userprot'dispct' $ DISPDONT: $ dispct = dispct + 1 $ if (dispct .le. dirct) then goto DISPLOOP $ goto DIRMENU $! $ DIRNONE: $ write sys$output "No subdirectories to choose, or no directory privileges." $ write sys$output " " $ goto DIREND $! $ DIREND: $ set message 'error_message' $ on control_y then exit $ on control_c then exit $ if (ndir .eqs. "*") then goto DISPLAY $ goto PARSE $! $!-Help----------------------------------------------------------------------- $! $ HELP: $ type sys$input CD.COM Version 6 VMS Change Directory Command Usage: CD command/directory CD Display home directory, CD .. Change directory to the current directory, node. CD [-] dir above current dir. CD \ Change directory to your CD ..sub Change directory to a CD HOME SYS$LOGIN directory. CD [-.sub] "sideways" subdirectory. CD dir Change directory to the CD * Display/select the CD [dir] [dir] directory. available subdirectories. CD .sub Change directory to the CD . Reset current directory. CD [.sub] [.sub] subdirectory. CD ? Display CD instructions. CD :== @SYS$LOGIN:CD.COM DEFINE SYS$PROMPT "ON" To make CD available from To have the VMS $ prompt any directory you change to. display the current directory. By The Mentor $ goto END Code for HUNT.COM >>>>>>>>>>>>>>>>> $ ! HUNT.COM $ ! By The Mentor $ ! Updated by: The Mad Mexican $ ! Usage: SPAWN/NOWAIT @HUNT $ ! $ !Searches SHOW USER output for a specified user, strobes at given $ !intervals considering the severity of the hunt at which time output $ !is generated and process terminates. If user loggs in then output $ !is generated and process terminates. May check both nodes if a set $ !host is called. Also supports a file with the names to be hunted for. $ ! $ ! *** NOTE *** This is set up for a two-node system with NYSSA $ ! being the default node and TEGAN being the alternate $ ! node (Circuit Breaker and some others will recognize $ ! the nodes as my 'home' ones.) You will need to $ ! slightly modify the code to reflect the nodename(s) $ ! of whatever system you are using... $ ! $ ! $ ! $ say="write sys$output" $ on control then goto door $ monitored_node = "''NODE'" $ say "Monitoring node ''monitored_node'. " $ severity_of_hunt: $ inquire selection "Severity of HUNT, 1 being the most urgent: 1-2-3" $ if selection.ge.2 then goto selection_2 $ delay="wait 00:00:20" $ loop_count=40 $ goto begin_process $ selection_2: $ if selection.eq.3 then goto selection_3 $ delay="wait 00:01:00" $ loop_count=8 $ goto begin_process $ if selection.gt.3 then goto severity_of_hunt $ delay="wait 00:02:30" $ loop_count=20 $ begin_process: $ if monitored_node.eqs."TEGAN" then goto search_file_tegan $ if f$search("nyssa.dat9") .nes. "" then goto file_exist $ goto continue $ search_file_tegan: $ if f$search("tegan.dat9") .nes. "" then goto file_exist $ continue: $ say "hit " $ inquire/nopunctuate choice9 "Who are we hunting for? " $ if choice9 .eqs. "" then exit $ count = 0 $ bell_sound[0,8]=%X07 $ top: $ sho user/output='monitored_node'.dat9 $ purge 'monitored_node'.dat9 $ set message/nofac/noid/notext/nosev $ search 'monitored_node'.dat9 'choice9' $ a=$severity $ if a .eqs. "1" then goto found_user $ set message 'temp_msg9' $ count = count + 1 $ if count .ge. 'loop_count' then goto give_up $ delay $ goto top $ file_exist: $ say "ERROR - Could not create temporary data file." $ say "Please delete or rename ''NODE'.DAT9" $ exit $ found_user: $ say bell_sound $ say "''choice9' is now online on node ''monitored_node'." $ say bell_sound $ goto door $ give_up: $ say " " $ say "''choice9' has not yet logged in on ''monitored_node'." $ door: $ say bell_sound $ say "HUNT routine has terminated on node ''monitored_node'." $ delete/noconfirm/nolog 'monitored_node'.dat9;* $ set message 'temp_msg9' $ exit Code for ALARM.COM >>>>>>>>>>>>>>>>>> $ ! ALARM.COM $ ! By The Mentor $ ! Usage: SPAWN/NOWAIT @ALARM $ ! Strobes f$time() every 5 seconds until specified time $ ! is met at which time output is generated and process terminates. $ CLR = " " $ count = 0 $ PID = F$PID(CONTEXT) $ TERMINAL = F$GETJPI(''PID',"TERMINAL") $ DEVICE = F$GETDVI(TERMINAL,"DEVTYPE") $ IF DEVICE .EQS. 110 THEN CLR = "[H[2J" ! VT220 $ IF DEVICE .EQS. 98 THEN CLR = "[H[2J" ! VT102 $ IF DEVICE .EQS. 96 THEN CLR = "[H[2J" ! VT100 $ IF DEVICE .EQS. 64 THEN CLR = "HJ" ! VT52 $ CLS = "WRITE SYS$OUTPUT CLR" $ DATE = F$CVTIME(F$TIME()) $ NODE = F$GETSYI("NODENAME") $ bell[0,8]=%X07 $ ON CONTROL THEN GOTO DOOR $ say = "write sys$output" $ say f$cvtime(,,"TIME") $ say " " $ say "Hit (RETURN)" $ say " " $ inquire/nopunctuate alarm "What time shall I ring you - " $ a_hour = f$element(0,":",alarm) $ a_minute = f$element(1,":",alarm) $ a_second = f$element(2,":",alarm) $ time_check: $ hour = f$element(0,":",f$cvtime(,,"TIME")) $ minute = f$element(1,":",f$cvtime(,,"TIME")) $ second = f$element(2,":",f$element(0,".",f$cvtime(,,"TIME"))) $ if hour .ge. a_hour .and. minute .ge. a_minute .and. second .ge. a_second then goto top $ if hour .ge. a_hour .and. minute .ge. a_minute then goto top $ wait 00:00:05 $ goto time_check $ top: $ count = count + 1 $ cls $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ say " A L A R M O N" $ say bell $ say " ",f$element(0,".",f$cvtime(,,"TIME")) $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ say " " $ wait 00:00:01.50 $ if count .le. "6" then goto top $ door: $ say "ALARM OFF" $ say f$element(0,".",f$cvtime(,,"TIME")) $ say bell $ exit Code for CGO.COM >>>>>>>>>>>>>>>> $! CGO.COM $! By The Mentor $! One-Line compile/link/execute of C programs $! Usage: CGO :== @CGO.COM $! CGO filename $! $if p1 .nes. "" then c_filename :== 'p1 $ write sys$output "Compiling:" $ cc 'c_filename/list='c_filename.lst $ write sys$output "Linking:" $ link 'c_filename ,options_file/opt $ write sys$output "Running:" $ assign/user sys$command sys$input $ run 'c_filename $ exit ------------------------------------------------------------------------------ Well, that's it. I hope to be back in the next issue with some other programs. And remember, any programmers out there, get in touch with me! The Mentor Thanksgiving 1987 ============================================================================== Received: (from LISTSERV@PSUVM for TK0EEE1@UCLAMAIL via NJE) (LISTSE00-7214; 368 LINES); Thu, 21 Dec 89 17:01:35 CST Date: Thu, 21 Dec 89 17:01 CST To: TK0EEE1 From: LISTSERV@PSUVM