From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX"  6-DEC-1990 02:37:56.18
To:	MRGATE::"ARISIA::EVERHART"
CC:	
Subj:	TERM_LOCK program for VMS 5.4

Received:  by crdgw1.ge.com (5.57/GE 1.80)
	 id AA21105; Thu, 6 Dec 90 02:24:06 EST
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Wed,  5 DEC 90 16:06:36 PST
Received: by ucbvax.Berkeley.EDU (5.63/1.42)
	id AA15114; Wed, 5 Dec 90 03:34:58 -0800
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 5 Dec 90 05:51:53 GMT
From: mvb.saic.com!dayton.saic.com!nieland!ted@ucsd.edu  (Ted Nieland)
Subject: TERM_LOCK program for VMS 5.4
Message-Id: <4569.AA4569@nieland.DAYTON.OH.US>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com

Here is the TERM_LOCK program that I have been maintaining the past couple of
years.  VMS 5.4 broke the program due to the new HASH routine that is used 
by default.  This version of the program will only work with VMS 5.4 or later
since it now uses the SYS$HASH_PASSWORD system service that is new in VMS 5.4.

Anyone wanting the older version can get it off the DECUS Tapes or send me 
a mail message.

--
M. Edward (Ted) Nieland

Ted@NIELAND.DAYTON.OH.US 

$! ------------------ CUT HERE -----------------------
$ v='f$verify(f$trnlnm("SHARE_VERIFY"))'
$!
$! This archive created by VMS_SHARE Version 7.2-007  22-FEB-1990
$!   On  4-DEC-1990 21:31:59.53   By user TNIELAND 
$!
$! This VMS_SHARE Written by:
$!    Andy Harper, Kings College London UK
$!
$! Acknowledgements to:
$!    James Gray       - Original VMS_SHARE
$!    Michael Bednarek - Original Concept and implementation
$!
$!
$! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING:
$!       1. TERM_LOCK54.FOR;1
$!       2. BUILD_TERMLOCK.COM;1
$!
$set="set"
$set symbol/scope=(nolocal,noglobal)
$f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID"))
$e="write sys$error  ""%UNPACK"", "
$w="write sys$output ""%UNPACK"", "
$ if f$trnlnm("SHARE_LOG") then $ w = "!"
$ ve=f$getsyi("version")
$ if ve-f$extract(0,1,ve) .ges. "4.4" then $ goto START
$ e "-E-OLDVER, Must run at least VMS 4.4"
$ v=f$verify(v)
$ exit 44
$UNPACK: SUBROUTINE ! P1=filename, P2=checksum
$ if f$search(P1) .eqs. "" then $ goto file_absent
$ e "-W-EXISTS, File ''P1' exists. Skipped."
$ delete 'f'*
$ exit
$file_absent:
$ if f$parse(P1) .nes. "" then $ goto dirok
$ dn=f$parse(P1,,,"DIRECTORY")
$ w "-I-CREDIR, Creating directory ''dn'."
$ create/dir 'dn'
$ if $status then $ goto dirok
$ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped."
$ delete 'f'*
$ exit
$dirok:
$ w "-I-PROCESS, Processing file ''P1'."
$ if .not. f$verify() then $ define/user sys$output nl:
$ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1'
PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET(
SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name");b:=
CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(b));
LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION(
BEGINNING_OF(b));g:=0;LOOP EXITIF MARK(NONE)=END_OF(b);x:=ERASE_CHARACTER(1);
IF g=0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x="V" THEN APPEND_LINE;
MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF;IF x="+" THEN g:=1;
ERASE_LINE;ENDIF;ELSE IF x="-" THEN IF INDEX(CURRENT_LINE,"+-+-+-+-+-+-+-+")=
1 THEN g:=0;ENDIF;ENDIF;ERASE_LINE;ENDIF;ENDLOOP;t:="0123456789ABCDEF";
POSITION(BEGINNING_OF(b));LOOP r:=SEARCH("`",FORWARD);EXITIF r=0;POSITION(r);
ERASE(r);x1:=INDEX(t,ERASE_CHARACTER(1))-1;x2:=INDEX(t,ERASE_CHARACTER(1))-1;
COPY_TEXT(ASCII(16*x1+x2));ENDLOOP;WRITE_FILE(b,GET_INFO(COMMAND_LINE,
"output_file"));ENDPROCEDURE;Unpacker;QUIT;
$ delete/nolog 'f'*
$ CHECKSUM 'P1'
$ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT
$ e "-E-CHKSMFAIL, Checksum of ''P1' failed."
$ ENDSUBROUTINE
$START:
$ create 'f'
XC
X      PROGRAM TERM_LOCK
XC
XC ***********************************************************************
XC    This program was written, so a user did not have to log off the
XC     system every time they left their terminal. I had in mind priveleged
XC     accounts at the time. The program does not require any priveleges to
XC     run. There is a problem, where I cannot include the code to LGI$HPWD.
XC     This is DEC's password hashing function, however it is supplied in
XC     the VMS micro-fiche, but I did include the object file. Another little
XC     program needed was UAI_DEF.MAR, this program when assembled, provides
XC     the needed symbols for $GETUAI. To put TERM_LOCK altogether, execute
XC     the following commands:
XC
XC     FORT TERM_LOCK
XC     MACRO UAI_DEF
XC     LINK/NOTRACE TERM_LOCK,UAI_DEF,HPWD
XC
XC    The program starts by disabling CONTROL_Y and CONTROL_T. We know why
XC    CONTROL_Y is disabled, CONTROL_T is disabled so that a would be
XC    troublemaker cannot find out who is running the program. Next, the imag
Ve
XC    gathers the terminal name and USERNAME that is using this image. If
XC    the terminal is over the network and a person presses CONTROL_Y enough
XC    the system asks if you are aborting the login, thus one could end up
XC    back on someone else's account or prevent somebody from getting to thei
Vr
XC    process. The USERNAME is used to get the appropriate UAF record,
XC    especially the correct PASSOWRD. I use $GETUAI, because a user with`20
XC    no privelges can get only their record, and nobody elses'. Also, becaus
Ve
XC    the program uses only the USERNAME running this particular image, a
XC    user cannot get at another users' UAF record. After we get this
XC    information I begin building pasteboards, virtual displays and keyboard
V.
XC    I chose Screen Management, because it would run on any type terminal.
XC    The SMG routines, also let me prompt for the USERNAME and PASSWORD,
XC    and at the same time prevent echoing on the screen and converts the`20
XC    data to uppercase. I next run what the user enters through the hashing
XC    routine and compare the hashed quadwords for a correct password match.
XC    If the quadwords match, they have entered a valid password and the prog
Vram
XC    exits, otherwise the terminal bell is rung and the user reprompted.
XC    I display on the terminal screen, while this image is running, that
XC    this is a "SECURE TERMINAL" in double high , double wide , bold text.
XC    This message is easily changed.
XC
XC    I know that the program does not take into account secondary passwords,
XC     but, our site does not use them.
XC
XC    If you find any problems or make any enhancements please let me know.
XC    I can be reached at the following address and phone:
XC
XC                     Gary Sachs
XC                     Lawrence Institute of Technology
XC                     21000 W 10 Mile Rd.
XC                     Southfield, Mi  48075
XC                     Ph. 313-356-0200  xtn 3700
XC
XC    Written by:    Gary Sachs    July 10, 1986
XC
XC    Updates:
XC                   Added default Username        Ted Nieland 11/28/88
XC                   displayed, Count of invalids
XC                   Message pasteboard, NTY Terms
XC
XC                   Added secondary password      Ted Nieland 4/27/89
XC
XC                   Updated for VMS 5.4           Ted Nieland 12/4/90
XC                   Now uses SYS$HASH_PASSWORD
XC                   Asks about Network link Terminals
XC                   Compile:
XC                        FORT TERM_LOCK
XC                   Link:
XC                        LINK TERM_LOCK/NOTRACE
XC **************************************************************************
XC
X      IMPLICIT INTEGER (A-Z)
XC
X      BYTE ENCRYPT,ENCRYPT2,ANS
XC
X      INTEGER*2 SALT , U , P, P2, invalid
XC
X      CHARACTER PASS*31 , USER*12 , USER_NAME*12 , TERMINAL*8, ERROR*80
X      CHARACTER SEC_PASS*31
XC
X      DIMENSION PASS1(2) , PASS2(2) , ECN(2), PASS_2(2)
XC
X      INTEGER SYS$DELPRC, SYS$GETMSG, LENSTR, OWNER_PID
X      EXTERNAL CHKMSG                       !ROUTINE TO HANDLE BROADCAST MSG
VS
XC
X      PARAMETER BLANK = ' '
XC
X      LOGICAL BRDFLAG
X
X      INCLUDE '($JPIDEF)'
X      INCLUDE '($SMGDEF)'
X      INCLUDE '($LIBCLIDEF)'
X      INCLUDE '($TRMDEF)'
X      INCLUDE '($UAIDEF)'
XC
X      STRUCTURE  /ITMLST/
X       UNION
X        MAP
X         INTEGER*2  BUFLEN , ITMCOD
X         INTEGER*4  BUFADR , RETADR
X        END MAP
X        MAP
X         INTEGER*4  END_LIST
X        END MAP
X       END UNION
X      END STRUCTURE
XC
X      RECORD /ITMLST/ ITM(6)
X
X      COMMON /BRDCST/ BRDFLAG,INPWAIT,MSGID,BRDID,KB,PBDID
XC
XC **********************************************************************
XC
XC  Disable CONTROL_T and CONTROL_Y.
X      MASK = LIB$M_CLI_CTRLT .OR. LIB$M_CLI_CTRLY
X      STAT = LIB$DISABLE_CTRL (MASK,)
X      INVALID = 0
XC
XC  Set up an item list to find out what terminal the process is on and t
XC   username running this image.
XC  Get the terminal.
X      ITM(1).BUFLEN = 7
X      ITM(1).ITMCOD = JPI$_TERMINAL
X      ITM(1).BUFADR = %LOC(TERMINAL)
X      ITM(1).RETADR = 0
XC
XC  Get the username.
X      ITM(2).BUFLEN = 12
X      ITM(2).ITMCOD = JPI$_USERNAME
X      ITM(2).BUFADR = %LOC(USER_NAME)
X      ITM(2).RETADR = 0
X
XC
XC  Get the username.
X      ITM(3).BUFLEN = 4
X      ITM(3).ITMCOD = JPI$_OWNER
X      ITM(3).BUFADR = %LOC(OWNER_PID)
X      ITM(3).RETADR = 0
X      ITM(4).END_LIST = 0
X
XC
X      STAT = SYS$GETJPI (,,, ITM ,,,)
X      IF (.NOT. STAT) CALL LIB$SIGNAL (%VAL(STAT))
X      U = LENSTR(USER_NAME)
X
X      IF (OWNER_PID.NE.0) THEN
X`09`09OWNER_PID2 = OWNER_PID
X`09`09DO WHILE (OWNER_PID2.NE.0)
X`09`09`09OWNER_PID1 = OWNER_PID2
X`09`09`09ITM(1).BUFLEN = 4
X`09`09`09ITM(1).ITMCOD = JPI$_OWNER
X`09`09`09ITM(1).BUFADR = %LOC(OWNER_PID2)
X`09`09`09ITM(1).RETADR = 0
X`09`09`09ITM(2).END_LIST = 0
X`09`09`09STAT = SYS$GETJPI (,OWNER_PID1,, ITM ,,,)
X`09`09`09IF (.NOT. STAT) CALL LIB$SIGNAL (%VAL(STAT))
X`09`09ENDDO
X`09OWNER_PID = OWNER_PID1
X`09ENDIF
X
XC
XC  Check to see if we are over the network, if so abort.
X      IF (INDEX(TERMINAL , 'RT') .GT. 0) THEN
X        TYPE *,' WARNING!! NO SECURITY OVER A REMOTE TERMINAL'`20
X`09TYPE 1219
X1219`09FORMAT (' Do you wish to continue? (Y or N) ',$)
X`09ACCEPT 1221, Ans
X1221`09FORMAT (A1)
X`09If (.NOT.ANS)         GOTO 80
X      ENDIF
X      IF (INDEX(TERMINAL , 'NT') .GT. 0) THEN
X        TYPE *, 'ABORTING!! NO SECURITY OVER A NETWORK TERMINAL'`20
X`09TYPE 1219`20
X`09ACCEPT 1221, Ans
X`09If (.NOT.ANS)         GOTO 80
X      ENDIF
XC
XC  Build the item list to gather UAF info.
XC  The encryption value.
X      ITM(1).BUFLEN = 1
X      ITM(1).ITMCOD = UAI$_ENCRYPT
X      ITM(1).BUFADR = %LOC(ENCRYPT)
X      ITM(1).RETADR = 0
XC
XC  The salt value.
X      ITM(2).BUFLEN = 2
X      ITM(2).ITMCOD = UAI$_SALT
X      ITM(2).BUFADR = %LOC(SALT)
X      ITM(2).RETADR = 0
XC
XC  The hashed password.
X      ITM(3).BUFLEN = 8
X      ITM(3).ITMCOD = UAI$_PWD
X      ITM(3).BUFADR = %LOC(PASS2)
X      ITM(3).RETADR = 0
XC
XC  The hashed secondary password.
X      ITM(4).BUFLEN = 8
X      ITM(4).ITMCOD = UAI$_PWD2
X      ITM(4).BUFADR = %LOC(PASS_2)
X      ITM(4).RETADR = 0
XC
XC  Get the hashing method for secondary
X      ITM(5).BUFLEN = 1
X      ITM(5).ITMCOD = UAI$_Encrypt2
X      ITM(5).BUFADR = %LOC(Encrypt2)
X      ITM(5).RETADR = 0
XC
X      ITM(6).END_LIST = 0
X
XC
XC  Now to get the UAF info.
X      STAT = SYS$GETUAI (,, USER_NAME , ITM ,,,)
X      IF (.NOT. STAT) CALL LIB$SIGNAL (%VAL(STAT))
XC
XC  Create a pasteboard and virtual diplay.
X20    STAT = SMG$CREATE_PASTEBOARD(PBDID,,,)
X      STAT = SMG$CREATE_PASTEBOARD(BRDID,,,)
X      STAT = SMG$SET_BROADCAST_TRAPPING(PBDID,CHKMSG)
X      STAT = SMG$CREATE_PASTEBOARD (PSTB ,,,,)
X      STAT = SMG$CREATE_VIRTUAL_DISPLAY (13 , 80 , MSGID ,,,)
X      STAT = SMG$CREATE_VIRTUAL_DISPLAY (10 , 80 , VD1 ,SMG$M_BORDER,,)
X      STAT = SMG$LABEL_BORDER (MSGID, ' Messages ', SMG$K_TOP)
X      STAT = SMG$PASTE_VIRTUAL_DISPLAY (VD1 , PSTB , 1 , 1 ,)
X      STAT = SMG$PASTE_VIRTUAL_DISPLAY (MSGID , BRDID , 8 , 1 ,)
XC
XC  Create the virtual keyboard.
X      STAT = SMG$CREATE_VIRTUAL_KEYBOARD (KB ,'TT',,,0)
XC
XC  Set teh keypad to numeric mode.
X      STAT = SMG$SET_KEYPAD_MODE (KB , 0)
XC
XC  Display message.
X      STAT = SMG$PUT_CHARS (VD1 , 'L O C K E D   T E R M I N A L' ,
X     -                               2 , 25 , SMG$M_BOLD ,,)
X      STAT = SMG$PUT_CHARS (VD1 , 'USER: '//USER_NAME,
X     -                               4 , 32 , SMG$M_BOLD ,,)
XC
XC  Initialize mask for terminal attributes.
X      TRMSK = TRM$M_TM_CVTLOW .OR. TRM$M_TM_NOECHO
XC
X40    STAT = SMG$REPAINT_SCREEN (PSTB)
X`09USER(1:12) = USER_NAME(1:12)
XC
XC  Get the password.
X
X`09INPWAIT = 1
X
X`09DO 60 WHILE (INPWAIT .EQ. 1)
X
XC *** Read the input, read each keystroke entered from the terminal
X
XC
X      STAT = SMG$SET_CURSOR_ABS (VD1 , 5 , 1)
X      STAT = SMG$READ_STRING (KB , PASS , 'Enter Password: ',,
X     -                        TRMSK ,,, P ,,,,,)
X`09   IF (.NOT. BRDFLAG) THEN
X`09`09INPWAIT = 0
X`09   ELSE
X`09`09BRDFLAG = .FALSE.
X`09   ENDIF
X60`09END DO
X      IF (PASS_2(1).NE.0) THEN
X`09INPWAIT = 1
X`09DO 61 WHILE (INPWAIT .EQ. 1)
X         STAT = SMG$SET_CURSOR_ABS (VD1 , 6 , 1)
X         STAT = SMG$READ_STRING (KB , SEC_PASS , 'Enter Password: ',,
X     -                        TRMSK ,,, P2 ,,,,,)
X`09   IF (.NOT. BRDFLAG) THEN
X`09`09INPWAIT = 0
X`09   ELSE
X`09`09BRDFLAG = .FALSE.
X`09   ENDIF
X61`09END DO
X      ENDIF
X
X
X
XC
XC  Check the encryption value against the Purdy value.
X      T = 12
X      IF (ENCRYPT .NE. %LOC(UAI$C_PURDY)) T = U
XC
XC  Hash the password entered.
XC
X      STAT = SYS$HASH_PASSWORD(PASS(1:P),%VAL(ENCRYPT),
X     -            %VAL(SALT),USER(1:T),PASS1(1))
XC
XC  Compare hashed passwords.
X      IF (PASS1(1) .NE. PASS2(1)) THEN
X        IF ((PASS(1:P) .EQ. 'LO').OR.
X     -      (PASS(1:P) .EQ. 'LOGOUT')) GOTO 100
X        STAT = SMG$RING_BELL (VD1 , 1)
X        INVALID = INVALID + 1
X        GOTO 40
X      ENDIF
XC
X      IF (PASS1(2) .NE. PASS2(2)) THEN
X        IF ((PASS(1:P) .EQ. 'LO').OR.
X     -      (PASS(1:P) .EQ. 'LOGOUT')) GOTO 100
X        STAT = SMG$RING_BELL (VD1 , 1)
X        INVALID = INVALID + 1
X        GOTO 40
X      ENDIF
X
X      IF (PASS_2(1).NE.0) THEN
XC
XC  Check the encryption value against the Purdy value.
X        T = 12
X        IF (ENCRYPT2 .NE. %LOC(UAI$C_PURDY)) T = U
XC
XC  Hash the password entered.
XC
X        STAT = SYS$HASH_PASSWORD(SEC_PASS(1:P),%VAL(ENCRYPT2),
X     -             %VAL(SALT),USER(1:T),PASS1)
XC
XC  Compare hashed passwords.
X       IF (PASS1(1) .NE. PASS_2(1)) THEN
X        IF ((SEC_PASS(1:P) .EQ. 'LO').OR.
X     -      (SEC_PASS(1:P) .EQ. 'LOGOUT')) GOTO 100
X        STAT = SMG$RING_BELL (VD1 , 1)
X        INVALID = INVALID + 1
X        GOTO 40
X      ENDIF
XC
X      IF (PASS1(2) .NE. PASS_2(2)) THEN
X        IF ((SEC_PASS(1:P) .EQ. 'LO').OR.
X     -      (SEC_PASS(1:P) .EQ. 'LOGOUT')) GOTO 100
X        STAT = SMG$RING_BELL (VD1 , 1)
X        INVALID = INVALID + 1
X        GOTO 40
X      ENDIF
X      ENDIF
XC
XC  Time to cleanup.
X80    STAT = SMG$DELETE_VIRTUAL_KEYBOARD (KB)
X      STAT = SMG$DELETE_VIRTUAL_DISPLAY (VD1)
X      STAT = SMG$DELETE_PASTEBOARD (PSTB , )
X      STAT = SMG$DELETE_VIRTUAL_DISPLAY (MSG)
X      STAT = SMG$DELETE_PASTEBOARD (MSGIB , )
X      STAT = SMG$DELETE_PASTEBOARD (PBDID , )
X      STAT = LIB$ENABLE_CTRL (MASK,)
X      IF (INVALID.NE.0) THEN
X           TYPE *, INVALID,' password failures.'
X      ENDIF
X      CALL EXIT
X100   STAT = SMG$DELETE_VIRTUAL_KEYBOARD (KB)
X      STAT = SMG$DELETE_VIRTUAL_DISPLAY (VD1)
X      STAT = SMG$DELETE_PASTEBOARD (PSTB , )
X      STAT = SMG$DELETE_VIRTUAL_DISPLAY (MSG)
X      STAT = SMG$DELETE_PASTEBOARD (MSGIB , )
X      STAT = SMG$DELETE_PASTEBOARD (PBDID , )
X      IF (OWNER_PID.EQ.0) THEN
X              STAT = SYS$DELPRC(,)
X      ELSE
X              STAT = SYS$DELPRC(OWNER_PID,)
X      ENDIF
X        J= SYS$GETMSG(%VAL(STAT),LENGTH,ERROR,%VAL(3),)
X        TYPE 5000,ERROR(2:LENGTH)
X5000    FORMAT(' %LOCK-I-',A<LENGTH-1>)
X      TYPE *, 'PROCESS DELETION FAILURE'
X      GOTO 20
X      END
X
X
X      SUBROUTINE CHKMSG
X
XC *** CHKMSG RUNS WHEN AN INCOMING MESSAGE HAS BEEN TRAPPED BY
XC *** SMG$SET_BROADCAST_TRAP. THE MESSAGE IS DISPLAYED ON A NEW
XC *** PASTEBOARD OVER THE EXISTING DISPLAY UNTIL THE MESSAGE
XC *** HAS BEEN ACKNOWLEDGED BY THE USER. CONTROL RETURNS TO THE
XC *** SCREEN IN PROGRESS.
X
X      IMPLICIT INTEGER (A-Z)
X`09INCLUDE '($SMGDEF)'
X`09INCLUDE '($TRMDEF)'
X
X`09INTEGER CCNT
X`09INTEGER MSGLEN
X
X`09INTEGER TCHAR(988)
X`09INTEGER*2 HCHAR(494)
X`09CHARACTER*988 MESSAGE
X
X`09COMMON /BRDCST/ BRDFLAG,INPWAIT,MSGID,BRDID,KB,PBDID
X`09EQUIVALENCE(HCHAR(1),MESSAGE)
X
X`09INTEGER STATUS,ROW,COL
X
X`09DO I = 1,988
X`09`09MESSAGE(I:I)= ' '
X`09ENDDO
X
X`09STATUS = SMG$GET_BROADCAST_MESSAGE(PBDID,MESSAGE,MSGLEN)
X
X`09J = 1
X
X`09DO 20 K = 1,325
X`09`09CALL MVBITS(HCHAR(K),0,8,TCHAR(J),0)
X`09`09J = J + 1
X`09`09CALL MVBITS(HCHAR(K),8,8,TCHAR(J),0)
X`09`09J = J + 1
X20`09CONTINUE
X
X`09IF (INPWAIT .EQ. 1) THEN
X
X`09   STATUS = SMG$CANCEL_INPUT(KB)
X
X`09   BRDFLAG = .TRUE.
X
X`09ENDIF
X
X
X`09`09   STATUS = SMG$PUT_LINE(MSGID,MESSAGE)
X
X
X        STAT = SMG$REPAINT_SCREEN (MSGID)
X
X`09RETURN
X`09END
X`09INTEGER FUNCTION LENSTR(STRING)
XC***********************************************************************
XC     Function to accept a string STRING and calculate
XC     its length LENGTH.  Where here LENGTH is not equal
XC     X for a CHARACTER*X character string, but is the last
XC     position in the character string where a character is found.
XC***********************************************************************
X`09CHARACTER*(*) STRING,SPACE,NULL
X`09PARAMETER (SPACE=CHAR(32), NULL=CHAR(0))
X`09LENSTR = 0
X`09ILENGTH=LEN(STRING)
X`09DO  I = ILENGTH,1,-1
X`09  IF ((STRING(I:I).NE.SPACE).AND.(STRING(I:I).NE.NULL)) THEN
X`09`09LENSTR = I
X`09 `09RETURN
X`09  ENDIF
X`09ENDDO
X`09RETURN
X`09END
$ CALL UNPACK TERM_LOCK54.FOR;1 1451651280
$ create 'f'
X$ fortran term_lock54
X$ link term_lock54/exe=term_lock
X$ exit
$ CALL UNPACK BUILD_TERMLOCK.COM;1 1181696343
$ v=f$verify(v)
$ EXIT

