[comp.unix.wizards] script & lock

drears@ardec.arpa (Dennis G. Rears (FSAC)) (12/27/88)

  This happens on a VAX 8600 running ULTRIK but does not happen on
Goulds or Pyramids.   I have a lock program I wrote several years
ago.  When I run it on top of /usr/ucb/script I get a Bus Error when I
type in my password.  Any idea why?  Here is the program lock:

#include <stdio.h>
#include <pwd.h>
#include <signal.h>

/*     lock.c  Author 1LT Dennis Rears  724-2474 <drears@ardc>   
    
     This program locks  the terminal until that person's password
     is typed in.  This is in place of the system lock program. This
     must be compiled using the berekly universe.
                                                                           */

main()

{

	struct passwd *pwd, *getpwent();
	char	*strcpy();
	char	*getpass(), *getlogin(), *uname,  *oldpass, *pass, *crypt();
	int	endpwent(), tries = 0, wrong;

	(void)signal(SIGINT, SIG_IGN);
	(void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGTSTP, SIG_IGN);

	/*  This gets the password entry from the file      */

	uname = getlogin();  /* What happens if the UTMP file is screwed? */
	while ((pwd = getpwent()) != NULL && strcmp (pwd->pw_name, uname) != 0)
		;
	(void)endpwent();

	/*   This checks the response                       */

	wrong = 1;
	while (wrong) {
		(void)printf("Enter Password");
		(void)fflush(stdout);
		oldpass = getpass("");
		pass = crypt(oldpass, pwd->pw_passwd);
		if (strcmp(pass, pwd->pw_passwd) == 0)
			wrong = 0;
		tries++;
	}

	if (tries > 1)
		(void)printf("There were %d tries at unlocking your terminal\n", tries);
}

Dennis
--------------------------------------------------------------------------
		Dennis G. Rears
ARPA:	drears@ardec-ac4.arpa	UUCP:  	...!uunet!ardec-ac4.arpa!drears
AT&T:	201-724-6639		USPS:	Box 210, Wharton, NJ 07885
Work:	SMCAR-FSS-E, Bldg 94, Picatinny Ars, NJ 07806
--------------------------------------------------------------------------

debra@alice.UUCP (Paul De Bra) (12/28/88)

In article <17972@adm.BRL.MIL> drears@ardec.arpa (Dennis G. Rears (FSAC)) writes:
>  This happens on a VAX 8600 running ULTRIK but does not happen on
>Goulds or Pyramids.   I have a lock program I wrote several years
>ago.  When I run it on top of /usr/ucb/script I get a Bus Error when I
>type in my password.  Any idea why?  Here is the program lock:
>...
>	uname = getlogin();  /* What happens if the UTMP file is screwed? */

You might want to check on this. script may confuse getlogin. The 4.3 manual
says:

If getlogin is called within a process that is not attached to a terminal,
or if there is no entry in /etc/utmp for the process's terminal, getlogin
returns a NULL pointer (0).

The manual further suggests:

A reasonable procedure for determining the login name is to first call
getlogin and if it fails, to call getpwuid(getuid()).

>		oldpass = getpass("");

script may or may not let you turn on/off the echo... after all the standard
output of the program goes to script, not to the terminal... (I may be wrong
on this one, my unix doesn't have script)

One last comment: I would replace the strcmp calls by strncmp. You never know
when you will get a bogus Unix version that forgets to 0-terminate a name
from utmp or passwd when it is 8 characters long.

Paul.
-- 
------------------------------------------------------
|debra@research.att.com   | uunet!research!debra     |
------------------------------------------------------

drears@ardec.arpa (Dennis G. Rears (FSAC)) (12/31/88)

   I like to thank everyone who responded to this.  The problem was
that getlogin() was returning NULL and I wasn't checking for it.  When 
script runs it open /dev/ptyX as a tty which of course isn't in utmp.
I have taken the advice to use it based upon uid.

Dennis

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/02/89)

In article <17972@adm.BRL.MIL> drears@ardec.arpa (Dennis G. Rears (FSAC)) writes:
>  This happens on a VAX 8600 running ULTRIK but does not happen on
>Goulds or Pyramids.   I have a lock program I wrote several years
>ago.  When I run it on top of /usr/ucb/script I get a Bus Error when I
>type in my password.  Any idea why?  ...

getlogin() can, and probably does when run under "script", return
NULL.  You didn't test for this and so you tried to strcmp() with
the second argument NULL.  strcmp() trusted you and you let it down..

sme@computing-maths.cardiff.ac.uk (Simon Elliott) (01/09/89)

   Getlogin returns a pointer to the login name as found in /etc/utmp.
   /etc/utmp contains a record for each terminal on the system (including
   pseudo-terminals (ttyp?).  The login name part is blank or null until
   login fills it it.  When you run script, your controlling terminal is a
   pseudo-terminal (eg. /dev/ttyp0).  Your login name is not put into
   /etc/utmp for this pseudo-terminal so the entry is still null.   A program
   run in script is attached to the pseudo terminal so getlogin() returns a
   pointer to the null string entry from utmp.    Getlogin returns the NULL
   pointer only if it called from a process which is NOT attached to any
   terminal (even a pseudo one).

-------cut here-------

#include	<stdio.h>
#include	<pwd.h>

main(ac,av)
	char	*av[];
{
	char	*uname, getlogin();
	struct	passwd	*pwd, getpwnam(), getpwuid();

	if ((uname = getlogin()) == NULL) {
		pwd = getpwuid(getuid());
fprintf(stderr, "uid: %d\n", getuid());
	}
	else {
		pwd = getpwnam(uname);
fprintf(stderr, "uname: *(char *)0x%lx = \"%s\"\n", uname, uname);
	}
	if (pwd == NULL) {
		fprintf(stderr, "%s: cannot locate passwd entry!\007\n", av[0]);
		exit(1);
	}
}

---------cut here-------
Try running this a) from shell prompt;
                 b) under 'script' (uses pseudo-tty);
                 c) using 'at' (detaches from terminal).

-- 
--------------------------------------------------------------------------
Simon Elliott            Internet: sme%v1.cm.cf.ac.uk@cunyvm.cuny.edu
UWCC Computer Centre     JANET:    sme@uk.ac.cf.cm.v1
40/41 Park Place         UUCP:     {backbones}!mcvax!ukc!reading!cf-cm!sme
Cardiff, Wales           PHONE:    +44 222 874300

chris@mimsy.UUCP (Chris Torek) (01/11/89)

In article <596@cf-cm.UUCP> sme@computing-maths.cardiff.ac.uk
(Simon Elliott) writes:
>... A program run in script is attached to [a] pseudo terminal so
>getlogin() returns a pointer to the null string entry from utmp.
>Getlogin returns the NULL pointer only if it called from a process
>which is NOT attached to any terminal (even a pseudo one).

Not so.  If I may quote from getlogin():

	#if defined(LIBC_SCCS) && !defined(lint)
	static char sccsid[] = "@(#)getlogin.c	5.3 (Berkeley) 5/9/86";
	#endif LIBC_SCCS and not lint

	...
		if (ubuf.ut_name[0] == '\0')
			return (0);
	...
		return (ubuf.ut_name);

I believe *getlogin()==0 may be true under some broken Unixes.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

ka@june.cs.washington.edu (Kenneth Almquist) (01/12/89)

chris@mimsy.UUCP (Chris Torek) writes:
> sme@computing-maths.cardiff.ac.uk (Simon Elliott) writes:
>> ... A program run in script is attached to [a] pseudo terminal so
>> getlogin() returns a pointer to the null string entry from utmp.
>> Getlogin returns the NULL pointer only if it called from a process
>> which is NOT attached to any terminal (even a pseudo one).
> 
> Not so.  If I may quote from getlogin():
> 
> 	#if defined(LIBC_SCCS) && !defined(lint)
> 	static char sccsid[] = "@(#)getlogin.c	5.3 (Berkeley) 5/9/86";
> 	#endif LIBC_SCCS and not lint
> 
> 	...
> 		if (ubuf.ut_name[0] == '\0')
> 			return (0);
> 	...
> 		return (ubuf.ut_name);
> 
> I believe *getlogin()==0 may be true under some broken Unixes.

The source may be the final reference, but there's no law against looking
things up in the manual.  If I may quote from the 4.3 BSD manual (dated
April 1986):

	Getlogin returns a pointer to the login name as found in
	/etc/utmp....

	If getlogin is called within a process that is not attached to
	a terminal or if there is no entry in /etc/utmp for the process's
	terminal, getlogin returns a NULL pointer (0).

A process running under script is attached to a pty, and there is
(presumably) a utmp entry for the pty, so getlogin should return the
user name from the /etc/utmp entry for the pty.  Since no user is
actually logged onto the pty, the name in the /etc/utmp entry is the
null string.

So unless Berkeley screwed up, code that depends upon getlogin
returning a NULL pointer when it encounters a null string won't be
portable to vanilla 4.3 BSD.  It certainly won't be portable to
Ultrix 2.3 (a 4.2 BSD derivative which we run here).  I will resist
commenting on whether 4.2 and 4.3 BSD can accurately be described
as "broken Unixes" and simply suggest that testing the results of
getlogin against both NULL and "" is good practice.
				Kenneth Almquist

chris@mimsy.UUCP (Chris Torek) (01/12/89)

In article <6925@june.cs.washington.edu> ka@june.cs.washington.edu
(Kenneth Almquist) writes:
>The source may be the final reference, but there's no law against looking
>things up in the manual.

(I like that line; shall have to use it myself someday...)

>	If getlogin is called within a process that is not attached to
>	a terminal or if there is no entry in /etc/utmp for the process's
>	terminal, getlogin returns a NULL pointer (0).

The key phrase is `if there is no entry in /etc/utmp'.  An entry with
utmp.ut_name[0]=='\0' is considered `no entry'.

Bad wording in the manual, to say the least.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

guy@auspex.UUCP (Guy Harris) (01/13/89)

>A process running under script is attached to a pty, and there is
>(presumably) a utmp entry for the pty, so getlogin should return
>the user name from the /etc/utmp entry for the pty.  Since no user
>is actually logged onto the pty, the name in the /etc/utmp entry is
>the null string.

Which means that the S5R3 and 4.3BSD versions of "getlogin" will return
a null pointer.  I don't have older versions handy, so I can't say that
this behavior dates back to V7.

>So unless Berkeley screwed up, code that depends upon getlogin
>returning a NULL pointer when it encounters a null string won't be
>portable to vanilla 4.3 BSD.

Berkeley's only screwup - or AT&T's screwup, if the wording in question
is derived from that in the 32V manual page - is that they didn't make
it clear that the "utmp" entry in question must not only exist (in the
sense that an entry in "/etc/ttys", for V7/BSD, or an entry in
"/etc/utmp" of type INIT_PROCES, LOGIN_PROCESS, USER_PROCESS or
DEAD_PROCESS, for S5, exists specifying the terminal in question), but
that it must represent a valid entry (in the sense that it must not have
a null user name). 

The code in question *is* portable to vanilla 4.3BSD, because 4.3BSD's
"getlogin" *does* return a NULL pointer when it encounters a null
string; the fact that the manual page may not explicitly say so is
arguably a deficiency of the manual page (unless you consider it to be
implicit in the description that the "utmp" entry must really specify a
user), but it doesn't affect the portability of code....

>It certainly won't be portable to Ultrix 2.3 (a 4.2 BSD derivative
>which we run here).

This according to the Ultrix documentation, or the Ultrix code (either
by inspecting the code or by probing its behavior)?  I don't have 4.2BSD
source handy to check, but if 4.2BSD returns NULL if the user name is
null and Ultrix doesn't, the screwup there is DEC's.

>I will resist commenting on whether 4.2 and 4.3 BSD can accurately
>be described as "broken Unixes"

If a system that returns NULL if the user name is a null string is
broken, that means 4.3BSD, 4.3-tahoe, and S5R3 are broken, and other
4.xBSD and S5 systems may be broken as well - perhaps even V7 and S3. 
If that's the case, I'd be inclined to say the only thing broken about
those systems may be the documentation, and say that systems that
*don't* provide that behavior are broken.

ka@june.cs.washington.edu (Kenneth Almquist) (01/13/89)

In article <837@auspex.UUCP>, guy@auspex.UUCP (Guy Harris) writes:
> This according to the Ultrix documentation, or the Ultrix code (either
> by inspecting the code or by probing its behavior)?  I don't have 4.2BSD
> source handy to check, but if 4.2BSD returns NULL if the user name is
> null and Ultrix doesn't, the screwup there is DEC's.

It's from the code.  The Ultrix manual page for getlogin is identical to
the 4.3 BSD manual page.  The getlogin code for Dynix (which claims 4.2 BSD
compatibility) is identical to the Ultrix code, so I assume that the code
in both systems is the 4.2 BSD code.

What I mean by saying that Berkeley screwed up is that the code and the
documentation were in agreement (even if they were both wrong) and then
they changed the code without changing the documentation.

>> ...the name in the /etc/utmp entry is the null string.

> Which means that the S5R3 and 4.3BSD versions of "getlogin" will return
> a null pointer.  I don't have older versions handy, so I can't say that
> this behavior dates back to V7.

Well, as I recall the S5R2 code checks for the null string, but null user
strings are rare in System V utmp files because when a user logs out
in System V this fact is indicated by changing the ut_type field of the
utmp entry to DEAD_PROCESS rather than by changing the user name to the
null string.  I *think* that the check for the null string predates the
conversion to the new utmp format, in which case USG Unix at one time
(before it got the name System V and the new utmp format) actually returned
NULL if called on a terminal with no one logged on.  Does S5R3 just contain
this same check for a null string, or does in actually check whether the
user has logged out?

In any case, getlogin is inherently risky under System V since a user
can start up a background process, log out, and allow someone else to
log in.  At this point getlogin will return the login name of the new
user, not the name of user that started the background process.  (The
vhangup call is supposed to prevent this scenario from occurring under
Berkeley UNIX.)  If a program really wants to find out who invoked it,
it should search the password file for the user's id.  The name returned
by getlogin can be used to resolve the ambiguity if more than one user
has the same user id, but because of the above scenario it's probably
safer to use the environment variable LOGNAME to resolve any ambiguity.
Of course a malicious user can reset LOGNAME; if you have malicious users
that you must distinguish between, the only safe approach is to give them
separate user ids.
				Kenneth Almquist

guy@auspex.UUCP (Guy Harris) (01/14/89)

>The getlogin code for Dynix (which claims 4.2 BSD compatibility) is
>identical to the Ultrix code, so I assume that the code in both systems
>is the 4.2 BSD code.

If that is the case, I'm slightly surprised; unfortunately, I don't have
4.2BSD code handy to check against.

>I *think* that the check for the null string predates the conversion to
>the new utmp format,

In which case it may well date back to V7; if so, I'd be even more
surprised if the check were missing from 4.2.

>Does S5R3 just contain this same check for a null string, or does
>in actually check whether the user has logged out?

S5R3's "getlogin" checks whether "ubuf.ut_user[0]" is '\0', and if so
returns NULL.  It does not check the "ut_type" field of the entry. 
"ttyslot" accepts either INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or
DEAD_PROCESS.  Since DEAD_PROCESS or INIT_PROCESS will show up if
somebody's logged out and nobody's logged in subsequently, and since
"init" stuffs the name of the *program* it ran into "ut_user" when it
sets the type to INIT_PROCESS, this seems to indicate that if there's
nobody logged in, "getlogin" will neither return NULL *nor* a null
string - it'll return the name of the person who logged in last, or
something like "getty"!  (It obviously won't return a null string, since
it checks for that and returns NULL.)

Perhaps there's a reason for this behavior, but given what "getlogin" is
supposed to do I don't see why it doesn't accept only USER_PROCESS and
maybe LOGIN_PROCESS in the "utmp" slot.

>In any case, getlogin is inherently risky under System V since a user
>can start up a background process, log out, and allow someone else to
>log in.  At this point getlogin will return the login name of the new
>user, not the name of user that started the background process.  (The
>vhangup call is supposed to prevent this scenario from occurring under
>Berkeley UNIX.)

It prevents it because it invalidates any file descriptors the program
has that refer to that tty.  Of course, if you start up a background
process and log out, it's not supposed to have any file descriptors for
the tty - otherwise, it can do amusing and possibly unpleasant things to
the owner of the current session - and "nohup ... &" will ensure that is
the case.  If you don't do "nohup", the SIGHUP sent to your tty when
your login shell exits should blow away the process in question.

(This brings up the general problem of disconnecting remnant processes
of a session from the session's tty, which is, I think, being discussed
in another thread here.)

Of course, none of the above is guaranteed to happen, so it's
conceivable that a program could have "getlogin" not fail when run in
the background and left behind after the session is terminated.

>If a program really wants to find out who invoked it, it should search
>the password file for the user's id.  The name returned by getlogin can
>be used to resolve the ambiguity if more than one user has the same
>user id,

>Of course a malicious user can reset LOGNAME; if you have malicious users
>that you must distinguish between, the only safe approach is to give them
>separate user ids.

If they're malicious, I'd give them separate user IDs just to keep them
from being malicious to each other, unless you know they wouldn't do
that....

I seem to remember reading somewhere in a V8 manual that V8 had what, if
I remember, was an old PWB idea (dating back to V6, when you had 1-byte
user IDs and users *had* to share them) of having the login name stored
securely in the U area, with a system call to get and set it.  Is this
the case?

chris@mimsy.UUCP (Chris Torek) (01/14/89)

>>The getlogin code for Dynix (which claims 4.2 BSD compatibility) is
>>identical to the Ultrix code, so I assume that the code in both systems
>>is the 4.2 BSD code.

In article <844@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
>If that is the case, I'm slightly surprised; unfortunately, I don't have
>4.2BSD code handy to check against.

I do.  The test is missing.

The test was usually unnecessary in 4.1BSD, where *getlogin()==0 would
be true only if you had actually logged out.  Script did not switch
control terminals, so getlogin() would find your real login entry.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris