idallen (07/10/82)
I have discovered, to my surprise, that the C Library function getlogin() is not a secure way of determining the name of the person running the current process. We need such a method here at Waterloo, so I solicit comments on the following discussion. Getlogin() calls ttyslot() to find the login name of the running process. It is possible to make getlogin() return the name of any user currently logged on, and I don't know of an easy way to fix this flaw. The problem lies with the use of ttyslot(). It is claimed ("man ttyname") that ttyslot() returns the index of the control terminal for the current process. This is not strictly true. Ttyslot() calls ttyname() on each of the units 0, 1, and 2 (in that order) until it finds one which is attached to a terminal. But -- there is no guarantee that the first terminal it finds is the real controlling terminal. Indeed, it could be *any* terminal controlled by any currently active user! You can fool getlogin() into thinking you are someone else by redirecting I/O units to or from the other user's terminal. For nice, friendly systems, this is not a problem. For accounting purposes, however, it is not acceptable, since this makes it possible to charge resources or submit requests as if you were that other user. To find the name of the current user, documentation tells me to use getlogin() first, and, if that fails, use getpwent(). Since many, many, programs do this, I am amazed to discover that getlogin() can be fooled. Apparently there is *no* secure way of determining the controlling terminal of the current process (the terminal from which the current process was submitted). Am I right? As it stands, getlogin() cannot be used because it can be fooled. I don't see any use for getlogin() because of this flaw, and I am amazed that any program uses it. Why does ttyslot() use such an ad-hoc method of determining the controlling terminal? Running down the I/O units and taking the first one that happens to be a terminal seems wrong. Comments on my view of this problem, and suggested fixes, are welcome. -IAN! U of Waterloo (decvax!watmath!idallen)
solomon (07/11/82)
Getlogin is very nearly worthless for all the reasons cited by watmath!idallen as well as many others. For example, we have a login named "who" with no password and login "shell" /usr/ucb/w. All you have to do is type "login who&", and from now on, getlogin() will say you are "who". Then, if you send mail, it will be from "who", since ucbmail, binmail, and delivermail (all of whom may, under certain circumstances add a From: line) all use getlogin(). Another nice feature of getlogin() is that it is NOT modified by "su". So you "su" on top of somebody else and then mail from you is labelled as being from him. Finally, you may get "You have new mail" and then have "mail" say "No mail", since one case is using getlogin() and the other is using getuid(). Now here is the fix: modify the man page "GETLOGIN(3)" to remove the ridiculous advice "The correct procedure for determining the login name is to first call \getlogin/ and if it fails, to call \getpwuid/." and perhaps replace it with a waring how getlogin() is of very limited usefulness. Then go through all software that was written following this advice and change it. The change is usually quite simple, since you will find something like if ((foo=getlogin())==0) ... (or ==NULL), and you can just remove the line. end of flame Marvin Solomon (solomon@uwisc, ...!harpo!uwvax!solomon)
mash (07/17/82)
1) The login name is not, and never has been, a first-class entity in any UNIX that I know of, except the PWB/UNIX 1.x systems, circa 1975-1978. (Their ublocks had an extra 32 bytes that carried around login name, tty letter, and login directory. The login name was mainly added to survive having >256 people on the complex of machines at Piscataway, while not duplicating uids across machines for reasons of inter-machine backup, protection, and balancing.) 2) The extra information above disappeared into the environment variables added in V7 (i.e., $HOME on most systems, $LOGNAME on later derived versions of V7). Even with all software geared to use $LOGNAME when approrpiate, one can still fool it by modifying LOGNAME, although at least the ridiculous conttoritons of getlogin() are unnecessary. 3) The only way to really be safe with LOGNAME is to make it part of the per-process information (as in older PWB/UNIXs) and people generally seemed unwilling to do that, especially when 16-bit uids became available. At point in the discussions leading to the design of the current environment variable approach, we'd actually worked out an elaborate scheme involving (name, value, attribute) tuples, where the attribute information included local/global, and read-only bits. The implications of all this (extra systems calls, bizarre interactions with shell, etc) scared us off, especially since the only item we really thought needed read-only was LOGNAME. 4) Thus, don't expect this situation to improve -- at least UNIX III and later use LOGNAME somewhat more consistently. -mashey
dan@BBN-UNIX@sri-unix (08/21/82)
From: Dan Franklin <dan at BBN-UNIX> Date: 10 Aug 1982 9:41:02 EDT (Tuesday) Oops. My apologies to anyone who was misled by my previous message about calling ttyname on /dev/tty; I had forgotten that we replaced our /dev/tty driver several years ago with something completely different inside, for which the trick I described does work--but it won't work on an ordinary V7 /dev/tty driver.
greep@Rand-Unix@sri-unix (08/31/82)
Date: Wednesday, 25 Aug 1982 16:50-PDT However, this only works if there is a tty open, or if there is some way of finding out the "controlling tty", and even then doesn't work if the process was started up by some background program (eg "at").
richl@daemon.UUCP (Rick Lindsley) (01/17/85)
Has anyone addressed the problems that getlogin() has when used from a pty that is NOT a login pty? Script is one prime example, but a growing number of other utilities also use ptys. One possibility is to have getlogin trace parent process ids to arrive at the TRUE login of a person; but this has the unpleasant side effect of forcing any program which uses getlogin() to be setgid sys (we've altered the perms on kmem for security reasons). Another possibility is to have getlogin do a getuid() and getpwnam() if it can't get a name out of utmp. A third possibility is to ask the calling program to perform the above check. (Getlogin will return a null string). Before we go and choose an option, I would be interested in determining if others have chosen a solution to this problem. I will be happy to summarize to the net if necessary. Rick Lindsley Small Systems Support Tektronix ...!{ihnp4,allegra,decvax}!tektronix!daemon!richl
richl@daemon.UUCP (Rick Lindsley) (02/05/85)
A while back I posted a question on what to do with getlogin(3) (it fails miserably on pty's that are not login ptys's). I promised a summary of responses; here they are. Only 3 responses though.. I'd say that in the interests of speed and compatibility that we will likely just fix the individual programs to check the result from getlogin(), and change getlogin only as indicated in the first letter (we have people who have to have the original functionality (buggy though it may be) and so can't really change the behavior of getlogin() too much). -------- From: dce@hammer (David Elliott) To: daemon!richl Date: Thu, 17 Jan 85 00:52:36 PST Organization: Tektronix, Wilsonville OR We went ahead and changed getlogin() to return NULL when it would have returned a "". This made su and a couple of other programs work correctly for us. David -------- From: tektronix!decvax!mcnc!jte To: decvax!tektronix!daemon!richl Date: Thu, 17 Jan 85 12:58:45 est Original-From: James Ellis <jte@mcnc> Organization: Microelectronics Center of NC, RTP, NC Some sites have modified the kernel to track the user's name and make it available via a system call. If you don't have such mods or are not inclined to put them in, I recommend the following: If getpwnam(getlogin()) returns the same uid as getuid(), then use getlogin(). Otherwise, use the name returned by getpwuid(getuid()). Getlogin is not to be trusted as an identifier of "who" one "is". A user should be considered to be who his permissions are - and that is defined by the uid. The only complication is that it is reasonable for a uid to be shared by several different logins, wherefore the first case above. Note that this is my opinion which is not, unfortunately, shared by all. Berkeley in particular prefers to consider that you "are" your uid in some cases (permission checks) and you "are" who you logged in as in other cases (e.g. mail). This allows folks to login as foo, su to root, and send mail that looks like it came from foo. This is fine and well, but I also think it is wrong. Since I don't have time to re-write mail myself, I don't complain too loudly. I'd be interested to know what you finally decide to use. Jim Ellis ------- From: j@utah-cs.arpa To: richl@tektronix.csnet Date: Fri, 18 Jan 85 12:33:11 MST Over all those alternatives I would choose: Find it via getpwuid. Only if that fails (hardly ever), then look at utmp. Looking at utmp first gives the wrong result for programs which have been left in the background and then someone else logs in. I believe dmr recommended this himself a long time ago. I haven't done it here yet tho, as a problem may be that this might change getlogin's behavior in some instances such as mail's determining the sender, when the sender may be su'ed or something of that sort, or a privileged sender, etc. Haven't really examined these potential problems though. {ihnp4,decvax}!utah-cs!lepreau