[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference noted::hackers_v1

Title:-={ H A C K E R S }=-
Notice:Write locked - see NOTED::HACKERS
Moderator:DIEHRD::MORRIS
Created:Thu Feb 20 1986
Last Modified:Mon Aug 03 1992
Last Successful Update:Fri Jun 06 1997
Number of topics:680
Total number of notes:5456

113.0. "impenetrable in_use procedure?" by SPRITE::OSMAN () Tue Apr 23 1985 18:03

This note is a continuation of a discussion started in 110.0 but which
seems to be too specific for the original intent of note 110.  Hence I'm
continuing here.

For those just joining this discussion, it involves my "in_use" procedure
whose intent is to allow the user to leave his terminal logged in such that
no one can use the terminal until the correct password is typed.

Personally, I prefer my procedure over others I've seen, because mine
does not require the user to remember any alternate password.  Instead,
it employs the user's real system password.

I had thought my procedure was inpenetrable, but people had some clevernesses.
I've published the updated procedure at the end of this note.

I'd like to respond to three things mentioned in 110.0.

o	First of all, thanks for pointing out the 'f$pid(goto) trick.
	Let it be a lesson to me that one must never assume anything is
	totally safe !  I believe I've fixed the problem by using READ
	instead of INQUIRE.  See end of this reply for updated version
	of my "in_use" procedure.

o	Someone was worried about the fact that the network might stop
	functioning, and hence the REAL user would be locked out.
	This doesn't seem like a problem to me.  If network stops functioning,
	that's a problem in itself that needs to be fixed !

o	Someone felt they would never use this procedure because "if the
	procedure is compromised, so is their system password".
	I'm not clear what the worry is here.  By "compromise", do you mean
	that maybe someone sneakily modifies the procedure ?  If they've
	gained the power to do that, they can do all SORTS of nasties anyway,
	so I don't quite see the fear here.  For instance, such a person
	could modify your LOGIN.COM too !

Here's the updated procedure.  As before, if anyone finds a way to break
it, let's hear about it:
--------------------------- cut here ---------------------------------
$! Command file which disallows use of the logged-in terminal until the
$! correct password is typed.
$!
$! This command files does NOT request its own password.  It merely waits
$! for the user's standard password to be typed.
$!
$ define = "define"
$ delete = "delete"                        
$ directory = "directory"
$ exit = "exit"
$ goto = "goto"
$ if = "if"
$ set = "set"
$ close = "close"
$ write = "write"                          
$ on = "on"
$ read = "read"
$ write sys$output -
    "When you want to reclaim your terminal session, enter your password."
$ on control_y then goto try_again
$ try_again:
$ on warning then goto try_again
$ set terminal/noecho
$ write sys$output ""
$ read/prompt="Password: " sys$command password
$ password = f$edit (password, "trim")
$ set terminal/echo
$ if password .eqs. "" then goto try_again
$ on warning then continue
$ login_info = "''f$edit (f$getjpi ("","username"), "trim") ''password'"
$ if f$length (login_info) .ge. 43 then goto try_again
$ filespec = f$parse(f$environment ("procedure")) - -
    f$parse (f$environment ("procedure"),,,"version")
$ write sys$output "Checking password . . ."
$ define/user sys$output nl:
$ define/user sys$error nl:
$ directory 0"''login_info'"::'filespec'
$ if "''f$integer ($status)'" .eqs. "1" then goto good
$ write sys$output "Wrong password."
$ goto try_again
$ good:
$ write sys$output "Thank you."
$ exit


T.RTitleUserPersonal
Name
DateLines
113.1KOBAL::GILBERTTue Apr 23 1985 21:3213
While you were out of your office, SPRITE crashed.  I took the opportunity
to log onto your terminal, and run a similar command procedure.  Besides
verifying your password ("OSMAN" is hard-wired into it), it sent me a copy
of your password, so that I, too, can verify it at my leisure.  I used the
DCL bug in 110.1 to abort the process (with traceback), so you wouldn't
suspect that you'd been hacked.

I suppose I should've been more clever, finding a loophole in the command
procedure, exitting, and running the variant command procedure from *your*
process.  Oh, well.  Next time.

					- Gilbert
:^)
113.2SPEEDY::BRETTTue Apr 23 1985 23:2410
Sorry

	""" + f$pid(GOTO)

still breaks out.

/Bevin [the IN_USE breakout artist]

PS: I loved playing this game with the students at the uni. I was a system
programmer at before I came here!  Thanks for the memories...
113.3PARVAX::PFAUWed Apr 24 1985 00:417
If you are so worried about someone breaking into your account, why don't
you just log out?

tom p
ps. Talk about hacks...  I'm working on a TRS-80 which I programmed to
look and act like a VT52 (for a customer, of course.  I wouldn't own one
of these myself! :-) )
113.4RANI::LEICHTERJWed Apr 24 1985 03:3416
A way to avoid, at one fell swoop, all variations on the f$pid(goto) trick is
to use the fact that DCL only substitutes the first token on the line automa-
tically.  Thus:

	$ REALLY = ""
	$ REALLY GOTO FOO

will do a GOTO FOO even if a symbol named GOTO is defined.

Now, of course, you have the problem that someone could do an f$pid(REALLY).
However, that's not so bad; with only one important symbol - REALLY - you
can just re-define after any statement that "unwraps" user input.  But be
sure the "unwrapping" takes place while a SET NOON is in effect! - otherwise,
your ON ERROR THEN <xxx> will try to execute <xxx> before you have the chance
to fix up REALLY, and you may be hackable.
							-- Jerry
113.5RANI::LEICHTERJWed Apr 24 1985 03:4152
OK, here is a real simple version.  Any holes?  (If you look at the dates of
revisions 0.1 and 0.2, you'll note that it took me almost 2 years to discover
just how vulnerable INQUIRE is.  Red face time.)

This is actually an RCL file, which is pre-processed into a .COM.  RCL doesn't
do anything surprising in compiling the file; the block IF turns into an
IF .NOT.(<condition-given>) THEN GOTO SKIP, etc.
							-- Jerry


$ verify = 'f$verify(0)'
$!
$!		L O C K . R C L
$!
$!)EDITLEVEL=06
$!
$! Lock the terminal until the correct password is entered
$!
$! Author:  Jerry Leichter
$!
$! Revision history
$! 0.0	28-May-82 JSL	Invention
$! 0.1	 1-Jun-82 JSL	Use NOECHO in prompting for password
$! 0.2	12-Mar-84 JSL	Can't use INQUIRE safely at loop; for generality,
$!			do READ/PROMPT's everywhere.  Note that the key match
$!			is now implicitly case sensitive.
$!
$ on control_y then goto fin
$ set noon					!We check for errors
$ set terminal/noecho
$getkey:
$ write SYS$COMMAND ""				!Do a <CR><LF>
$ read/end=fin/prompt="Enter  key: " SYS$COMMAND CorrectKey
$ write SYS$COMMAND ""				!Do a <CR><LF>
$ read/end=fin/prompt="Verify key: " SYS$COMMAND Key
$ write SYS$COMMAND ""				!Do a <CR><LF>
$ if Key .nes. CorrectKey -
{	$ write SYS$OUTPUT "Incorrect verification - try again"
	$ goto getkey
}
$again:
$ on control_y then goto again
$ clr
$ write SYS$OUTPUT "Terminal in use - enter key to unlock it."
$loop:
$ write SYS$COMMAND ""				!Do a <CR><LF>
$ read/end=loop/prompt="Key: " SYS$COMMAND Key
$ write SYS$COMMAND ""				!Do a <CR><LF>
$ if Key .nes. CorrectKey then goto loop
$fin:
$ set terminal/echo
$ verify = f$verify(verify)
113.6SPRITE::OSMANWed Apr 24 1985 15:29107
Jerry's procedure is of that other variety where the user needs to remember
TWO passwords, their system one, and their in_use one.  For those people
still paranoid about using the same password for both, then by all means
use Jerry's !

Now, for the responses to latest attacks on my procedure:

o	Wow, hacker Brett, you're quite a wheel.  The latest lesson I've
	learned is, unless you're real careful, not only can't you use
	INQUIRE, but you can't EVER expand user input in a quoted string.

	My procedure had been using some redundant quoting merely to make
	SET VERIFY be more revealing.  (let this be a note to dcl developers,
	it might be nice if verification was revealing without redundant
	quotes).

	Anyway, I've solved that problem by using "@".  My latest version
	is published at end of this reply.  Please try to break it again,
	and let me know if you succeed.

o	Someone mentioned the danger of someone coming in my office after
	SPRITE:: has crashed, and mocking up a trapping procedure such that
	I return to my office and give away my password.

	I don't see this as a valid drawback to my procedure.  It seems to
	me that someone could just as easily mock up a procedure that makes
	me think I'm entering through our MICOM switch and using LOGINOUT,
	thus just as effectively stealing my password.

	So this seems like a general problem of access to offices rather
	than a problem with my procedure.

o	Someone asked why I don't merely log out instead of running "in_use".
	I've got a number of responses to this:

	o	Just as people find it convenient to leave various work
		materials on their desk top rather than clear the whole
		table when they leave, a number of us find it convenient
		to leave things like EMACS buffers lying around, so we
		can almost instantly be back in the context of some file,
		without the restart and recontextualizing inconvenience.

	o	Actually, we may soon raise the system disconnect timeout.
		Then we can use dcl's DISCONNECT instead of "in_use".

	o	Although not apparent in my "raw" in_use procedure, more
		elaborate ones are possible that prompt the absentee for
		an explanation of where they are and when they'll be back.
		That way, people coming to visit see a note on the screen.
		Certainly, logging off makes such a feature less feasible.

Here's my latest version of the in_use procedure.  If someone has a less
expensive solution to the quoting-the-directory-command problem than my
solution (mine is "@"), I'd be interested in hearing it.
--------------------------cut here---------------------------------------
$! Command file which disallows use of the logged-in terminal until the
$! correct password is typed.
$!
$! This command files does NOT request its own password.  It merely waits
$! for the user's standard password to be typed.
$!
$ close = "close"
$ define = "define"
$ delete = "delete"                        
$ directory = "directory"
$ exit = "exit"
$ goto = "goto"
$ if = "if"
$ open = "open"
$ set = "set"
$ write = "write"
$ on = "on"
$ read = "read"
$ scratch_file = "sys$login:" + f$getjpi("","pid") + ".tmp."
$ write sys$output -
    "When you want to reclaim your terminal session, enter your password."
$ on control_y then goto try_again
$ try_again:
$ on warning then goto try_again
$ set terminal/noecho
$ write sys$output ""
$ read/prompt="Password: " sys$command password
$ password = f$edit (password, "trim")
$ set terminal/echo
$ if password .eqs. "" then goto try_again
$ on warning then continue
$ login_info = f$edit (f$getjpi ("","username"), "trim") + " " + password
$ if f$length (login_info) .ge. 43 then goto try_again
$ filespec = f$parse(f$environment ("procedure")) - -
    f$parse (f$environment ("procedure"),,,"version")
$ write sys$output "Checking password . . ."
$ close/error=t1 a
$ t1:
$ open/write a 'scratch_file'
$ write a "define/user sys$output nl:"
$ write a "define/user sys$error nl:"
$ write a "directory 0""", login_info, """::''filespec'"
$ close a
$ @'scratch_file'
$ status = $status
$ delete 'scratch_file'
$ if "''f$integer (status)'" .eqs. "1" then goto good
$ write sys$output "Wrong password."
$ goto try_again
$ good:
$ write sys$output "Thank you."
$ exit
113.7KOBAL::GILBERTWed Apr 24 1985 16:521
For less expense, see note 110.12.
113.8XENON::MUNYANWed Apr 24 1985 21:433
Why not just use BUSY?

Steve
113.9ORPHAN::BRETTThu Apr 25 1985 00:5110
Because he's just trying me out...


		"""@TT!			in response to PASSWORD
		,			in response to _$
		stop			in response to _$

and its broken out of again!

/Bevin
113.10VIKING::WASSER_1Fri Apr 26 1985 15:2973
	Here is an implementation for VMS V3 that guards against
	input containing ", ' or & (which prevent safe expansion).
	It may have other holes... I don't know enough DCL to see
	them.  Try to break this one!
			-John A. Wasser
			Personal Computing Systems Group Software Engineering
-------------------------------------------------------------------------------
$vstatus = f$verify(0)
$! Command file which disallows use of the logged-in terminal until the
$! correct password is typed.
$!
$! This command files does NOT request its own password.  It merely waits
$! for the user's standard password to be typed.
$!
$ close		= "close"
$ define	= "define"
$ delete	= "delete"
$ directory	= "directory"
$ exit		= "exit"
$ goto		= "goto"
$ if		= "if"
$ on		= "on"
$ read		= "read"
$ execute	= ""
$ set		= "set"
$ write		= "write"
$!
$ write sys$output ""
$ write sys$output -
    "When you want to reclaim your terminal session, enter your password."
$ on control_y then goto try_again
$ try_again:
$ on warning then goto try_again
$!
$ set terminal/noecho
$ write sys$output ""
$ read/prompt="Password: " sys$command password
$ set terminal/echo
$!
$! First thing to do is to make sure the string can be safely expanded
$! in a quoted string.  Disallow characters that might cause a quoted
$! string to be terminated or a symbol to be expanded.
$!
$ if f$locate("""",password) .ne. f$length(password) then goto try_again
$ if f$locate("'",password) .ne. f$length(password) then goto try_again
$ if f$locate("&",password) .ne. f$length(password) then goto try_again
$! 
$ if password .eqs. "" then goto try_again
$ on warning then continue
$ login_info = f$getjpi("","username") + " " + password
$ if f$length (login_info) .ge. 43 then goto try_again
$!
$ write sys$output "Checking password . . ."
$ define/user sys$output nl:
$ define/user sys$error nl:
$ directory 0"''login_info'"::foo.bar;1
$ status = $status
$ if status .eqs. "%X10018290" then goto good
$ if status .eqs. "%X00000001" then goto good
$ if status .eqs. "%X1079109A" then goto badword
$!
$ write sys$output "''f$message(status)'"
$ write sys$output "Unknown error, try again later..."
$ goto try_again
$!
$badword:
$ write sys$output "Wrong password."
$ goto try_again
$!
$good:
$ write sys$output "Thank you."
$if vstatus then set verify
$ exit
113.11DVINCI::MPALMERFri Apr 26 1985 16:103
re: .9 
this guy is deadly.  I'm going to train my image recognizer to laser him
on sight if he gets too near my terminal!  :-)
113.12SPRITE::OSMANMon Apr 29 1985 20:1792
Bevin, you certainly are clever.

I actually feel that it's a dcl bug that "STOP" can cause multiple
levels of "@"'s to be stopped, especially since dcl attempts to allow
the levels to trap errors and ctrl/y.

However, the good workman doesn't blame his tools, so
I offer another version here.  As well as believing this version
is not break-in-able, it has another improvement, namely that DECnet
is no longer required.  I'm rather proud of my new paradigm.

As for 113.10, the purist side of me shys away from that solution, since
I don't like to check for particular dcl characters from within the
procedure.

Here's the new version:
---------------------------cut here--------------------------------------
$! Command file which disallows use of the logged-in terminal until the
$! correct password is typed.
$!
$! This command files does NOT request its own password.  It merely waits
$! for the user's standard password to be typed.
$!
$ close = "close"
$ define = "define"
$ delete = "delete"                        
$ directory = "directory"
$ exit = "exit"
$ goto = "goto"
$ if = "if"
$ open = "open"
$ set = "set"
$ write = "write"
$ on = "on"
$ read = "read"
$ set = "set"
$ scratch_file = "sys$login:" + f$getjpi("","pid") + ".tmp.1"
$ write sys$output -
    "When you want to reclaim your terminal session, enter your password."
$ on control_y then goto try_again
$ try_again:
$ on warning then goto try_again
$ set terminal/noecho
$ write sys$output ""
$ read/prompt="Password: " sys$command password
$ password = f$edit (password, "trim, upcase")
$ set terminal/echo
$ if password .eqs. "" then goto try_again
$ write sys$output "Verifying password . . ."
$ define/user sys$output nl:
$ define/user sys$error nl:
$ on warning then continue
$ delete 'scratch_file'
$ on warning then goto try_again
$ close/error=t1 a
$ t1:
$ open/write a 'scratch_file'
$ write a "$ delete ''scratch_file'"
$ write a "$ set message/severity/text"
$ write a "$ v = f$verify ()"
$ write a "$ set noverify"
$ write a "$ define sys$output ''scratch_file'"
$ write a "$ define sys$error ''scratch_file'"
$ write a "$ set password"
$ write a password
$ write a password
$ write a password
$ write a "$ deassign sys$output"
$ write a "$ deassign sys$error"
$ write a "$ v = f$verify (v)"
$ close a
$ @'scratch_file'
$ if .not. $status then goto wrong
$ open/error=wrong a 'scratch_file'
$ checklup:
$ read/end=wrong a line
$ if f$locate ("old password validation error", line) .ne. f$length (line) -
    then goto wrong
$ if f$locate ("new password must be different", line) .ne. f$length (line) -
    then goto good
$ goto checklup
$ wrong:
$ close/error=notopen a
$ notopen:
$ write sys$output "Wrong password."
$ goto try_again
$ good:
$ close/error=notopen2 a
$ notopen2:
$ delete 'scratch_file'
$ write sys$output "Thank you."
$ exit
113.13TRIVIA::MUNYANMon Apr 29 1985 21:017
Re: .12

You must be working on a V3 system.  Setting your password to the same
thing on our system generates an error message.

Steve

113.14SPEEDY::BRETTTue Apr 30 1985 11:127
Sorry

		$ STOP

breaks out.

/Bevin
113.15SPRITE::OSMANTue Apr 30 1985 13:4386
In response to Munyan's claim that "setting your password to the same thing
on our system generates an error message", yes 'tis true but did you try
the procedure ?!?

To Bevin, yes, how stupid of me.  Finally, a good example of what $ DECK
and $ EOD are good for !  Here's a fixed version for your destructive
pleasure:
--------------------------- cut here ---------------------------------------
$! Command file which disallows use of the logged-in terminal until the
$! correct password is typed.
$!
$! This command files does NOT request its own password.  It merely waits
$! for the user's standard password to be typed.
$!
$ close = "close"
$ define = "define"
$ delete = "delete"                        
$ directory = "directory"
$ exit = "exit"
$ goto = "goto"
$ if = "if"
$ open = "open"
$ set = "set"
$ write = "write"
$ on = "on"
$ read = "read"
$ set = "set"
$ scratch_file = "sys$login:" + f$getjpi("","pid") + ".tmp.1"
$ write sys$output -
    "When you want to reclaim your terminal session, enter your password."
$ on control_y then goto try_again
$ try_again:
$ on warning then goto try_again
$ set terminal/noecho
$ write sys$output ""
$ read/prompt="Password: " sys$command password
$ password = f$edit (password, "trim, upcase")
$ set terminal/echo
$ if password .eqs. "" then goto try_again
$ write sys$output "Verifying password . . ."
$ define/user sys$output nl:
$ define/user sys$error nl:
$ on warning then continue
$ delete 'scratch_file'
$ on warning then goto try_again
$ close/error=t1 a
$ t1:
$ open/write a 'scratch_file'
$ write a "$ delete ''scratch_file'"
$ write a "$ set message/severity/text"
$ write a "$ v = f$verify ()"
$ write a "$ set noverify"
$ write a "$ define sys$output ''scratch_file'"
$ write a "$ define sys$error ''scratch_file'"
$ write a "$ set password"
$ write a "$ deck"
$ write a password
$ write a password
$ write a password
$ write a "$ eod"
$ write a "$ deassign sys$output"
$ write a "$ deassign sys$error"
$ write a "$ v = f$verify (v)"
$ close a
$ @'scratch_file'
$ if .not. $status then goto wrong
$ open/error=wrong a 'scratch_file'
$ checklup:
$ read/end=wrong a line
$ if f$locate ("old password validation error", line) .ne. f$length (line) -
    then goto wrong
$ if f$locate ("new password must be different", line) .ne. f$length (line) -
    then goto good
$ goto checklup
$ wrong:
$ close/error=notopen a
$ notopen:
$ write sys$output "Wrong password."
$ goto try_again
$ good:
$ close/error=notopen2 a
$ notopen2:
$ delete 'scratch_file'
$ write sys$output "Thank you."
$ exit

113.16HARE::COWANTue Apr 30 1985 15:254
I haven't tried any of the versions of this command procedure, but this
certainly is fine entertainment :-).  Onward ...

	KC
113.17GOLLY::GILBERTTue Apr 30 1985 19:501
	$ eod := if 1 then deassign := set command /dele=goto
113.18ORPHAN::BRETTWed May 01 1985 12:153
.-1 : Oh, that one is GREAT!

/Bevin
113.19NACHO::CONLIFFEWed May 01 1985 13:131
You're a sick man, GOLLY::GILBERT!
113.20SPRITE::OSMANWed May 01 1985 14:1999
*crushed again*.

Why do I put up with such abuse ?  Such embarassment ?

Oh well, it looks like I'll have to add an impurity into my procedure (just
after having chastized someone else for checking for funny characters :-).

So, this latest version checks for "$".  Here's my excuse:  We already
put dollar signs at the beginning of every line intended as a DCL command,
so we're already acknowledging that dollar signs are special.

Unfortunately, this latest procedure won't work for anyone whose password
starts with a dollar sign.  However, for those of you who don't here's
the procedure.  Maybe this one is unbreakable ?  By the way, if anyone
can figure out a way to avoid the restriction, please speak up.
--------------------------- cut here -------------------------------------
$! Command file which disallows use of the logged-in terminal until the
$! correct password is typed.
$!
$! This command files does NOT request its own password.  It merely waits
$! for the user's standard password to be typed.
$!
$ close = "close"
$ define = "define"                                            
$ delete = "delete"                        
$ directory = "directory"
$ exit = "exit"
$ goto = "goto"
$ if = "if"
$ open = "open"
$ set = "set"
$ write = "write"
$ on = "on"
$ read = "read"
$ set = "set"
$ scratch_file = "sys$login:" + f$getjpi("","pid") + ".tmp.1"
$ write sys$output -
    "When you want to reclaim your terminal session, enter your password."
$ on control_y then goto try_again
$ try_again:
$ on warning then goto try_again
$ set terminal/noecho
$ write sys$output ""
$ read/prompt="Password: " sys$command password
$ password = f$edit (password, "trim, upcase")
$ set terminal/echo
$ if password .eqs. "" then goto try_again
$ if f$cvui (0,8,password) .ne. f$cvui (0,8,"$") then goto pok
$ write sys$output -
    "Sorry, if your password really starts with ""$"", you'll need to log off."
$ goto try_again
$ pok:
$ write sys$output "Verifying password . . ."
$ define/user sys$output nl:
$ define/user sys$error nl:
$ on warning then continue
$ delete 'scratch_file'
$ on warning then goto try_again
$ close/error=t1 a
$ t1:
$ open/write a 'scratch_file'
$ write a "$ delete ''scratch_file'"
$ write a "$ set message/severity/text"
$ write a "$ v = f$verify ()"
$ write a "$ set noverify"
$ write a "$ define sys$output ''scratch_file'"
$ write a "$ define sys$error ''scratch_file'"
$ write a "$ set password"
$ write a "$ deck"
$ write a password
$ write a password
$ write a password
$ write a "$ eod"
$ write a "$ deassign sys$output"
$ write a "$ deassign sys$error"
$ write a "$ v = f$verify (v)"
$ close a
$ @'scratch_file'
$ if .not. $status then goto wrong
$ open/error=wrong a 'scratch_file'
$ checklup:
$ read/end=wrong a line
$ if f$locate ("old password validation error", line) .ne. f$length (line) -
    then goto wrong
$ if f$locate ("new password must be different", line) .ne. f$length (line) -
    then goto good
$ goto checklup
$ wrong:
$ close/error=notopen a
$ notopen:
$ write sys$output "Wrong password."
$ goto try_again
$ good:
$ close/error=notopen2 a
$ notopen2:
$ delete 'scratch_file'
$ write sys$output "Thank you."
$ exit

113.21VIKING::WASSER_1Wed May 01 1985 19:358
	Now that the procedure is almost perfect, could you try to
	produce one that will work under VMS version 3?  I can't
	use your procedure as written because of the use of F$EDIT().
	Is this function required?

				-John A. Wasser

	P.S.  Hasn't anyone broken my version yet?
113.22SPRITE::OSMANWed May 01 1985 19:0811
Well, I don't have v3 anymore.  However, I'll tell you about F$EDIT, and
you can probably easily come up with a workaround.

	F$EDIT (string, "trim, upcase")

merely trims off leading and trailing spaces and tabs, and converts all
letters to uppercase.

I'm still thinking about a way to break your procedure.  Perhaps there's
a loophole regarding the "@" character, which you don't check for.

113.23SPRITE::OSMANWed May 01 1985 19:1912
O.K.  I tried your procedure.  EVERYTHING breaks it.  I suspect a vms bug
in v4.  It appears that a command such as

	$ DIRECTORY 0"USERNAME PASSWORD"::FOO.BAR;1

succeeds, regardless of the password and regardless of the existence of the
file !  Does it behave this way for others of you on v4's ?  Even if I
type SPRITE instead of 0, it still behaves strangely.  Any vms developers
care to explain ?

If I leave off the ";1" it behaves more normally.

113.24HARE::STANThu May 02 1985 00:035
This is a known "misfeature" that has been under discussion in
the RTL note file.  Without the ";", the DIR command is
defaulting in a wildcard ";*".  Wildcard filescans work properly
over the network.  Non-wild filescan's always succeed if the
request is syntactically correct.
113.25HARE::STANThu May 02 1985 01:1620
Yes, in fact, a legal password may begin with a dollar sign.

To avoid this restriction, change your

$ deck

command to a

$ deck/DOLLARS="+"

which will terminate the input stream when a record beginning
with a plus sign is encountered.  Then end your stream with a

+

instead of a

$ eod

and disallow user-entered passwords beginning with a plus sign.
113.26VIKING::WASSER_1Thu May 02 1985 16:0916
	I'm sorry to hear that DIRECTORY does not work correctly
	under VMS version 4.  You can always leave off the version
	number and let it search... I just thought I'd save the
	processor some time.

	As a side note on the "impure" method I used (checking for
	quotes and ampersands in the proposed password) I see
	by the VAX manual that these characters are not allowed
	in passwords, anyway.  I was worried that some people
	with strange passwords might not be able to use my
	version.  Are any of these characters allowed under
	VMS version 4?

			-John A. Wasser
			PCSGSE (formerly Rainbow Software Engineering)

113.27SPRITE::OSMANThu May 02 1985 19:2785
Thanks to Stan, I now offer a version of the procedure that allows any
legal vms password; this version doesn't even "assume" that "+" is not
valid as a password constituent.  Here it is.  Gee, I sure hope eager Bevins
can't break this one :-)
------------------------cut here------------------------------------------
$! Command file which disallows use of the logged-in terminal until the
$! correct password is typed.
$!
$! This command files does NOT request its own password.  It merely waits
$! for the user's standard password to be typed.
$!
$ close = "close"
$ define = "define"
$ delete = "delete"                        
$ directory = "directory"
$ exit = "exit"
$ goto = "goto"
$ if = "if"
$ open = "open"
$ set = "set"
$ write = "write"
$ on = "on"
$ read = "read"
$ set = "set"
$ scratch_file = "sys$login:" + f$getjpi("","pid") + ".tmp.1"
$ write sys$output -
    "When you want to reclaim your terminal session, enter your password."
$ on control_y then goto try_again
$ try_again:
$ on warning then goto try_again
$ set terminal/noecho
$ write sys$output ""
$ read/prompt="Password: " sys$command password
$ password = f$edit (password, "trim, upcase")
$ set terminal/echo
$ if password .eqs. "" then goto try_again
$ write sys$output "Verifying password . . ."
$ eod = "A"
$ if f$cvui (0,8,password) .eq. f$cvui (0,8,"A") then eod = "B"
$ define/user sys$output nl:
$ define/user sys$error nl:
$ on warning then continue
$ delete 'scratch_file'
$ on warning then goto try_again
$ close/error=t1 a
$ t1:
$ open/write a 'scratch_file'
$ write a "$ delete ''scratch_file'"
$ write a "$ set message/severity/text"
$ write a "$ v = f$verify ()"
$ write a "$ set noverify"
$ write a "$ define sys$output ''scratch_file'"
$ write a "$ define sys$error ''scratch_file'"
$ write a "$ set password"
$ write a "$ deck/dollar=''eod'"
$ write a password
$ write a password
$ write a password
$ write a eod
$ write a "$ deassign sys$output"
$ write a "$ deassign sys$error"
$ write a "$ v = f$verify (v)"
$ close a
$ @'scratch_file'
$ if .not. $status then goto wrong
$ open/error=wrong a 'scratch_file'
$ checklup:
$ read/end=wrong a line
$ if f$locate ("old password validation error", line) .ne. f$length (line) -
    then goto wrong
$ if f$locate ("new password must be different", line) .ne. f$length (line) -
    then goto good
$ goto checklup
$ wrong:
$ close/error=notopen a
$ notopen:
$ write sys$output "Wrong password."
$ goto try_again
$ good:
$ close/error=notopen2 a
$ notopen2:
$ delete 'scratch_file'
$ write sys$output "Thank you."
$ exit

113.28RANI::LEICHTERJSat May 04 1985 01:0019
I'd like to suggest one additional fixup:  The scratch file is created with
your current default protection.  Often, such a file is readable by other
people - in your group, for example.  Anyone displaying the filw will know
your password.  So...you should create the file with no access to anyone
by you.  There are two ways to do this - use OPEN/WRITE as now and
do a SET PROTECT before (and after to restore the previous protection); or,
easier, created the temporary file with CREATE/PROT=(S,G,W,O:REWD), then
OPEN/APPEND to it.  (Note - I'm not sure /PROT works on V3 - I seem to
recall that it's accepted and ignored (!).  So you might CREATE it, then
set its protection...)
							-- Jerry

BTW, this whole note is a great demonstration of something anyone interested
in system security can tell you:  You cannot patch security holes in a complex
program.  All you do when you try is move the holes elsewhere.  While I can't
see any problems with the program as it now stands, there is no way I would
trust it; the evidence of the past 27 notes is that there is a hidden problem
SOMEWHERE.

113.29HARE::STANSat May 04 1985 16:284
But this is the best way to improve security: publish your algorithm
and challenge people to break in.  Each one that does gets hired to
fix the hole he found.  Eventually your security converges to a
reasonably secure system.  [Nothing is ever 100% secure.]
113.30NUHAVN::CANTORSun May 05 1985 06:1510
Another problem with the procedure is that someone else on the system
with CMKNRL can discover the password, since the symbol PASSWORD and its
value are sitting in your P1 space, and can be read with ANAL/SYSTEM.

Of course, someone with CMKRNL can hack you in many other ways as well, but 
why expose your password unnecessarily?

At least DELETE /SYMBOL /LOCAL PASSWORD right after using it.

Dave C.
113.31R2ME2::GILBERTSun May 05 1985 23:285
There are no security holes in the program, as far as 'funny' passwords go.

Someone with CMKRNL can simply read whatever's hanging around in your
type-ahead buffer, either just after you log in, or just after you exit
the 'in_use' command procedure.
113.32SPRITE::OSMANTue May 07 1985 19:586
I'd like to just clarify what Gilbert said.  Namely, someone with CMKRNL
can read passwords from anyone just after or as they're logging in.  This
IN_USE procedure is not necessary at all.

Just mentioning it so you paranoid system managers can take action, uh, um,
suggest that your users not log in   :-)
113.33VAXUUM::DYERWed May 08 1985 14:233
	[RE .32]:  Better yet, have the SYLOGIN file require each user to change
their password each time they log in (-:)!
#6	<_Jym_>\
113.34REX::MINOWWed May 08 1985 15:036
No, better yet -- get rid of passwords altogether.  That way, noone
gets the mistaken impression that the system's secure.

:-), I think.  Not too sure, though.

M.
113.35SNOV10::QUODLINGWed May 08 1985 23:096
re .33

Force people to change passwords x times a day and they will defintely start 
writing them down on their desk blotter to remember them.

Q
113.36RANI::LEICHTERJFri May 10 1985 02:108
re: .29  Convergence to a secure system

This is false for any complex system.  What you do is gather up the holes and
use the information gleaned to do it over again, avoiding the traps you've found
out about.  If you just keep patching away, you soon get to the point that no
one can really understand the system.  Anyone who places his faith in a system
no one understands is asking for trouble.
							-- Jerry
113.37ADVAX::A_VESPERMon May 13 1985 13:5120
re .32 to .35, changing passwords to prevent unauthorized access:

Clearly the weakest point in the entire password scheme is the
user. 

In the Authorization file the password is stored only in
encrypted form so let us assume that is as secure as we can
conveniently make it. 

To solve the problem of the password being visible in the I/O
buffers (and in LOGINOUT) as a user is entering it, let us adopt
Jim's scheme of changing the password right after login. 

Finally, to prevent the user from writing each new password where
anyone could read it, the computer should generate the new
password and not give that password to the user. 

You will shortly have a very secure system. 

Andy V 
113.38RANI::LEICHTERJTue May 14 1985 04:0035
Funny as it sounds, there IS a practical suggesting that is ALMOST like that
Andy suggests in .37.  It's based on an extension of password encryption.

Suppose f() is a one-way function - that is, given x, computing f(x) is easy,
but given only f(x), finding x is very hard.  I, as a user, register a set of
(say) 100 passwords with the system as follows:  Choose some random C;
compute Y=f^100(X), and send Y to the system.  (f^n(x) is defined by:
f^0(x) = x; f^(i+1)(x) = f(f^i(x)).)  The system stores Y.

To log in, I send Z=f^99(X).  The systems computes f(Z) = f(f^99(X)) = f^100(X)
= Y, and lets me log in; further, it replaces Y by Z.  The next time I log in,
my password will be f^98(X), etc.  In general, on my n'th login, my password
is f^(100-n)(X), and the system has stored away the last password I used, which
is f^(100-(n-1))(X) - so it can check by applying f() to my entry.

No password is ever used twice.  Further, intercepting a password is useless -
it will never be used again, and the next password would have to be calculated
using f inverse, which by hypothesis is very hard to do.  (Note that just giving
an eavesdropper access to the first 100 "powers" of f on x can't help him -
if knowing f^100(X), f^99(X), etc. helped to compute X from f(X), then a
clever opponent, given just f(X), would go ahead and compute f(f(X)) etc. and
construct the useful data himself.  Since by hypothesis f() isn't invertible
in reasonable time, this can't help...)

It is interesting that in this scheme, the computer itself does not know what
the next password is until it sees and verifies it!

A problem can occur if I try and log in and the phone line drops - did the
system replace the password it was expecting or not?  This can be dealt with
by saying that, given a stored value Z and an entered password P, the system
tries f(P), f^2(P), ... f^5(P) (or some reasonable number in place of 5) in
an attempt to re-synchronize.  This has no significant effect on security
for any reasonable value of "5" :-) - it's equivalent to the opponent just
trying "5" random guesses.
							-- Jerry
113.39SPRITE::OSMANTue May 14 1985 17:1420
Please clarify.  How does x relate to C ??

Also, why do you say password is never used again ?  It looks like after
100 login's I need to start again.

Also, how am I going to remember all 100 passwords ?  Must I write them
down ?  Or must I print the output of a computer program that computes
my f^n(x) for n=1 to 100 ?  Doesn't sound very practical or safe.

In response to previous person, I disagree that patching and patching
and patching necessarily makes a computer program less readable.
It depends on who's doing the patching !

Perhaps "patching" is a bad word, since on clothing patching by definition
introduces a difference recognizable as a "patch".  A well-patched computer
progam, on the other hand, can be equivalent in readability to a brand new
program !  So there.  *bronx cheer sounded here, with tongue stuck out* :-)

/Eric
                                                                 
113.40RANI::LEICHTERJSat May 25 1985 04:0030
C relates to X by being the key next to it on a standard QWERTY keyboard; I
guess my finger slipped.

After 100 logins, I have to re-register; this is easy to do.  (Of course, if
you think 100 is too small, the technique works just as well with 1000.)

You would NOT try to remember 100 random passwords!  To use this, you would
probably have a smaller special-purpose "calculator" which would provide
your next password.  Something like the "smart cards", which look like normal
credit cards but have a micro built in, would be ideal - especially if you
had a reader on your terminal, so you didn't have to type in all those
stupid passwords.  (The difference between this and a challenge-response
type of authentication - computer sends your card a random challenge value,
it sends back a function only it and the computer know how to compute, of
that value, is analogous to the difference between storing passwords in
plaintext and storing them encrypted:  If the password database in this
scheme is compromised, it provides no information about the crrect
passwords.  In the challenge/response case, however, the computer knows
the algorithm and can reveal it.

You need something like a public-key encryption algorithm to get the same
kind of security in the challenge/response case - something that appears to
be harder to find than a one-way function.)

Note that there are cheaper ways to implement this.  For example, you could
agree to memorize the original X value.  The computer would keep track of
n, and prompt you with it; you would enter n and X into your calculator,
which would now be standardized - everyone can use the same F - and would
calculate your password as F^n[X].
							-- Jerry
113.41COMET::LECOMPTEThu Nov 07 1985 17:332
	I had been using this procedure without any problem while we
had V4.1 then when we upgraded to 4.2 it stopped working.  What happened?
113.42SPRITE::OSMANTue Nov 12 1985 17:5284
Here's a fixed version.  The problem was that in 4.2 the "SET PASSWORD"
command was fixed to correctly set $STATUS.  The following updated procedure
now works correctly in both the 4.1 and 4.2 environment:

$! Command file which disallows use of the logged-in terminal until the
$! correct password is typed.
$!
$! This command files does NOT request its own password.  It merely waits
$! for the user's standard password to be typed.
$!
$ close = "close"
$ define = "define"
$ delete = "delete"                        
$ directory = "directory"
$ exit = "exit"
$ goto = "goto"
$ if = "if"
$ open = "open"
$ set = "set"
$ write = "write"
$ on = "on"
$ read = "read"
$ set = "set"
$ scratch_file = "sys$login:" + f$getjpi("","pid") + ".tmp.1"
$ write sys$output -
    "When you want to reclaim your terminal session, enter your password."
$ on control_y then goto try_again
$ try_again:
$ on warning then goto try_again
$ set terminal/noecho
$ write sys$output ""
$ read/prompt="Password: " sys$command password
$ password = f$edit (password, "trim, upcase")
$ set terminal/echo
$ if password .eqs. "" then goto try_again
$ write sys$output "Verifying password . . ."
$ eod = "A"
$ if f$cvui (0,8,password) .eq. f$cvui (0,8,"A") then eod = "B"
$ define/user sys$output nl:
$ define/user sys$error nl:
$ on warning then continue
$ delete 'scratch_file'
$ on warning then goto try_again
$ close/error=t1 a
$ t1:
$ open/write a 'scratch_file'
$ write a "$ delete ''scratch_file'"
$ write a "$ set message/severity/text"
$ write a "$ v = f$verify ()"
$ write a "$ set noverify"
$ write a "$ on warning then $status == 1"
$ write a "$ define sys$output ''scratch_file'"
$ write a "$ define sys$error ''scratch_file'"
$ write a "$ set password"
$ write a "$ deck/dollar=''eod'"
$ write a password
$ write a password
$ write a password
$ write a eod
$ write a "$ deassign sys$output"
$ write a "$ deassign sys$error"
$ write a "$ v = f$verify (v)"
$ close a
$ @'scratch_file'
$ if .not. $status then goto wrong
$ open/error=wrong a 'scratch_file'
$ checklup:
$ read/end=wrong a line
$ if f$locate ("old password validation error", line) .ne. f$length (line) -
    then goto wrong
$ if f$locate ("new password must be different", line) .ne. f$length (line) -
    then goto good
$ goto checklup
$ wrong:
$ close/error=notopen a
$ notopen:
$ write sys$output "Wrong password."
$ goto try_again
$ good:
$ close/error=notopen2 a
$ notopen2:
$ delete 'scratch_file'
$ write sys$output "Thank you."
$ exit
113.43GENRAL::RINESMITHWed Oct 15 1986 14:43239
	This program takes what I consider to be the best features of
    some of the previous programs and combines them.   This procedure
    uses your own password as well as allowing the user to leave a
    message as to where they are or when they will return.


$!			L O C K
$!
$!	Author - unknown
$!	Modified by Matthew Clarke
$!      Modified by Roger Rinesmith	13-NOV-85
$!	Modified by Roger Rinesmith	11-JUN-86
$!
$! Command file to lock up a user terminal while the user is
$! temporarily away but doesn't want to log out of the current
$! directory. Uses control-y lockout to prevent access by unauthorised
$! users. 
$!
$! This command files does NOT request its own password.  It merely waits
$! for the user's standard password to be typed.
$!
$! A new message may be left by leaving a message for youself preceded by
$! percent sign (%).
$!
$ INITIALISE:
$	set noverify
$	on error then logout			! for safety
$	if "''f$mode()'" .nes. "INTERACTIVE" then logout
$
$! Set up escape sequences to manipulate vt100 screen
$	escape[0,7]=27					! escape character
$	Bell[0,7]=7   					! control-g (bell)
$	set_ansi	= escape + "<"			! set term ansi
$	line_2		= escape + "[2;"
$	line_3		= escape + "[3;"
$	line_7		= escape + "[7;"
$	line_8		= escape + "[8;"
$	line_11		= escape + "[11;"
$	line_18		= escape + "[18;"
$	line_19		= escape + "[19;"
$	line_21		= escape + "[21;"
$	line_22		= escape + "[22;"
$	line_23_pos2	= escape + "[23;2f"
$	clear_screen	= escape + "[2J"
$	rev 		= escape + "[7m
$	noatts		= escape + "[m"
$	double_height_1	= escape + "#3"
$	double_height_2	= escape + "#4"
$
$ close = "close"
$ define = "define"
$ delete = "delete"
$ directory = "directory"
$ exit = "exit"
$ goto = "goto"
$ if = "if"
$ open = "open"
$ set = "set"
$ write = "write"
$ on = "on"
$ read = "read"
$ set = "set"
$ scratch_file = "sys$login:" + f$getjpi("","pid") + ".tmp.1"
$
$     process_name := "''f$process()'"	! User's process name
$
$! Use this to count number of invalid attempts to exit.
$	number_of_tries = 0
$! Use this to count number of messages left for the user.
$	n = 0
$
$ IF P1 .EQS. "" THEN GOTO GET_MESSAGE
$ message = p1
$ goto MESSAGE_GOT
$
$CHANGE_MESSAGE:
$	message 	:=	"''f$extract(1,40,reply)'"
$ goto message_got
$
$!
$ GET_MESSAGE:
$
$! Show user how long 40 characters are.
$	write sys$output "Make sure message lines don't extend past here          v"
$
$	inquire message		"Message line "
$
$ MESSAGE_GOT:
$     left_at_time := "''f$extract(0,17,f$time())'"
$!
$!   When in double size, screen width is 40,
$! so truncate messages to first 40 characters.
$	message 	:=	"''f$extract(0,40,message)'"
$
$!  start_pos_??? are used for centering all lines on the screen.
$	start_pos	=	(40 - ''f$length(message)') / 2
$	start_pos_lock	=	(21 - ''f$length(process_name)') / 2
$	start_pos_time	=	(37 - ''f$length(left_at_time)') / 2
$
$ PROTECT:
$ 	set nocontrol_y
$
$!  Set the terminal to NOBROADCAST so that loaction message remains on
$!  screen, even if user receives MAIL etc.
$	set broadcast=(NOPHONE,NOSHUTDOWN)
$
$ DISPLAY_SCREEN:
$
$	write sys$output set_ansi
$	write sys$output  clear_screen
$
$	write sys$output  line_7, start_pos, "H", double_height_1, message
$	write sys$output  line_8, start_pos, "H", double_height_2, message
$
$	write sys$output  line_18, start_pos_lock, "H", double_height_1,-
		rev,"Left at:",noatts," ",left_at_time
$	write sys$output line_19, start_pos_lock, "H", double_height_2,-
		rev,"Left at:",noatts," ",left_at_time

$
$ GET_REPLY:
$     current_time := "''f$extract(0,17,f$time())'"
$	write sys$output line_21, start_pos_time, "H", double_height_1,-
		rev,"Current time:",noatts," ",current_time
$	write sys$output line_22, start_pos_time, "H", double_height_2,-
		rev,"Current time:",noatts," ",current_time
$	number_of_replies = n
$	if number_of_replies .ne. 0 then -
	    write sys$output line_23_pos2, " ", n, " messages"
$	write sys$output line_11, "6H"
$	write sys$output -
   "      If you want to leave a message for ",rev,"''process_name'",noatts," then enter it below."
$
$	read/prompt=""/timeout=120/error=GET_REPLY sys$command reply
$	if reply .eqs. "" then goto GET_PASSWORD
$	if f$extract(0,1,reply) .eqs. "%" then goto change_message
$! Increment reply counter
$	n = n + 1
$	reply_'n := "''reply'"
$	write sys$output "Message recorded."
$	wait 00:00:03.00
$	goto DISPLAY_SCREEN
$!
$ GET_PASSWORD:
$	write sys$output set_ansi
$	write sys$output clear_screen
$	write sys$output line_2, "1H"
$	set terminal/noecho		! Turn echo off for password protection
$ 	read/prompt="Password: " sys$command password
$ 	password = f$edit (password, "trim, upcase")
$	set terminal/echo
$
$! if reply matches LOGOUT then logout
$	if password .eqs. f$extract(0,f$length(password),"LOGOUT") -
	    then goto LOGOUT_NOW
$
$ 	if password .eqs. "" then goto INVALID_PASSWORD
$ 	write sys$output "Verifying password . . ."
$ 	on warning then continue
$ 	eod = "A"
$ 	if f$cvui (0,8,password) .eq. f$cvui (0,8,"A") then eod = "B"
$ 	define/user sys$output nl:
$ 	define/user sys$error nl:
$ 	delete 'scratch_file'
$ 	close/error=t1 a
$ t1:
$ 	open/write a 'scratch_file'
$ 	write a "$ delete ''scratch_file'"
$ 	write a "$ set message/severity/text"
$ 	write a "$ v = f$verify ()"
$ 	write a "$ set noverify"
$ 	write a "$ on warning then $status == 1"
$ 	write a "$ define sys$output ''scratch_file'"
$ 	write a "$ define sys$error ''scratch_file'"
$ 	write a "$ set password"
$ 	write a "$ deck/dollar=''eod'"
$ 	write a password
$ 	write a password
$ 	write a password
$ 	write a eod
$ 	write a "$ deassign sys$output"
$ 	write a "$ deassign sys$error"
$ 	write a "$ v = f$verify (v)"
$ 	close a
$ 	@'scratch_file'
$ 	if .not. $status then goto wrong
$ 	open/error=wrong a 'scratch_file'
$ checklup:
$ 	read/end=wrong a line
$ if f$locate ("old password validation error", line) .ne. f$length (line) -
    then goto wrong
$ if f$locate ("new password must be different", line) .ne. f$length (line) -
    then goto good
$ 	goto checklup
$ wrong:
$ 	close/error=notopen a
$ notopen:
$ 	goto INVALID_PASSWORD
$ good:
$ 	close/error=notopen2 a
$ notopen2:
$ 	write sys$output "Thank you."
$ 	delete 'scratch_file'
$	goto FINISH
$
$
$ INVALID_PASSWORD:
$	write sys$output bell, "INVALID Password"
$	number_of_tries  =  number_of_tries + 1
$	goto DISPLAY_SCREEN
$
$ FINISH:
$	set terminal/echo
$ 	set broadcast=ALL
$	set control_y
$	write sys$output clear_screen
$	write sys$output line_2, "1H"
$	if number_of_tries .ne. 0 then -
	    write sys$output "Number of incorrect attempts was ", number_of_tries,"."
$	number_of_replies = n
$	if number_of_replies .eq. 0 then goto EXIT
$	write sys$output ""
$
$	write sys$output "The following messages were left for you -"
$	write sys$output ""
$	n = 1
$
$ DISPLAY_REPLIES:
$	if n .gt. number_of_replies then goto EXIT
$	write sys$output reply_'n
$	n = n + 1
$	goto DISPLAY_REPLIES
$
$ EXIT:
$	exit
$
$ LOGOUT_NOW:
$	set terminal/echo
$	logout
113.44Not quite, at least on V4.2SERPNT::GULDENSCHUHChuck GuldenschuhWed Oct 15 1986 16:225
Using the procedure in .43:
  1. Give it an invalid password once
  2. Hit <CTRL/Z> the next time it asks for the password

/s/ Chuck
113.45Slight glitch in .43PVAX::PATTERSONKen PattersonWed Oct 15 1986 18:506
    re: .43
    
    The procedure will not work if your account has been set with the
    /GENPWD flag via AUTHORIZE. 
    
    Ken
113.46in VMS V4.4...WHOARU::CERNESEDan Cernese, CAD Systems Eng., APOWed Oct 15 1986 21:152
With all those this="this" lines in the command file, you would think
one would take advantage of the SET SYMBOL/SCOPE DCL command...
113.47Another one bites the dustGENRAL::RINESMITHFri Oct 17 1986 13:024
    RE 113.44  
    		Ok...
    			Just proves once more that it is difficult to make
    DCL procedures impenetrable.