[comp.unix.wizards] Cuserid

ccdn@levels.sait.edu.au (DAVID NEWALL) (05/31/89)

According to the manual, cuserid(3) is supposed to "return the character
login name of the user".  I interpret this as meaning it will return the
login name of the invoker.  This is _not_ what cuserid() does.

In fact, cuserid() returns the login name of the person who is logged in
on the terminal pointed to by stdin, stdout or stderr.  So if one were to
close stdin (or point it at a text file), close stderr, and point stdout
at someone else's terminal, cuserid() would return that person's login
name, and not yours.  A great pity if the program you're running relies
on cuserid() to identify the caller.

Oh, and the same applies for getlogin().

So people, do not, absolutely do not, rely on these functions to identify
the user.  Use getuid() or geteuid() instead.

I personally think this is an important security hole.  Consider, for
example, set gid mail programs...


David Newall                     Phone:  +61 8 343 3160
Unix Systems Programmer          Fax:    +61 8 349 6939
Academic Computing Service       E-mail: ccdn@levels.sait.oz.au
SA Institute of Technology       Post:   The Levels, South Australia, 5095

friedl@vsi.COM (Stephen J. Friedl) (05/31/89)

In article <289@levels.sait.edu.au>, ccdn@levels.sait.edu.au (DAVID NEWALL) writes:
> According to the manual, cuserid(3) is supposed to "return the character
> login name of the user".  I interpret this as meaning it will return the
> login name of the invoker.  This is _not_ what cuserid() does.
>    [...]
> So people, do not, absolutely do not, rely on these functions to identify
> the user.  Use getuid() or geteuid() instead.

     Here is an alternate method that may be a little bit more
flexible (for Sys V, at least).  First get the $LOGNAME
environment variable and look up the password entry for it.  If
the uid here matches getuid (or geteuid, depending on your
application), go ahead and believe $LOGNAME.  If it doesn't
match, forgery is going on and you have to use the getuid entry.

     This technique allows multiple accounts sharing the same uid
to distinguish between them.  Presumably, the accounts only share
if fraud between them is not a big deal.

     Steve

-- 
Stephen J. Friedl / V-Systems, Inc. / Santa Ana, CA / +1 714 545 6442 
3B2-kind-of-guy   / friedl@vsi.com  / {attmail, uunet, etc}!vsi!friedl

You can't have everything: where you would put it?

guy@auspex.auspex.com (Guy Harris) (06/01/89)

>According to the manual, cuserid(3) is supposed to "return the character
>login name of the user".  I interpret this as meaning it will return the
>login name of the invoker.  This is _not_ what cuserid() does.

Which manual is "the manual"?  The S5R3 manual page says it returns "a
character-string representation of the login name that the user of the
current process is logged in under", which makes it not surprising that,
as you note:

>In fact, cuserid() returns the login name of the person who is logged in
>on the terminal pointed to by stdin, stdout or stderr.

>Oh, and the same applies for getlogin().

In fact, "cuserid" in AT&T's implementation just tries to do a
"getlogin" first and, if that fails, uses "getpwuid(getuid())".  I
assume any Berkeley implementations do the same....

>So people, do not, absolutely do not, rely on these functions to identify
>the user.  Use getuid() or geteuid() instead.

Yup.  In most versions of UNIX, there is *no* guaranteed way to get the
login name for the current session, since doing so basically involves 1)
getting the tty name for the current session and 2) finding the "utmp"
entry for that session, and 1) can only be done if you have a handle on
that tty, and as you note there's no way of reliably getting such a
handle (no, "/dev/tty" doesn't do so - an "fstat" on it will, in all
UNIXes with which I'm familiar, report the major and minor device number
of "/dev/tty", and thus doesn't give you enough information to find the
device in "/dev" to which it refers).

I think some versions may actually stash the login name in the U area
with a privileged call, and provide a call to fetch it.  (I think
PWB/UNIX 1.0 did this; I seem to remember something in the V9 manual
that indicated that there might be such a call there.)

It is worth noting that, in some cases, you may *want* the answer that
"getpwuid(getuid())" or "getpwuid(geteuid())" gives you, and not the
answer that even an "unbreakable" "getlogin()" would give you....

ccdn@levels.sait.edu.au (DAVID NEWALL) (06/02/89)

In article <1725@auspex.auspex.com>, guy@auspex.auspex.com (Guy Harris) writes:
> Which manual is "the manual"?  The S5R3 manual page says it returns "a
> character-string representation of the login name that the user of the
> current process is logged in under", which makes it not surprising that,
> as you note:
>
>>In fact, cuserid() returns the login name of the person who is logged in
>>on the terminal pointed to by stdin, stdout or stderr.

Huh?  I don't get it.  If I close stdin and stderr, and point stdout at
your terminal, then cuserid() will say that I am you.  That's isn't a
"representation of the login name that the user of the current process is
logged in under".

And that's why I was surprised.  (Though on reflection, I am now not
surprised, given how it must surely work -- scanning the utmp file).


David Newall                     Phone:  +61 8 343 3160
Unix Systems Programmer          Fax:    +61 8 349 6939
Academic Computing Service       E-mail: ccdn@levels.sait.oz.au
SA Institute of Technology       Post:   The Levels, South Australia, 5095

wagoner@imokay.dec.com (Darryl Wagoner) (06/02/89)

Neither cuserid(3) or getlogin(3) in Ultrix checks stdin for user
information.  

The cuserid(3) routine tries to do a getlogin(3); if it fails, it then does a
getpwuid(3) of the real uid.

The getlogin(3) routine only gets login information from utmp.

I have never checked this on other systems, but would be interested in knowing
if this is indeed a bug on other versions of Unix. 



-- 
Darryl Wagoner			wagoner@imokay.dec.com
Digital				(work) 508.264.5586
Secure Workstation Project 	(DTN)  293.5586
Boxboro, Ma.

karl@haddock.ima.isc.com (Karl Heuer) (06/03/89)

The plot thickens.  In POSIX, cuserid() is required to use the *effective uid*
of the process.  The Rationale section does not comment on this inconsistency
with traditional implementations.

Moreover, POSIX getlogin() is supposed to return the login name associated
with the *controlling terminal*, not the tty on descriptor 0-2 as is commonly
implemented.  Since, as Guy points out, a program can't always find the true
name of its controlling terminal, it would seem that this requires either a
new system call, or else getlogin() should just give up and return NULL.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

wagner@humboldt.uucp (Juergen Wagner) (06/03/89)

Cuserid is *NOT* a security hole. Programs relying on a property of this
function which it doesn't have, are security holes.

Juergen Wagner					gandalf@csli.stanford.edu
						 wagner@arisia.xerox.com

sms@WLV.IMSD.CONTEL.COM (Steven M. Schultz(Y)) (06/03/89)

In article <902@arisia.Xerox.COM> wagner@arisia.xerox.com (Juergen Wagner) writes:
>Cuserid is *NOT* a security hole. Programs relying on a property of this
>function which it doesn't have, are security holes.
>Juergen Wagner					gandalf@csli.stanford.edu
>						 wagner@arisia.xerox.com

	Enough is enough!  After seeing this "problem/bug" posted umpteen
	times i no longer restrain myself...

	cuserid() is a System V(anilla) construct/problem NOT a 
	2.10.1BSD (or for that matter a 4.3BSD) concern at all. 

	for real 2BSD bugs contact either Keith Bostic 
	(bostic@okeeffe.berkeley.edu) (who will probably refer you to me)
	or Steven Schultz (sms@wlv.imsd.contel.com).

	Steven M. Schultz
	sms@wlv.imsd.contel.com

guy@auspex.auspex.com (Guy Harris) (06/08/89)

>Neither cuserid(3) or getlogin(3) in Ultrix checks stdin for user
>information.

Neither of them "check stdin for user information", in the sense of
reading said information from standard input, on *any* system I know of.
*However*:

>The cuserid(3) routine tries to do a getlogin(3); if it fails, it then does a
>getpwuid(3) of the real uid.
>
>The getlogin(3) routine only gets login information from utmp.

But on the versions of UNIX with which I'm familiar, in order to find
the entry in "/etc/utmp" it has to figure out which terminal the job is
running from, and it does that by calling "ttyslot", which finds that
out by calling "ttyname" on file descriptors 0, 1, and 2, successively,
until it gets a non-null pointer back.

In other words, it assumes that one of those three file descriptors is
opened to the terminal in question; since it checks standard input
first, you can just redirect standard input to some other terminal and
*voila*, it checks the "utmp" entry for *that* terminal, instead.

>I have never checked this on other systems, but would be interested in knowing
>if this is indeed a bug on other versions of Unix. 

If you consider it a bug to be able to redirect standard input and, as a
result, be able to force "getlogin" give you the wrong information, you
might find it is a bug in many versions of UNIX, *including* Ultrix....

I think it may not be a bug in some versions, because they have a
"getlogin" that's implemented as a system call.

rob@PacBell.COM (Rob Bernardo) (06/08/89)

In article <1768@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes:
+If you consider it a bug to be able to redirect standard input and, as a
+result, be able to force "getlogin" give you the wrong information, you
+might find it is a bug in many versions of UNIX, *including* Ultrix....

The "problem" is that a programmer might use cuserid() without knowing
about this "deception".

This might be particularly bad in, say, a mail user agent.  MUA's often
must run setgid.  As a setgid program is has access to *anyone's*
incoming mail box, and must judge whether the user would normally be
able to access the mailbox s/he has directed the MUA to access. If
cuserid() is used to determine the user's id, the MUA may unwittingly
grant access to some other person's incoming mailbox.
-- 
Rob Bernardo, Pacific Bell UNIX/C Reusable Code Library
Email:     ...![backbone]!pacbell!pbhyf!rob   OR  rob@pbhyf.PacBell.COM
Office:    (415) 823-2417  Room 4E850O San Ramon Valley Administrative Center
Residence: (415) 827-4301  R Bar JB, Concord, California

leo@philmds.UUCP (Leo de Wit) (06/08/89)

In article <472@imokay.dec.com> wagoner@imokay.dec.com (Darryl Wagoner) writes:
|Neither cuserid(3) or getlogin(3) in Ultrix checks stdin for user
|information.  
|
|The cuserid(3) routine tries to do a getlogin(3); if it fails, it then does a
|getpwuid(3) of the real uid.
|
|The getlogin(3) routine only gets login information from utmp.
|
|I have never checked this on other systems, but would be interested in knowing
|if this is indeed a bug on other versions of Unix. 

On Ultrix, having read about the potential security problems with
getlogin(), it took me about 5 minutes to break a privilized setuid program
(read: become root) that relied upon getlogin() ... with a shell script!

    Leo.

C.R.Ritson@newcastle.ac.uk (Chris Ritson) (06/08/89)

In article <472@imokay.dec.com> wagoner@imokay.dec.com (Darryl Wagoner) writes:
>The getlogin(3) routine only gets login information from utmp.
>
>I have never checked this on other systems, but would be interested in knowing
>if this is indeed a bug on other versions of Unix.

I am working on an Encore multimax, and have access to a BSD4.3 source for a
VAX.

As  I understand it, getlogin() depends on ttyslot() to find out which
tty to look for in /etc/utmp.

ttyslot()  looks  for  the  first file descriptor of (0,1,2) that is a
tty, then looks that up in /etc/utmp.  To fool it,  redirect  standard
input  from  /dev/null,  standard output to some other user's terminal
which must be writeable, and print out the return from  getlogin()  on
standard error.

As it stands, getlogin() is not a safe way to identify the caller of a
program, unless you cross check with the (real) userid too.

Can  anyone  see  anything  wrong  with  adding something like this to
getlogin(), to avoid confusion?

        stat( ttyslot_result, statbuf);
        if (statbuf.st_uid != getuid())
                return(0);

--
Chris Ritson

JANET: C.R.Ritson@uk.ac.newcastle                    PHONE: +44 91 222 8175
UUCP : ...!ukc!newcastle.ac.uk!C.R.Ritson
ARPA : C.R.Ritson@newcastle.ac.uk
SNAIL: Computing Laboratory, University of Newcastle upon Tyne, UK, NE1 7RU
JANET: C.R.Ritson@uk.ac.newcastle                    PHONE: +44 91 222 8175
UUCP : ...!ukc!newcastle.ac.uk!C.R.Ritson
ARPA : C.R.Ritson@newcastle.ac.uk
SNAIL: Computing Laboratory, University of Newcastle upon Tyne, UK, NE1 7RU

maujf@warwick.ac.uk (Mike Taylor) (06/08/89)

[Someone (original reference lost) says:]
> If this [cuserid()'s behaviour]is indeed a bug on other versions of
> Unix ... 

The fact that it doesn't do what you want it to do doesn't make it a
bug -- it's only a bug if it doesn't do what it *says* it does.  If
you want the login name of the user running the process, then you
should use getpwuid(getuid())->pw_name.  Cuserid() is specifically
designed to do this only if its attempt to look up the name in
/etc/utmp fails.
______________________________________________________________________________
Mike Taylor - {Christ,M{athemat,us}ic}ian ...  Email to: mirk@uk.ac.warwick.cs